Generated SDKs that feel hand-crafted
Generated SDKs that feel hand-crafted
Generated SDKs that feel hand-crafted
Automate the generation of truly idiomatic SDKs for TypeScript, Python, Go, and more. Built by the team behind Stripe's code generation, with rich types, auto-pagination, and retries out-of-the-box. With Stainless, your libraries feel as though they were hand-written by an expert in the language who had the time to get it right.
Automate the generation of truly idiomatic SDKs for TypeScript, Python, Go, and more. Built by the team behind Stripe's code generation, with rich types, auto-pagination, and retries out-of-the-box. With Stainless, your libraries feel as though they were hand-written by an expert in the language who had the time to get it right.
Automate the generation of truly idiomatic SDKs for TypeScript, Python, Go, and more. Built by the team behind Stripe's code generation, with rich types, auto-pagination, and retries out-of-the-box. With Stainless, your libraries feel as though they were hand-written by an expert in the language who had the time to get it right.
TypeScript
Python
Go
Java
Kotlin
Ruby
Terraform
C#
PHP
import OpenAI from "openai"; import { zodTextFormat } from "openai/helpers/zod"; import { z } from "zod"; const openai = new OpenAI(); const format = zodTextFormat( z.object({ namesOfParticipants: z.array(z.string()) }), "namesOfParticipants" ); const response = await openai.responses.parse({ model: "gpt-5", instructions: "Extract the names of the participants.", input: "Alice and Bob are going to a science fair on Friday.", text: { format }, }); console.log(response.output_parsed);
TypeScript
Python
Go
Java
Kotlin
Ruby
Terraform
C#
PHP
import OpenAI from "openai"; import { zodTextFormat } from "openai/helpers/zod"; import { z } from "zod"; const openai = new OpenAI(); const format = zodTextFormat( z.object({ namesOfParticipants: z.array(z.string()) }), "namesOfParticipants" ); const response = await openai.responses.parse({ model: "gpt-5", instructions: "Extract the names of the participants.", input: "Alice and Bob are going to a science fair on Friday.", text: { format }, }); console.log(response.output_parsed);
TypeScript
Python
Go
Java
Kotlin
Ruby
Terraform
C#
PHP
import OpenAI from "openai"; import { zodTextFormat } from "openai/helpers/zod"; import { z } from "zod"; const openai = new OpenAI(); const format = zodTextFormat( z.object({ namesOfParticipants: z.array(z.string()) }), "namesOfParticipants" ); const response = await openai.responses.parse({ model: "gpt-5", instructions: "Extract the names of the participants.", input: "Alice and Bob are going to a science fair on Friday.", text: { format }, }); console.log(response.output_parsed);
Stop Choosing Between
Idiomatic and Automated
Stop Choosing
Between Idiomatic
and Automated
Hand-written SDKs are expensive to build and a nightmare to maintain. Most auto-generators produce clunky, unidiomatic wrappers that developers hate.
// Legacy export class PetApi { protected _basePath = defaultBasePath; protected defaultHeaders: any = {}; protected _useQuerystring: boolean = false; protected authentications = { 'default': new VoidAuth(), 'api_key': new ApiKeyAuth('header', 'api_key'), 'petstore_auth': new OAuth(), } public updatePet(body: Pet, options: any = {}): Promise<{ response: http.ClientResponse; body?: any; }> { const localVarPath = this.basePath + '/pet'; let localVarQueryParameters: any = {}; let localVarHeaderParams: any = (Object).assign({}, this.defaultHeaders); let localVarFormParams: any = {}; // verify required parameter 'body' is not null or undefined if (body === null || body === undefined) { throw new Error('Required parameter body was null or undefined when calling updatePet.'); } (Object).assign(localVarHeaderParams, options.headers); let localVarUseFormData = false; let localVarRequestOptions: localVarRequest.Options = { method: 'PUT', qs: localVarQueryParameters, headers: localVarHeaderParams, uri: localVarPath, useQuerystring: this._useQuerystring, json: true, body: ObjectSerializer.serialize(body, "Pet") }; this.authentications.petstore_auth.applyToRequest(localVarRequestOptions); this.authentications.default.applyToRequest(localVarRequestOptions); if (Object.keys(localVarFormParams).length) { if (localVarUseFormData) { (<any>localVarRequestOptions).formData = localVarFormParams; } else { localVarRequestOptions.form = localVarFormParams; } } return new Promise<{ response: http.ClientResponse; body?: any; }>((resolve, reject) => { localVarRequest(localVarRequestOptions, (error, response, body) => { if (error) { reject(error); } else { if (response.statusCode && response.statusCode >= 200 && response.statusCode <= 299) { resolve({ response: response, body: body }); } else { reject({ response: response, body: body }); } } })
// Legacy export class PetApi { protected _basePath = defaultBasePath; protected defaultHeaders: any = {}; protected _useQuerystring: boolean = false; protected authentications = { 'default': new VoidAuth(), 'api_key': new ApiKeyAuth('header', 'api_key'), 'petstore_auth': new OAuth(), } public updatePet(body: Pet, options: any = {}): Promise<{ response: http.ClientResponse; body?: any; }> { const localVarPath = this.basePath + '/pet'; let localVarQueryParameters: any = {}; let localVarHeaderParams: any = (Object).assign({}, this.defaultHeaders); let localVarFormParams: any = {}; // verify required parameter 'body' is not null or undefined if (body === null || body === undefined) { throw new Error('Required parameter body was null or undefined when calling updatePet.'); } (Object).assign(localVarHeaderParams, options.headers); let localVarUseFormData = false; let localVarRequestOptions: localVarRequest.Options = { method: 'PUT', qs: localVarQueryParameters, headers: localVarHeaderParams, uri: localVarPath, useQuerystring: this._useQuerystring, json: true, body: ObjectSerializer.serialize(body, "Pet") }; this.authentications.petstore_auth.applyToRequest(localVarRequestOptions); this.authentications.default.applyToRequest(localVarRequestOptions); if (Object.keys(localVarFormParams).length) { if (localVarUseFormData) { (<any>localVarRequestOptions).formData = localVarFormParams; } else { localVarRequestOptions.form = localVarFormParams; } } return new Promise<{ response: http.ClientResponse; body?: any; }>((resolve, reject) => { localVarRequest(localVarRequestOptions, (error, response, body) => { if (error) { reject(error); } else { if (response.statusCode && response.statusCode >= 200 && response.statusCode <= 299) { resolve({ response: response, body: body }); } else { reject({ response: response, body: body }); } } })
Stainless generates client libraries that feel hand-crafted, with idiomatic patterns and type-safety, while offering the speed and consistency of automation.
// Stainless import { APIResource } from '../core/resource'; import { APIPromise } from '../core/api-promise'; import { RequestOptions } from '../internal/request-options'; import { path } from '../internal/utils/path'; export class PetResource extends APIResource { update(body: PetUpdateParams, options?: RequestOptions): APIPromise<Pet> { return this._client.put('/pet', { body, ...options }); } }
// Stainless import { APIResource } from '../core/resource'; import { APIPromise } from '../core/api-promise'; import { RequestOptions } from '../internal/request-options'; import { path } from '../internal/utils/path'; export class PetResource extends APIResource { update(body: PetUpdateParams, options?: RequestOptions): APIPromise<Pet> { return this._client.put('/pet', { body, ...options }); } }
"Stainless' tooling is intuitive, well-documented, and automated, which is essential when you're managing SDKs across multiple languages."

