Frequently Asked Questions (FAQs)
Answers to common questions about Stainless, including migration, testing, and more.
How are generated SDKs tested?
Section titled “How are generated SDKs tested?”Have a look at our test documentation for details about the tests we generate and run.
What if my API defines endpoints that aren’t stable yet?
Section titled “What if my API defines endpoints that aren’t stable yet?”Here are our recommended approaches:
Option 1 — Use a Beta Resource in the Stainless config
Section titled “Option 1 — Use a Beta Resource in the Stainless config”Unstable models and methods can be placed into a beta resource (or alpha, experimental). When they are
ready to be generally available (GA), you can move them out of the beta resource. This approach has worked well in
practice and results in the best Developer Experience (DX) for end users — it is easily discoverable, is
clearly documented, and adds a minimal amount of overhead.
For example:
resources: beta: methods: create: /v2/createOption 2 — Create and Release a Separate SDK
Section titled “Option 2 — Create and Release a Separate SDK”Another option is to create and release a separate SDK for the second spec. This can create a clear distinction between the stable SDK and the non-stable one. However, it may be more confusing for end-users and adds the overhead of managing two projects/repos per language.
Option 3 — Access Undocumented Endpoints
Section titled “Option 3 — Access Undocumented Endpoints”You can choose not to configure endpoints that aren’t stable, and instead access them as undocumented endpoints. This method is documented in the generated READMEs for each language, providing a way to make custom/undocumented requests.
How can I migrate an endpoint to a new version?
Section titled “How can I migrate an endpoint to a new version?”If you’re replacing an endpoint with a new version, you can use aliases to point to the new version. This way, users will still see the same method name in the SDK, but it will point to the new version. This can make the process of upgrading and deprecating methods easier for you and your users.
Let’s assume you start with a method POST /data/create that you configured in your Stainless config like so:
resources: users: methods: create: /data/createTo migrate this method, add the following:
- a new version of the endpoint, let’s call it
createV2 - Rename the existing method to
createV1 - Add an alias to the method
createV2to target the version you want users to use by default - Optionally, add a deprecation message to the old method
resources: users: methods: createV1: endpoint: /data/create deprecated: go: use `List` instead default: use `list` instead createV2: /data/createV2 create: type: alias to: createV2Importantly, make sure to release this as part of a major version bump with migration instructions. Check out our publishing guide for more information.
Our API spec is made of multiple OpenAPI files but Stainless only supports a single file. What can we do?
Section titled “Our API spec is made of multiple OpenAPI files but Stainless only supports a single file. What can we do?”You have two options when dealing with multiple OpenAPI files:
Option 1: Combine your specs into a single file
We recommend using the redocly CLI to combine OpenAPI files. This works well when:
- Customers commonly use multiple APIs together in a single integration
- The APIs share authentication and configuration
- You want a simpler developer experience with one unified SDK
Redocly wrote this comprehensive blog article with clear examples. If you’re using Stainless GitHub Action to upload your spec file, just add an extra step beforehand to run the redocly CLI and combine your files in a single spec file.
Option 2: Generate separate SDKs from each OpenAPI file Create multiple Stainless projects, one for each OpenAPI spec. This approach makes sense when:
- Your APIs serve entirely different customer bases
- Developers typically only integrate with one API at a time
- The APIs have very different authentication or versioning schemes
Our OpenAPI spec has errors or is auto-generated with incorrect types. What can we do?
Section titled “Our OpenAPI spec has errors or is auto-generated with incorrect types. What can we do?”Use spec transforms to fix issues in your OpenAPI spec during SDK generation without modifying the source file. Transforms are useful when:
- Your spec is auto-generated from backend code with incorrect types or missing fields
- You need to add Stainless metadata like x-stainless-naming
- Fixing the source spec is difficult or time-consuming
- You want to customize SDK generation for specific languages
Transforms let you fix incorrect types, add missing fields, rename properties, remove problematic defaults, and more. See the transforms guide for examples.
We are using Postman collections, how can we get an OpenAPI file?
Section titled “We are using Postman collections, how can we get an OpenAPI file?”Postman does offer an API to transform a collection to OpenAPI, documented here.
In addition they wrote an excellent blog article on the subject with simple examples. We recommend giving it a read!
If the converted OpenAPI spec has issues, you can use transforms to fix them.
Does Stainless support runtime request validation?
Section titled “Does Stainless support runtime request validation?”The SDKs we generate validate the general shape of requests at compile-time using the language’s type system and leave constraints that aren’t ergonomically supported for the API to validate (e.g. string length, number of items in a collection, and so on).
While forgoing full runtime request validation may seem counterintuitive, we’ve found the benefits outweigh the cons:
-
Code size: It’s critical to keep code size low for frontend use-cases and edge functions. Runtime request validation requires embedding far more information in the SDK, especially in languages like TypeScript where forgoing validation keeps type information in the type system only.
-
Performance: Runtime request validation negatively impacts performance, especially on low-powered devices. For constraints that can’t be handled by a language’s type system it’s better to let your API validate incoming data. Most requests contain valid data, so client-side validation adds overhead to most requests with no tangible benefit. Validating only on the server optimizes for the most common outcome.
-
Forward compatibility: If constraints are loosened on the API side, then the runtime request validation of older SDK versions will be outdated and will reject valid requests until the SDK is upgraded, which may not even be possible to guarantee if it requires an end-user to update something like a mobile app.
-
Undocumented values: Without runtime request validation, the user can pretty easily bypass the type system in dynamically typed languages and send requests that don’t match the expected shape, which is useful when there are bugs in the OpenAPI spec or when there’s undocumented or not-yet-in-the-spec API functionality.
Why does the TypeScript SDK preserve the original API property names instead of converting to camelCase?
Section titled “Why does the TypeScript SDK preserve the original API property names instead of converting to camelCase?”Our TypeScript SDK generator preserves property names in JSON requests and responses exactly as they appear in
your API. We don’t currently plan to add an option to map snake_case (user_id) in your API to camelCase
(userId) in the SDK.
While mixing camelCase and snake_case can feel awkward initially, we’ve found the benefits of preserving exact API names outweigh the negative gut reaction:
-
Bundle sizes matter: It’s critical to keep bundle sizes low for frontend bundles and edge functions. Converting property names would require shipping additional transformation code and metadata, significantly increasing SDK size.
-
Undocumented properties: APIs often include experimental or undocumented properties not in the OpenAPI specification. Without knowing these properties exist, we can’t reliably transform their names. For example, if your API returns an undocumented
experimental_featurefield, there’s no way to know it should map toexperimentalFeature. -
Developer expectations: Developers’ mental models of request/response properties naturally map to the JSON sent over the wire. Unlike languages like Go where explicit serialization is expected, TypeScript developers often find it confusing when the SDK doesn’t match the API documentation. In practice, we rarely hear complaints from end users once they’re using the SDK.
Can I use the TypeScript SDK in the browser?
Section titled “Can I use the TypeScript SDK in the browser?”Yes, Stainless-generated TypeScript SDKs run directly in browser environments. The SDKs are designed to work seamlessly across Node.js, modern browsers, and edge runtimes like Cloudflare Workers and Vercel Edge Functions.
Preventing accidental API key exposure
Section titled “Preventing accidental API key exposure”To prevent accidental disclosure of API keys in browser code, you can configure browser access in your Stainless config:
targets: typescript: options: browser: state: allow # or: disallow, dangerous_allowSetting state: disallow will cause the SDK to throw an error if instantiated in a browser environment without explicit acknowledgment, helping protect sensitive credentials from being exposed in client-side code.
Why doesn’t Stainless use Python’s Enum class for enums?
Section titled “Why doesn’t Stainless use Python’s Enum class for enums?”Stainless generates Python enums using Literal types instead of Python’s built-in Enum class. For example, instead of:
from enum import Enum
class Status(str, Enum): PENDING = "pending" COMPLETED = "completed" FAILED = "failed"We generate:
from typing_extensions import Literal
Status = Literal["pending", "completed", "failed"]This is an intentional design decision based on several considerations:
Forward compatibility: Literal types ensure forward compatibility when new enum values are added to your API. If your server starts returning a new value like "cancelled" that wasn’t present when the SDK was generated, Literal types allow it to pass through gracefully. With Enum classes, you’d need to update the SDK and release a new version to handle new values.
Lightweight and developer-friendly: Literal types require no runtime overhead and less boilerplate. They provide excellent type checking and auto-completion in modern IDEs while keeping the generated code simple and readable.
Consistent philosophy: Across all our SDKs, we believe it’s better to let unexpected enum values pass through rather than breaking when new values are introduced. This approach prioritizes SDK stability and reduces the need for frequent breaking changes.
For more context on our design philosophy around forward compatibility, check out our blog post on Java enum compatibility — while Java doesn’t have literals like Python, it illustrates similar design considerations.
Why is there both a Java and Kotlin SDK when the Java SDK is written in Kotlin?
Section titled “Why is there both a Java and Kotlin SDK when the Java SDK is written in Kotlin?”Although the Java SDK is written in Kotlin, which is interoperable with Java, its public API differs from the Kotlin SDK’s. Here are some examples:
- OpenAPI nullable schemas are exposed as
Optionaltypes for Java and nullable types for Kotlin - Lazy iterables are exposed as
Streamtypes for Java andSequencetypes for Kotlin - Async operations are exposed using
CompletableFuturetypes for Java andsuspendfunctions for Kotlin
The Java SDK is written in Kotlin because it simplifies code sharing between the Java and Kotlin SDKs, including custom code.
To add custom Java code, create a java/ directory alongside the existing kotlin/ directory. The Kotlin documentation on Java interoperability has guidance and examples you can reference to ensure your Java code works with the Kotlin code we generate.
How does Stainless handle dependency security?
Section titled “How does Stainless handle dependency security?”We take dependency security very seriously. We have systems and processes in place to scan, be alerted to, and update dependencies for all SDKs we generate. We seriously review alert reports and their associated CVEs and take rapid actions when necessary.
Automated Dependency Scanning
Section titled “Automated Dependency Scanning”We have an automated system set up performing dependency scanning. This system alerts us to any vulnerabilities identified in our dependencies.
Rapid Updates
Section titled “Rapid Updates”When a vulnerability is detected, we can quickly push an update to our codegen system to address the issue the next time a build is triggered. Dependency updates rely on the same release and versioning flow used for OpenAPI and Stainless config changes.
This ensures that the SDKs remain secure and up-to-date, as long as release PRs opened by Stainless are regularly merged.
We strongly recommend that you automate your OpenAPI updates, that way your SDKs are built regularly without any manual action on your part.
Add custom code
Section titled “Add custom code”While our systems will handle most cases, you may have the need to quickly address a vulnerability by yourself. In that situation you can always directly open a PR on your SDK repository, and merge it yourself. See our Add custom code docs for more details.
How do I report a security issue?
Section titled “How do I report a security issue?”Stainless takes security seriously, you are encouraged to report any security vulnerability promptly so that appropriate action can be taken.
Reporting an SDK security issue
Section titled “Reporting an SDK security issue”Please contact the Stainless team at security@stainless.com with detailed information. We will review and respond promptly.
Reporting a security issue related to Stainless services
Section titled “Reporting a security issue related to Stainless services”For example:
Please contact the Stainless team at security@stainless.com with detailed information. We will review and respond promptly.
Reporting a security issue related to a Stainless customer API
Section titled “Reporting a security issue related to a Stainless customer API”If you encounter security issues that are not directly related to SDKs generated by Stainless but pertain to the services or products provided by the company who owns and publish the SDK, please follow the respective company’s security reporting guidelines.
See the file SECURITY.md present in SDKs generated by Stainless for details.
Responsible Disclosure
Section titled “Responsible Disclosure”We appreciate the efforts of security researchers and individuals who help us maintain the security of SDKs we generate. If you believe you have found a security vulnerability, please adhere to responsible disclosure practices by allowing us a reasonable amount of time to investigate and address the issue before making any information public.
Thank you for helping us keep the SDKs and systems they interact with secure.