Client settings
Configure your SDK's client level settings, including authentication, custom arguments, default headers, retries with exponential backoff, timeouts, idempotency keys, and file uploads.
Authentication
Section titled “Authentication”The Stainless Generator defines your SDK’s authentication using the #/security and #/components/securitySchemes particulars from your OpenAPI spec. By default, Stainless SDKs are set to authenticate using an environment variable:
client_settings: opts: auth_token: type: string # Whether this client option is required to instantiate the client: nullable: false # Whether this value should be read from an env: read_env: ORG_AUTH_TOKEN auth: { security_scheme: BearerAuth }
# optional, overrides the OpenAPI spec's top-level security key, required if it isn't presentsecurity: - BearerAuth: []For more complicated authentication schemes, or should the Stainless Generator fail to configure yours correctly, see the examples below.
The Stainless generator uses the top-level security as the security configuration supported by the SDKs, but
you may want to specify a different combination of security than the one used in your OpenAPI spec. The
security and security_schemes in the Stainless config overrides the values in the spec.
HTTP Bearer Authorization: Bearer <bearer-token>
The HTTP Bearer authentication method is configured like so:
# OpenAPIcomponents: security_schemes: MyBearerAuth: type: http scheme: bearer # optional, documentation purpose only bearerFormat: JWT
security: - MyBearerAuth: {}# Stainless configclient_settings: opts: my_bearer_token: # or `token`, `bearer_token`, `api_key`, etc. type: string read_env: ORG_BEARER_TOKEN auth: { security_scheme: MyBearerAuth }API Key <Header>: <API Key>
An API key in a header authentication method is configured like so:
# OpenAPIcomponents: security_schemes: MyApiKeyAuth: type: apiKey name: My-Api-Key in: header
security: - MyApiKeyAuth: {}# Stainless configclient_settings: opts: my_api_key: # or `token`, `auth_token`, etc. type: string read_env: ORG_API_KEY_TOKEN auth: { security_scheme: MyApiKeyAuth }HTTP Basic Authorization: Basic <base64(username:password)>
The HTTP Basic authentication method is configured like so:
# OpenAPIcomponents: security_schemes: MyBasicAuth: type: http scheme: basic
security: - MyBasicAuth: {}# Stainless configclient_settings: opts: my_username: type: string read_env: ORG_MY_USERNAME_TOKEN auth: { security_scheme: MyBasicAuth, role: 'username' } my_password: type: string read_env: ORG_MY_PASSWORD_TOKEN auth: { security_scheme: MyBasicAuth, role: 'password' }OAuth 2.0 Client Credentials
Stainless fully supports OAuth client_credentials. For this grant type, our SDKs handle initial authorization and the entire token management lifecycle.
Stainless uses the OAuth configuration in your OpenAPI spec if present, or you can specify an OAuth configuration in your Stainless config.
Example security configuration in the Stainless config:
security:- OAuth2: []
security_schemes: OAuth2: type: oauth2 flows: clientCredentials: tokenUrl: >- https://example.com/oauth2/token?grant_type=client_credentials scopes: # ...You must also define client options for the client_id and client_secret parameters in your Stainless config so users of your SDKs can provide those values. The names of these parameters in opts can be customized; the important part is to specify the correct auth information for each (especially auth.role, which must be either client_id or client_secret).
client_settings: opts: client_id: type: string auth: security_scheme: OAuth2 role: client_id read_env: ORG_CLIENT_ID client_secret: type: string auth: security_scheme: OAuth2 role: client_secret read_env: ORG_CLIENT_SECRETWith a configuration like the one above, users can provide a client_id and client_secret when initializing your SDK to use OAuth.
Behind the scenes, the SDK will fetch an access token from the configured tokenUrl when the first request is made, cache it, and use it for all following requests until the token expires. Upon expiration, the SDK will automatically obtain a new token.
Failed OAuth requests are automatically retried based on the retry configuration for the SDK. If all retries fail, an exception will be thrown or an error will be returned (whichever makes sense for the particular language being used).
Please reach out if you need help supporting your configuration.
OAuth 2.0 Authorization Codes
If you’re using authorization codes, we recommend you set up Bearer Authentication and add custom code to help your users convert authorization codes to access tokens. If you’re interested in generated helpers for this, or if you need additional guidance, reach out and let us know!
With this approach, initial authorization and token management are not handled by Stainless. We recommend you point your users to an OAuth SDK in their preferred language for handling these parts of the OAuth flow.
Once Stainless is configured to use Bearer Authentication, as seen in the example below, users of your SDKs will be able to authenticate with their access token.
OpenAPI spec:
securitySchemes: OAuth2: type: oauth2 flows: authorizationCode: authorizationUrl: https://example.com/oauth2/auth tokenUrl: https://example.com/oauth2/token scopes: # ...Stainless config:
client_settings: opts: access_token: type: string auth: security_scheme: BearerAuth read_env: MY_TEAM_ACCESS_TOKEN
security: - BearerAuth: []
security_schemes: BearerAuth: type: http scheme: bearerPlease reach out if you need help supporting your configuration.
Optional Auth
To specify that you accept no authentication, declare a security configuration with no key and no properties like so:
security: - BearerAuth: {} - {} # <= No authMultiple API Keys
If your API requires different keys for different endpoints, you can configure multiple security schemes in your OpenAPI spec and corresponding client options in your Stainless config:
# OpenAPIcomponents: securitySchemes: ReadKeyAuth: type: apiKey in: header name: X-Read-Api-Key WriteKeyAuth: type: apiKey in: header name: X-Write-Api-Key
security: - ReadKeyAuth: [] - WriteKeyAuth: []# Stainless configclient_settings: opts: read_key: type: string nullable: true auth: security_scheme: ReadKeyAuth read_env: READ_API_KEY write_key: type: string nullable: true auth: security_scheme: WriteKeyAuth read_env: WRITE_API_KEYThe generated SDK accepts multiple keys during initialization. When both keys are provided, all configured auth credentials are sent with each request:
const client = new MyAPI({ readKey: 'read_key_123', writeKey: 'write_key_456',});
// Both keys are sent with requestsclient.resources.list();client.resources.create({...});client = MyAPI( read_key="read_key_123", write_key="write_key_456",)
# Both keys are sent with requestsclient.resources.list()client.resources.create(...)client := myapi.NewClient( option.WithReadKey("read_key_123"), option.WithWriteKey("write_key_456"),)
// Both keys are sent with requestsclient.Resources.List(ctx)client.Resources.New(ctx, ...)Extra client arguments
Section titled “Extra client arguments”You can define extra client arguments, which generally appears as an extra argument on the client
constructor of each SDK (in Go, it appears as an extra RequestOption). These are generally used for
supplying values for authentication methods, but can be also used for extra headers and
more.
client_settings: opts: pet_store_version: type: string # can be a string, boolean, or a number nullable: true # makes this an optional argument default: v3 # the default pet store version to use
read_env: PETSTORE_VERSION send_in_header: 'X-Petstore-Version'const client = new Petstore({ apiKey: '...', petStoreVersion: 'v2', // sends 'X-Petstore-Version: v2'});Default headers
Section titled “Default headers”Default headers are headers we add to every request made by the SDK. We send platform headers so that you can collect metrics on the languages and platforms your users use. For all SDKs, we send the following:
| Headers | Description |
|---|---|
X-Stainless-Arch | The architecture, such as x32, x64, arm, aarch64, or other:xxx. |
X-Stainless-Lang | The language, such as typescript, python, java, kotlin, or go. |
X-Stainless-OS | The OS, such as Android, MacOS, Windows, FreeBSD, OpenBSD, Linux, or Other:xxx. |
X-Stainless-Package-Version | The package version, such as v2.3.1. |
X-Stainless-Read-Timeout | The timeout, in seconds, between receiving response chunks, such as 3. Not sent if no read timeout is configured. |
X-Stainless-Retry-Count | Which retry number the request is for, such as 0 for the first request, 1 for the first retry, 2 for the second retry, and so on. |
X-Stainless-Runtime | The runtime, such as node or CPython. |
X-Stainless-Runtime-Version | The runtime version, such as v14.8.0. |
X-Stainless-Timeout | The timeout, in seconds, for the entire request, such as 10. Not sent if no overall timeout is configured. |
We also send some extra headers for each language:
| Python Headers | Description |
|---|---|
X-Stainless-Async | Whether or not the AsyncClient was used. |
| Java/Kotlin Headers | Description |
|---|---|
X-Stainless-OS-Version | The OS version, such as 14.4. |
For requests made by a Stainless-generated MCP server, we will also send some extra headers:
| MCP Headers | Description |
|---|---|
X-Stainless-MCP | Always true. |
Retries
Section titled “Retries”Our clients retry connection errors (for example, a network connectivity problem), 408 Request Timeout, 409 Conflict, 429 Rate Limit, and >=500 Internal errors.
By default, our clients retry 2 times (so a total of 3 requests) using the exponential backoff strategy with an initial delay of 0.5s and a max delay of 8s. We also add a jitter of 25% to spread out requests.
This can be configured by you for your users:
client_settings: default_retries: # 5 retries are made, with the interval [1, 2, 4, 8, 10 (capped by the max)] # not accounting for jitter max_retries: 5 initial_delay_seconds: 1 max_delay_seconds: 10Or it can be changed by the user in each language’s SDK:
client = new Petstore({ maxRetry: 3,});Each request includes an X-Stainless-Retry-Count header so you know how often clients retry. See Default headers for details.
Disabling retries
Section titled “Disabling retries”Retries can be disabled in two ways. Your users can disable this at at the client level by setting max_retries to 0. For example:
client = new Petstore({ maxRetry: 0, // Doesn't retry at all});Alternatively, your API can direct our SDKs to not retry by sending the X-Should-Retry header in your responses.
Retry-After and Retry-After-Ms
Section titled “Retry-After and Retry-After-Ms”Our SDKs also respect the Retry-After
header sent by the API, which defines
in integers how many seconds we should wait before making another request. We also support the
Retry-After-Ms header which is less standard but gives more fine-grained control over timings in
milliseconds.
The clients only respect values that are “reasonable” which are positive values less than a minute.
X-Should-Retry
Section titled “X-Should-Retry”Additionally, the clients support the X-Should-Retry header, which can be used to explicitly control whether
a request should be retried. This header must be explicitly set to either X-Should-Retry: true or
X-Should-Retry: false to be used as an override.
When set to true, it forces a retry attempt even if the request would not normally be retried based on the
default retry rules. When set to false, it prevents a retry attempt even if the request would normally be
retried. If the header is not present or set to any other value, the default retry behavior is used.
We recommend using the header over other methods to control the retry behavior on special status codes or other situations specific to your API, as it can be used by all consumers of the API and can be configured independently of the version of the SDK.
Timeouts
Section titled “Timeouts”In addition to retries, our clients also have a default timeout of 60 seconds, which can be configured.
client_settings: default_timeout: PT60S # ISO8601 or number of milliseconds. This is 60 secondsIdempotency key
Section titled “Idempotency key”Idempotency Keys can prevent errors where multiple retried requests are interpreted as separate requests. Our clients retry connection errors and certain status codes by default to create robust integrations, so we recommend that your API supports idempotency keys, especially for critical endpoints.
You can configure idempotency keys by specifying client_settings.idempotency like so:
client_settings: idempotency: header: 'Idempotency-Key' # or a header you prefer, like 'X-Request-Id'We send the configured header with a value in the format stainless-retry-{random_uuid} on all
non-GET requests. This header is also possible to override in every SDK that we generate.
File uploads
Section titled “File uploads”Our SDKs support file uploads out of the box, via multipart/form-data requests.
File parameters can be defined in the OpenAPI spec by specifying a multipart/form-data request with
parameters that are type: string and format: binary.
paths: /files: post: summary: Upload a file requestBody: required: true content: multipart/form-data: schema: type: object properties: file: type: string format: binary description: The file to upload file_metadata: type: string description: > Some other property that you can add, serialized as a field in multipart/form-data required: - file responses: '200': description: File uploaded successfullyEach SDK provides convenient ways to handle file uploads appropriate for that language. Below is an example in TypeScript:
await client.files.create({ file: fs.createReadStream('./local-file.txt') });// orawait client.files.create({ file: new File(['my bytes'], 'content.txt') });Similar helpers exist in other languages. For example, in Python:
with open('content.txt', 'rb') as f: client.files.create(file=f)See the README.md of each SDK for language-specific documentation.