--- title: Frequently Asked Questions (FAQs) | Stainless description: Answers to common questions about Stainless, including migration, testing, and more. --- ## How are generated SDKs tested? Have a look at our [test documentation](/docs/guides/tests/index.md) for details about the tests we generate and run. ## 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 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/create ``` ### 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 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? 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/create ``` To 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 `createV2` to 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: createV2 ``` Importantly, make sure to release this as part of a major version bump with migration instructions. Check out our [publishing guide](/docs/guides/publish#versioning-and-releases/index.md) for more information. ## 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](https://redocly.com/blog/combining-openapis) with clear examples. If you’re using Stainless [GitHub Action](https://github.com/stainless-api/upload-openapi-spec-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? Use [spec transforms](/docs/guides/transforms/index.md) 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](/docs/guides/transforms/index.md) for examples. ## 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](https://www.postman.com/postman/workspace/postman-public-workspace/request/12959542-aeceb96d-2ba6-48ea-b0df-71661491dac3). In addition they wrote an excellent [blog article](https://blog.postman.com/creating-an-openapi-definition-from-a-collection-with-the-postman-api/) on the subject with simple examples. We recommend giving it a read! If the converted OpenAPI spec has issues, you can use [transforms](/docs/guides/transforms/index.md) to fix them. ## 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? 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_feature` field, there’s no way to know it should map to `experimentalFeature`. - **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? 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 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_allow ``` Setting `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? 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](https://www.stainless.com/blog/forwards-compatible-enums-in-java) — 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? Although the Java SDK is written in Kotlin, which is [interoperable with Java](https://kotlinlang.org/docs/java-to-kotlin-interop.html), its public API differs from the Kotlin SDK’s. Here are some examples: - OpenAPI nullable schemas are exposed as [`Optional` types](https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html) for Java and [nullable types](https://kotlinlang.org/docs/null-safety.html) for Kotlin - Lazy iterables are exposed as [`Stream` types](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html) for Java and [`Sequence` types](https://kotlinlang.org/docs/sequences.html) for Kotlin - Async operations are exposed using [`CompletableFuture` types](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html) for Java and [`suspend` functions](https://kotlinlang.org/docs/coroutines-overview.html#suspending-functions-and-coroutine-builders) for Kotlin The Java SDK is written in Kotlin because it simplifies code sharing between the Java and Kotlin SDKs, including [custom code](/docs/guides/add-custom-code/index.md). To add custom Java code, create a `java/` directory alongside the existing `kotlin/` directory. The [Kotlin documentation on Java interoperability](https://kotlinlang.org/docs/java-interop.html) 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? 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 We have an automated system set up performing dependency scanning. This system alerts us to any vulnerabilities identified in our dependencies. ### 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](/docs/guides/publish#versioning-and-releases/index.md) 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](/docs/guides/preview-builds/index.md) your OpenAPI updates, that way your SDKs are built regularly without any manual action on your part. ### 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/guides/add-custom-code/index.md) docs for more details. ## 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 Please contact the Stainless team at with detailed information. We will review and respond promptly. ### Reporting a security issue related to Stainless services For example: - [www.stainless.com](https://www.stainless.com) - [Stainless SDK Studio](https://app.stainless.com) - [Stainless GitHub App](https://github.com/apps/stainless-app) - [Upload Spec GitHub Action](https://github.com/stainless-api/upload-openapi-spec-action/) Please contact the Stainless team at with detailed information. We will review and respond promptly. ### 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 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.