Zeke Sikelianos
Founding Designer - Replicate
"Stainless' tooling is intuitive, well-documented, and automated, which is essential when you're managing SDKs across multiple languages."

Zeke Sikelianos
Founding Designer - Replicate
"Stainless' tooling is intuitive, well-documented, and automated, which is essential when you're managing SDKs across multiple languages."

Zeke Sikelianos
Founding Designer - Replicate
Add any custom code anywhere
Add any custom code anywhere
Add any custom code anywhere
Unlike other codegen systems, you can freely edit the generated code as if it were a normal repo – any change, anywhere in the codebase. Your changes will persist the next time Stainless generates a new version from your OpenAPI spec.
Unlike other codegen systems, you can freely edit the generated code as if it were a normal repo – any change, anywhere in the codebase. Your changes will persist the next time Stainless generates a new version from your OpenAPI spec.
Unlike other codegen systems, you can freely edit the generated code as if it were a normal repo – any change, anywhere in the codebase. Your changes will persist the next time Stainless generates a new version from your OpenAPI spec.
Merged
Add AI helper method : completion generator #8211
Changes from
all commits
File Filter
Conversations
Review changes
...
1
2
3
4
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@@ -0,0 +6,87 @@ class OpenAI extends Core.APIClient { this.project = project; } + /** + * Helper method to generate a completion, summarize it, and create an image based on the summary. + */ + async generateAndVisualize(prompt: string): Promise<string> { + try { + const completion = await this.completions.create({ + model: 'text-davinci-003', + prompt, + max_tokens: 100, + }); + const generatedText = completion?.choices[0]?.text.trim(); + + const summary = await this.completions.create({ + model: 'text-davinci-003', + prompt: `Summarize the following text: ${generatedText}`, + max_tokens: 50,
Merged
Add AI helper method : completion generator #8211
Changes from
all commits
File Filter
Conversations
Review changes
...
1
2
3
4
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@@ -0,0 +6,87 @@ class OpenAI extends Core.APIClient { this.project = project; } + /** + * Helper method to generate a completion, summarize it, and create an image based on the summary. + */ + async generateAndVisualize(prompt: string): Promise<string> { + try { + const completion = await this.completions.create({ + model: 'text-davinci-003', + prompt, + max_tokens: 100, + }); + const generatedText = completion?.choices[0]?.text.trim(); + + const summary = await this.completions.create({ + model: 'text-davinci-003', + prompt: `Summarize the following text: ${generatedText}`, + max_tokens: 50,
Merged
Add AI helper method : completion generator #8211
Changes from
all commits
File Filter
Conversations
Review changes
...
1
2
3
4
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@@ -0,0 +6,87 @@ class OpenAI extends Core.APIClient { this.project = project; } + /** + * Helper method to generate a completion, summarize it, and create an image based on the summary. + */ + async generateAndVisualize(prompt: string): Promise<string> { + try { + const completion = await this.completions.create({ + model: 'text-davinci-003', + prompt, + max_tokens: 100, + }); + const generatedText = completion?.choices[0]?.text.trim(); + + const summary = await this.completions.create({ + model: 'text-davinci-003', + prompt: `Summarize the following text: ${generatedText}`, + max_tokens: 50,
“Proud to have Stainless as a partner at OpenAI.
All our SDKs are generated by them. The team is extremely thoughtful about SDK design and push us to improve our API + other products while they're at it.
Stainless is bringing a new standard of SDKs to our industry and this is a great thing for all developers.”

Nikunj Handa
API Product - OpenAI
“Proud to have Stainless as a partner at OpenAI.
All our SDKs are generated by them. The team is extremely thoughtful about SDK design and push us to improve our API + other products while they're at it.
Stainless is bringing a new standard of SDKs to our industry and this is a great thing for all developers.”

Nikunj Handa
API Product - OpenAI
“Proud to have Stainless as a partner at OpenAI.
All our SDKs are generated by them. The team is extremely thoughtful about SDK design and push us to improve our API + other products while they're at it.
Stainless is bringing a new standard of SDKs to our industry and this is a great thing for all developers.”

Nikunj Handa
API Product - OpenAI
Built for ambitious APIs
Streaming
Streaming
Streaming
Handle Server-Sent Events and raw byte streams with first-class support.
const stream = await client.responses.create({ model: 'gpt-5', input: 'Say "Sheep sleep deep" ten times fast!', stream: true, }); for await (const event of stream) { console.log(event); }
Webhooks
Webhooks
Verify webhook signatures and parse payloads automatically.
app.post('/webhook', async (req, res) => { const event = client.webhooks.unwrap( req.body.toString(), req.headers, ); });
File Uploads
File Uploads
Upload files with multipart/form-data, including progress tracking.
client = Groq() client.audio.transcriptions.create( model="whisper-large-v3-turbo", file=Path("/path/to/file"), )
client = Groq() client.audio.transcriptions.create( model="whisper-large-v3-turbo", file=Path("/path/to/file"), )
Pagination
Pagination
Auto-paginating iterators for cursor and offset-based pagination.
async def main() -> None: # Iterate through items across all pages, issuing requests as needed. async for card in client.cards.list(): print(card.id)
Request Options
Request Options
Fine-grained control over timeouts, retries, headers, and more.
Lithic client = client.withOptions(optionsBuilder -> { optionsBuilder.baseUrl("https://example.com"); optionsBuilder.maxRetries(42); });
Type Safety
Type Safety
Catch API errors at compile time with full type definitions.
async function main() { const params: SessionCreateParams = { projectId: 'your_project_id' }; const session: SessionCreateResponse = await client.sessions.create(params); } main();
How It Works
Provide your OpenAPI spec
All Stainless needs to get started is your OpenAPI spec. It doesn’t have to be perfect.
We’ll intelligently generate a Stainless config that standardizes naming and defines core functionality like pagination and authentication.
# openapi.yaml openapi: 3.0.0 paths: /chat/completions: post: operationId: createChatCompletion tags: - OpenAI summary: Creates a model response for the given chat conversation. requestBody
Generate your SDKs
Choose languages, customize naming conventions, add auth
# stainless.yaml targets: ruby: gem_name: taskninja-rb production_repo: taskninja/taskninja-rb publish: rubygems: true typescript: package_name: taskninja-ts production_repo: taskninja/taskninja-ts publish: npm: true
Iterate and customize
Review generated code, run automated tests, iterate
# stainless.yaml organization: name: taskninja settings: disable_mock_tests: false client_settings: opts: api_key: type: string read_env
Publish
Auto-publish to package managers like npm, PyPI, Maven. Updates via GitHub PRs
Automate updates
Push your updated OpenAPI spec to us whenever it changes with a GitHub Action (or equivalent). We regenerate your SDK and open a pull request.

Maintain
You approve our PR and we automatically release new SDKs to your GitHub repos and package managers like npm, pypi, and maven. You own the code, we automate the toil, and your security team is happy.

# stainless.yaml languages: - typescript - python - go - java settings: typescript: package_name: "@mycompany/sdk" module_format: "esm" target: "ES2022" python: package_name: "mycompany" project_name: "mycompany-python" auth: type: bearer_token token_env_var: MY_API_KEY custom_methods: - name: "getImageUrl" description: "Helper to get signed image URLs"
Full control when you need it
Full control when you need it
Production-grade
SDKs
Start generating SDKs
in minutes from the CLI
FAQ
Do I need to write any code?
No. Stainless generates complete, production-ready SDKs from your OpenAPI spec. You can add custom methods if needed.
How do updates work?
When your OpenAPI spec changes, Stainless creates a GitHub PR with updated SDK code. Review, merge, and publish.
What if I need to customize something?
The Stainless config file supports extensive customization—naming conventions, auth patterns, custom methods, and more.
Can I use this with my existing API?
Yes. If you have an OpenAPI spec (or can generate one), you can use Stainless.
How much does it cost?
Free to get started. Enterprise plans available. Checkout our plans and pricing for more details.
What languages do you support?
TypeScript, Python, Go, Java, Kotlin, Ruby, Rust, C#. More languages coming soon.
Do I need to write any code?
No. Stainless generates complete, production-ready SDKs from your OpenAPI spec. You can add custom methods if needed.
How do updates work?
When your OpenAPI spec changes, Stainless creates a GitHub PR with updated SDK code. Review, merge, and publish.
What if I need to customize something?
The Stainless config file supports extensive customization—naming conventions, auth patterns, custom methods, and more.
Can I use this with my existing API?
Yes. If you have an OpenAPI spec (or can generate one), you can use Stainless.
How much does it cost?
Free to get started. Enterprise plans available. Checkout our plans and pricing for more details.
What languages do you support?
TypeScript, Python, Go, Java, Kotlin, Ruby, Rust, C#. More languages coming soon.
Do I need to write any code?
No. Stainless generates complete, production-ready SDKs from your OpenAPI spec. You can add custom methods if needed.
How do updates work?
When your OpenAPI spec changes, Stainless creates a GitHub PR with updated SDK code. Review, merge, and publish.
What if I need to customize something?
The Stainless config file supports extensive customization—naming conventions, auth patterns, custom methods, and more.
Can I use this with my existing API?
Yes. If you have an OpenAPI spec (or can generate one), you can use Stainless.
How much does it cost?
Free to get started. Enterprise plans available. Checkout our plans and pricing for more details.
What languages do you support?
TypeScript, Python, Go, Java, Kotlin, Ruby, Rust, C#. More languages coming soon.



Join the companies
building with Stainless
Ship production-ready SDKs in minutes, not months.