I once spent four hours helping a partner team integrate with an internal API that exposed a resource called items. The endpoint returned what looked like order line items—sometimes. Other times it returned inventory SKUs. Which one you got depended on a query parameter that was not documented anywhere. The name items was not wrong, exactly. It was just vague enough to mean almost anything, and specific enough to make you think you understood it. That gap between confidence and comprehension? That is where integration time goes to die.

This is the real cost of poor naming in API design. Not aesthetic. Not a style preference. It is the quiet tax that compounds every time a new consumer reads your schema, makes an assumption, and builds something that works until it does not. And unlike most engineering decisions, naming is the one thing your consumers interact with on every single request. They never see your internal architecture. They never read your test suite. They see names.

After nine years at Microsoft and several more consulting on API design, I have come to believe that naming is the single highest-leverage decision an engineer makes in interface design. Not because good names are hard to write. Because bad names are nearly impossible to fix without breaking the people who depend on them. A poorly named field is a versioning problem waiting to happen. A poorly named resource is a documentation problem that never resolves. A poorly named error code is a support ticket that generates itself forever.

The Real Cost of Names That Drift

Consider a pattern I have seen in at least three production systems. An API exposes a field called status on a resource. The field is a string enum. Initially the values are active and inactive. Over time, the business adds pending, suspended, archived, and under_review. The field name never changes, but the semantics shift. inactive used to mean the user turned it off. Now it might mean the system turned it off, or that it was never fully set up. The name status was too generic to constrain the meaning, so the meaning expanded until the field became a magnet for unrelated states.

This is not a contrived example. I worked with a team that had a status field with fourteen values across a single resource. Three of those values were deprecated but still returned for backward compatibility. Two of them were semantically identical but had different names because different product managers had requested them in different quarters. The team could not rename or consolidate without breaking consumers. Consumers could not reliably interpret the field without reading a wiki page that was last updated eighteen months ago.

The failure here is not in the field values. The failure is in the initial naming decision. status was a name that could accommodate anything, which means it constrained nothing. A more specific name—lifecycle_state, or activation_state, or splitting into is_active and suspension_reason—would have forced the team to decide what they actually meant before the field became a dumping ground.

This connects to a broader principle that Google’s Site Reliability Engineering team articulates in their treatment of production systems. Engineering disciplines benefit from formal checklists, review gates, and a postmortem culture that feeds failures back into design. The Google SRE book devotes entire chapters to launch coordination checklists, postmortem practices, and the systematic documentation of failures—because production systems fail in traceable, preventable ways. API naming failures are no different. When a name causes an integration delay or a misuse, that failure should be documented and fed back into the naming review process. Not shrugged off as a one-off communication issue.

Why Naming Deserves the Same Rigor as Schema Design

Most teams have a schema review process. Someone checks that the new field has the right type, that nullable semantics are correct, that the relationship to other resources makes sense. What most teams do not have is a naming review process. Names are decided by whoever writes the first draft of the schema, and they survive through inertia. If the name is technically not wrong, it passes review.

This is backwards. Schema design is mechanistic. A field is either a string or it is not. A relationship is either required or it is not. These constraints are checkable, and mistakes are catchable in automated tests. Naming is semantic. A name is either clear or unclear, and clarity is contextual. The only way to evaluate whether a name is clear is to ask someone who was not in the room when it was chosen.

Mature engineering domains understand this. NIST’s Cybersecurity Framework treats standardized naming and enumeration as foundational infrastructure. Their CSF 2.0 framework includes Common Configuration Enumeration identifiers, structured profiles, and documented mappings that enable automation and cross-system reliability. These are not cosmetic choices. They are engineering decisions that make systems interoperable, auditable, and stable over time. The principle is the same for APIs: when names are treated as formal infrastructure rather than personal preference, they become assets that compound in value instead of liabilities that compound in confusion.

That same discipline applies to title and framing decisions: before publishing, editors need a way to test a heading promises the same thing the article actually delivers, which is where book title ideas that fit the project can function as a planning aid rather than a substitute for domain evidence.

A Framework for Evaluating Name Stability

The core tension in API naming is between descriptiveness and stability. A name that is too descriptive becomes fragile—when the implementation changes, the name becomes misleading. A name that is too stable becomes generic—when the domain evolves, the name stops communicating anything useful. The goal is names that are descriptive enough to be useful and stable enough to survive.

