In an OpenAPI specification, the operationId
is a unique string that identifies a specific API operation. While the OpenAPI spec marks it as optional, any practical SDK generation depends on it entirely—the Stainless SDK generator and other developer tools use this ID to create predictable, human-readable method names that feel native to each programming language.
Without a stable operationId
, SDK method names can change unexpectedly between generations, creating breaking changes for your users. This guide covers how operationId
drives SDK generation, best practices for writing effective IDs, and common mistakes that can break your SDKs.
In an OpenAPI specification, the operationId
is a unique string that identifies a specific API operation. While the spec marks it as optional, for any practical code generation, it's essential. The Stainless SDK generator and other developer tools rely on this ID to create predictable, human-readable method names, making it a critical field for automating a great developer experience.
Without a stable operationId
, SDK method names can change unexpectedly between generations, leading to breaking changes for your users.
What is operationId in OpenAPI
The operationId
is a key inside an OpenAPI path's operation object, like get
, post
, or put
. It must be unique across all operations defined in your API spec. Think of it as a stable, machine-readable nickname for an endpoint that code generators use as a source of truth.
Here is a simple example in an OpenAPI YAML file:
Note: In Stainless, defining
operationId: retrieveUser
here means your SDK will have aclient.users.retrieve()
method (or similar, depending on your resource naming in your config).
Code generators read retrieveUser
and use it as the basis for the method name in the SDK. This direct mapping is why operationId
is so important. At Stainless, our generator expects a stable operationId
for every endpoint to produce idiomatic and predictable SDKs.
Show before and after code
When our generator processes an operationId
, it intelligently converts it into method names that feel native to each programming language.
A single operationId
in your spec...
...becomes idiomatic methods in multiple SDKs:
Map identifiers to languages
A good generator handles naming conventions for you. The operationId
is typically written in camelCase
, and the generator transforms it to fit the target language's style.
createUser
in TypeScript becomescreate
on theusers
resource, followingcamelCase
.createUser
in Python becomescreate
on theusers
resource, followingsnake_case
.createUser
in Go becomesNew
on theUsers
resource, followingPascalCase
.
This ensures developers using your SDK get an experience that feels handcrafted for their ecosystem, all driven by one simple string in your spec.
Why operationId drives SDK generation
The operationId
is the central pillar of SDK generation. It's not just about the method name; it dictates the names of related types, documentation anchors, and even how we track changes over time. A well-managed set of **operationId
**s leads to a stable, intuitive, and professional SDK.
When you generate an SDK, the operationId
directly influences the developer experience. It improves IDE autocompletion, makes the SDK searchable, and clarifies changelogs. If IDs are missing or duplicated, a good generator will raise diagnostics to help you fix them before they cause problems for your users.
Prevent method name drift
The most critical role of operationId
is providing stability. If you rely on the generator to infer a name from the endpoint path (e.g., POST /users
), a simple re-architecture of your API from /users
to /v2/users
could rename the method, creating a breaking change for your users.
A stable operationId
like createUser
ensures the SDK method remains client.users.create()
even if the underlying path changes. This decouples the public-facing SDK from your internal API structure.
Enable multi-language parity
When you offer SDKs in multiple languages, consistency is key. A developer switching from your Python SDK to your TypeScript SDK should find the same logical operations.
The operationId
acts as the source of truth, ensuring that listUsers
maps to client.users.list()
in both languages. This creates a cohesive developer experience across your entire ecosystem.
Write effective operationIds
Good **operationId
**s are clear, consistent, and predictable. They make your API easier to understand and your generated SDKs a pleasure to use. We've found that a few simple rules go a long way.
The best **operationId
**s are descriptive and follow a consistent pattern. This not only helps the generator but also makes the raw OpenAPI spec itself easier for humans to read and maintain.
Good | Bad | Why it's bad |
---|---|---|
|
| Not a verb, unclear action. |
|
| Describes the HTTP method, not the action. |
|
| Uses snake_case; camelCase is conventional. |
|
| Redundant "By" phrasing. |
Use verb noun pattern
The most reliable naming convention is verbNoun
. For standard CRUD operations, use a consistent set of verbs.
create
: ForPOST
requests that create a new resource.retrieve
: ForGET
requests that fetch a single resource by ID.update
: ForPUT
orPATCH
requests that modify a resource.delete
: ForDELETE
requests that remove a resource.list
: ForGET
requests that return a collection of resources.
For non-CRUD actions, use descriptive verbs like archive
, send
, cancel
, or approve
.
Keep naming consistent
Consistency across your entire API is crucial. If you use listUsers
for one resource, don't use getAccounts
for another. Stick to your chosen patterns.
You can enforce this with an OpenAPI linter in your CI/CD pipeline. This catches inconsistencies before they ever make it into a generated SDK.
Avoid generic terms
Avoid vague or implementation-specific names. An operationId
like doRequest
or handleAction
tells the developer nothing about what the operation actually does.
Similarly, avoid just using the resource name, like users
or invoices
. Always pair it with a verb to describe the action being performed.
Handle missing or duplicate operationIds
In an ideal world, every OpenAPI spec would have perfect operationIds from the moment you start creating OpenAPI specs. In reality, you might be working with a spec that's missing them or has duplicates. When this happens, generators have to fall back to less ideal strategies, which can harm the developer experience.
A good SDK generator will warn you about these issues. For example, the Stainless platform runs diagnostics on your spec and flags missing or duplicate **operationId
**s, so you can fix them at the source.
Detect missing ids
If an operationId
is missing, a generator might try to create one from the HTTP method and path, like post_users_{id}_resend_invite
. This is ugly, unstable, and not something you want in your SDK.
Using a tool that provides diagnostics, like our SDK Studio, lets you quickly find every endpoint that's missing an operationId
so you can add one.
Resolve duplicate ids
Duplicate **operationId
**s are even more dangerous because they can cause silent overwrites or compilation errors in the generated code. An operationId
must be unique across the entire specification.
If you have two operations with operationId: listUsers
, the generator doesn't know how to differentiate them. You'll need to rename one or both to be more specific, for example, listOrgUsers
and listProjectUsers
.
OperationId mistakes that break SDKs
While operationId
is a powerful tool for creating great SDKs, a few common mistakes can cause major headaches for your users. Understanding these pitfalls helps you maintain a stable and reliable SDK over the long term.
The most severe mistakes are those that introduce breaking changes into your SDK. A simple change in the spec can ripple out and force all of your users to update their code, reinforcing why your API isn't finished until the SDK ships.
Change id after release
Once an SDK is published and in use, changing an operationId
is a breaking change. If you rename listUsers
to listAllUsers
, the generated SDK method will change from client.users.list()
to client.users.listAll()
, and all existing user code will break.
If you must change an operationId, you should treat it like any other breaking API change. This typically involves a major version bump of your SDK and clear documentation in the changelog, which becomes even more important when integrating SDK snippets into your API documentation.
Use invalid characters
**operationId
**s should only contain alphanumeric characters. While some generators might handle other characters, symbols like -
, , or /
can cause unpredictable behavior or invalid code to be generated. Stick to camelCase
for maximum compatibility.
Mix naming patterns
Inconsistent naming doesn't just look unprofessional; it makes your SDK harder to use. If a developer sees client.users.create()
and client.accounts.addNew()
, they can't form a mental model of how your API works. This friction slows down integration and adds cognitive load.
Frequently asked questions about operationId and SDKs
Can I change an operationId after users adopt my SDK?
You can, but it is a breaking change. Renaming an operationId
will rename the corresponding method in the SDK, forcing your users to update their code, so you should release it as a new major version.
How does Stainless handle a spec that lacks operationIds?
Our generator will fall back to creating a name from the HTTP method and path, but we will raise a warning diagnostic. We strongly recommend adding explicit **operationId
**s for a stable and clean SDK.
What happens if two endpoints share an operationId?
This will cause an error during SDK generation. Our diagnostics will flag the duplicate operationId
so you can locate and rename one of them to ensure all IDs are unique.
Should operationIds mirror backend function names?
Not necessarily. Your **operationId
**s should be designed from the user's perspective and describe the public API action, which may be different from your internal service's function name.
How can large teams keep operationIds consistent?
Use an OpenAPI linter in your CI pipeline to enforce naming conventions. Additionally, using branches that provide SDK previews on pull requests helps catch inconsistencies before they are merged.
Ready to turn your OpenAPI spec into high-quality, idiomatic SDKs? Get started for free.