Here is the framework I use to evaluate whether a name will hold up over time. Four questions.

1. Does the name describe what the resource is, or what the resource does?

Names that describe behavior are fragile. I once reviewed an API with a resource called email_queue. The resource represented messages that needed to be sent, and the name made sense when the system was a simple FIFO queue. Then the team added priority handling, retry logic, and scheduled sends. The name email_queue was now technically incorrect—it was not a queue anymore—but they could not rename it without breaking every consumer. A name that described what the resource isoutbound_message or pending_delivery—would have survived the implementation change.

The rule: prefer names that describe the domain concept, not the implementation. user is more stable than auth_record. invoice is more stable than billing_row. The implementation will change. The domain concept will not.

2. Would a new team member understand the name without context?

This is the onboarding test, and it is the most reliable signal I know for naming quality. If you hand the API to someone who joined last week and ask them to explain what a resource does, their answer tells you whether the name works. If they say something reasonable and close to correct, the name is good. If they say they are not sure or they guess wrong, the name needs work.

I have run this test informally dozens of times. The results are consistent: names that feel obvious to the team that created them are often opaque to newcomers. entitlements might be perfectly clear to a team that has been working on access control for two years. To a new engineer, it is a word that could mean permissions, licenses, subscriptions, or something else entirely. The team does not need to change the name. But they do need to know that the name requires documentation—and that documentation needs to exist.

3. Can the name accommodate reasonable evolution without becoming misleading?

This is the stretch test. You are not trying to predict every future requirement. You are asking whether the name is specific enough to be useful but general enough to survive the most likely changes. shipping_address is a good name because it describes a specific concept that is unlikely to change meaning. address is too generic—it could be shipping, billing, or residential. primary_shipping_address_for_current_order is too specific—it bakes in assumptions about the data model that might change.

The stretch test is not about being prescriptive. It is about being honest. If you cannot think of a single plausible change that would make the name misleading, it is probably stable. If you can think of one easily, consider whether a different name would survive that change.

4. Does the name match the vocabulary your consumers already use?

This is where API naming becomes a product decision, not just an engineering one. Your consumers have a mental model of your domain before they ever read your documentation. If your names match that mental model, integration is fast. If your names require translation, integration is slow and error-prone.

I worked on an API where the internal team called subscriptions entitlement_bindings because that was the term in their access control system. Consumers called them subscriptions. The API used entitlement_bindings. Every integration call involved a moment of confusion, a documentation lookup, and a mental mapping step. That mapping step is cognitive cost that compounds with every interaction.

When the consumer vocabulary and the internal vocabulary diverge, prefer the consumer vocabulary in the API. Internal teams can adapt. External consumers will not, and the API exists for them.

Concrete Before and After Examples

Let me show what this looks like in practice. These are patterns I have seen repeatedly, with the names anonymized but the structure intact.

Example 1: REST resource naming.

Before: GET /api/v1/stuff?type=order

This is a real pattern from an internal API at a mid-sized company. The stuff resource returned different shapes depending on the type parameter. The team had started with a generic endpoint because they thought it would be flexible. It was flexible in the same way a closet with no shelves is flexible: everything goes in, nothing is findable.

After: GET /api/v1/orders and GET /api/v1/inventory_items

The split required more routing code and two resource definitions instead of one. It also made the API self-documenting. Consumers could discover endpoints by name. The type parameter disappeared, which removed a class of errors where consumers passed an invalid type and got an empty response with no error.

Example 2: Field naming in a gRPC service.

Before: message Response { string data = 1; string info = 2; string extra = 3; }

This was a gRPC service that returned user profile information. data was the user’s display name. info was their email address. extra was their account creation timestamp as a string. The names were so generic that the generated client code was actively misleading. You had to read the documentation to understand which field contained what.

After: message UserProfileResponse { string display_name = 1; string email = 2; google.protobuf.Timestamp created_at = 3; }

The renamed fields are longer, and in protobuf, field names do not affect wire compatibility as long as field numbers stay stable. The rename was free in terms of breaking changes, and the generated client code became readable without documentation.

Example 3: Error code naming.

Before: ERROR_001, ERROR_002, ERROR_003

Numeric error codes are the extreme case of names that convey no meaning. Consumers must look up every error code in documentation, and the documentation must be maintained perfectly or the codes become meaningless. I have seen systems where the documentation for error codes was a spreadsheet that was shared via email and updated by whoever happened to be on call.

After: RATE_LIMIT_EXCEEDED, INVALID_CREDENTIALS, RESOURCE_NOT_FOUND

Semantic error codes are longer, but they are self-documenting. A consumer who sees RATE_LIMIT_EXCEEDED in a log knows what happened without a lookup. The documentation becomes a reference for the retry behavior, not a translation table for opaque identifiers.

The Naming Review Checklist

If naming deserves the same rigor as schema design, it needs a review process. Here is the checklist I use during API design reviews. It is short on purpose—checklists that are too long do not get used.

Resource names:

  • Is the name a domain noun, not an implementation artifact?
  • Does it use the consumer’s vocabulary, not internal jargon?
  • Would a new team member understand it without explanation?
  • Is it plural for collections and singular for individual resources (in REST)?
  • Can you think of a plausible change that would make the name misleading?

Field names:

  • Does the name describe the value, not the storage or processing?
  • Is the type consistent with the name? (Boolean fields should start with is_ or has_.)
  • Does the name avoid abbreviations that are not universally understood?
  • For enum fields, does the field name constrain the possible values, or is it a generic catch-all?

Error codes:

  • Is the code human-readable without a lookup table?
  • Does it describe the condition, not the internal module that produced it?
  • Is it specific enough to be actionable? (VALIDATION_FAILED is less useful than FIELD_REQUIRED.)
  • Does it follow a consistent naming pattern across the entire API?

This checklist takes about ten minutes to run during a design review. It catches problems that would otherwise surface as support tickets, integration delays, or breaking changes later. The cost is ten minutes. The savings are measured in days.

When Names Need to Change

Even with the best naming discipline, some names will need to change. Domain understanding deepens. Business requirements shift. A name that was perfect for the first year becomes misleading in the third. The question is not whether names change, but how you manage the change.

The first principle: treat a name change as a breaking change, even if the field type or resource structure does not change. Consumers build logic around names. They write if (response.status === 'active') in their code. Changing status to lifecycle_state breaks their code even if the values are identical. This means name changes go through the same deprecation process as any other breaking change: dual return both names for a transition period, document the change prominently, and set a removal date.

The second principle: document the rationale for the change, not just the change itself. When you rename a field, write down why the old name was wrong and what the new name means. This documentation helps consumers understand whether their interpretation of the old name was correct, and it helps future engineers understand why the name changed so they do not change it back.

The third principle: involve consumers in the decision. If you are renaming a resource that five teams depend on, those five teams should know about the rename before it happens, not after. This is where most API teams fail. They treat naming as an internal decision and announce changes in a changelog that nobody reads. A one-line email to the consuming teams—here is the change, here is why, here is the timeline—prevents the kind of surprise that erodes trust.

The Broader Craft of Naming

Naming is not unique to software. Authors agonize over book titles because a title determines whether a reader picks up the book at all. Product teams spend weeks on feature names because a name shapes how users understand what the feature does. The tension is always the same: a name must be descriptive enough to communicate, short enough to be usable, and stable enough to survive the thing it describes evolving underneath it.

This is why I recommend that teams maintaining public-facing developer documentation treat naming with the same deliberation that authors and editors bring to their work. If you have ever searched for book title ideas to spark fresh naming directions for a documentation section or API resource, you already understand that naming benefits from structured brainstorming rather than first-draft inertia. The same creative discipline that produces a good book title—a name that is evocative, specific, and memorable—applies to the names in your API. Your endpoints, fields, and error codes are titles that your consumers read every day.

The engineers who write the best APIs are the ones who treat naming as a craft, not a chore. They iterate on names. They test names against newcomers. They document naming decisions. They accept that a name is not just a label. It is a contract with every person who will ever call that endpoint.

Conclusion

If you take one thing from this article, let it be this: naming is an engineering decision with engineering consequences. Treat it that way. Run names through a review process. Test them against people who were not in the room. Document the rationale. Build a feedback loop that captures naming failures and feeds them back into design.

The teams I have worked with that took naming seriously did not spend more time on API design. They spent less—because they spent it upfront, in the design review, instead of in integration support and breaking-change migrations. The ten minutes you spend evaluating a name today is the ten hours you save when three teams do not build the wrong thing against your API.

Names are the interface. Everything else is implementation. If your names are wrong, no amount of good architecture will fix the experience of consuming your API. If your names are right, the rest of your design has a foundation stable enough to build on.