Provider integrations

Stripe API Versions: What Actually Determines Which Version Your Request Uses?

Stripe API versions come from request headers, SDK behavior, and account defaults—not from the relay name alone.

Stripe version questions usually mix together three different things: the account's default API version, an explicit Stripe-Version request header, and the version associated with an SDK release. They affect different requests. A package version is not itself an API-version selector for every integration.

The account default

Raw requests that do not specify a version use the Stripe account's default API version. The default is managed in Stripe Workbench. Upgrading it can change response shapes for requests that rely on it, so treat an account-wide upgrade as a compatibility change rather than a dashboard-only setting.

An account default also matters for Stripe-run activity where your application is not making an outbound API request. Do not infer the version of every Stripe-generated operation from the SDK installed in your application. Webhook endpoints, Event snapshots, and direct API requests have related but separate version selectors.

Stripe publishes named releases and maintains a versioning reference. Do not call a particular version “latest” in application documentation unless you have checked the current first-party reference at the time you edit it.

An explicit Stripe-Version header

For a raw HTTP request, the version is explicit when the request includes the header:

curl https://api.stripe.com/v1/customers/cus_123 \
  -u "$STRIPE_SECRET_KEY:" \
  -H "Stripe-Version: 2025-06-30.basil"

If the header is absent, the account default applies. If it is present, the request asks Stripe for that version, subject to the version and endpoint rules documented by Stripe. The header is part of the request sent to Stripe; it is not a comment for the application.

The same distinction appears on a POST:

POST /v1/payment_intents
Authorization: Bearer <Stripe secret key>
Content-Type: application/x-www-form-urlencoded
Stripe-Version: 2025-06-30.basil

amount=2500&currency=usd

Without Stripe-Version, the request depends on the account's default. With it, the requested version is explicit. Keep the request identifier and response headers when diagnosing a difference between environments.

SDK release and API version

Stripe SDK behavior is language- and version-dependent. For example, Stripe's current Node documentation says that requests made with a supported stripe-node release align with the API version current when that SDK release was published, while an apiVersion option can override it. Other SDKs expose their own configuration and release rules.

A direct SDK example therefore needs to be labelled as SDK-specific:

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
  apiVersion: '2025-06-30.basil'
});

const customer = await stripe.customers.retrieve('cus_123');

The exact option name and supported value depend on the language and installed SDK. If the option is omitted, the SDK may transmit a version selected by its own documented behavior, or the request may rely on the account default. Read that SDK's current versioning documentation rather than assuming all clients work the same way.

Package version and Stripe API version are related but not identical. A package upgrade can change the version selected by generated requests and can also change the SDK's types, serialization, retry defaults, or helper methods. An account-default change can affect raw HTTP clients and SDK requests that do not send an explicit override. Conversely, pinning an SDK does not necessarily pin a raw request made elsewhere in the same application.

What raw HTTP controls

Raw HTTP gives the application direct control over the request header. It is easy to test two otherwise identical requests:

GET /v1/customers/cus_123
(no Stripe-Version header)
→ Stripe applies the account-default behavior

GET /v1/customers/cus_123
Stripe-Version: <explicit version>
→ Stripe applies the explicitly requested version

Do not compare only the application code. Confirm the account, mode, connected-account context, path, expansions, and headers. An apparently identical request can return a different shape because it came from a different account or used a different version selector.

Stripe returns a Stripe-Version response header when applicable. The Request-Id response header identifies the provider request, and Stripe's Dashboard request logs provide another way to inspect the request. Use those values when comparing a direct SDK call with a relay call. Never copy credentials or sensitive request bodies into a support ticket just to make the comparison easier.

What Gateman forwards

Gateman's stripe:use capability preserves this distinction. The application sends a native Stripe method, path, body, and supported headers to POST /stripe/request. Gateman allowlists Stripe-Version and forwards it only when the application explicitly supplies the nested header.

For a Gateman relay request:

  • The official Gateman client does not infer a Stripe API version from an installed Stripe SDK.
  • Gateman does not impose its own Stripe SDK version layer.
  • If the nested Stripe-Version header is omitted, Stripe applies the relevant account-default behavior.
  • If it is present, Gateman forwards the explicit value as part of the native Stripe request.
  • The selected Gateman environment chooses the configured provider credential, not the Stripe API version.

For example:

{
  "environment": "staging",
  "method": "GET",
  "path": "/v1/customers/cus_123",
  "headers": {
    "Stripe-Version": "2025-06-30.basil"
  }
}

Removing that nested header changes the selector: it does not cause Gateman to substitute a version from a Gateman client library. See the Stripe capability reference and Contract v1 for the application-to-Gateman boundary.

Connect does not remove the version question

Stripe-Account: acct_... selects the connected-account context for supported platform requests. The application must authorize that account context; an account ID in a header is not proof that the caller may use it. Gateman can allowlist and forward the header, but Stripe's credential and account permissions remain authoritative. Version selection remains a separate concern.

A request may therefore have two independent selectors: the account context selected by Stripe-Account, and the API version selected by an explicit Stripe-Version or by the relevant account default. When debugging Connect, record both. Do not conclude that a version difference is an authorization difference, or that a connected-account header chooses the API version.

Stripe's Connect authentication documentation explains the account context.

Webhook endpoint versions are separate

Webhook events are not rendered according to the API version of a later retrieval request. A webhook endpoint can have an API version set when it is created; otherwise the account default applies according to Stripe's rules. Stripe's webhook endpoint object exposes api_version, and the endpoint API lets you configure the version for events sent to that endpoint.

The event object also records api_version. For API v1 events, the event contains a versioned snapshot of the underlying object. Retrieving that old Event under a newer request version does not rewrite its embedded snapshot: the event's data remains the representation created at event time. A later API request for the current Customer or PaymentIntent can have a different shape, but it is not a migration of the historical Event.

This makes webhook upgrades a separate compatibility task. Your receiver must understand the endpoint's payload version, while follow-up API calls may use their own explicit request version or account default. Test both paths.

See Stripe's webhook endpoint API, Event object reference, and signature guidance.

A practical upgrade checklist

Before changing an account default, SDK release, request header, or webhook endpoint version:

  1. Identify every selector: account default, SDK behavior, explicit Stripe-Version, connected-account context, and webhook endpoint api_version.
  2. Record representative requests, response headers, Request-Id values, and the relevant Stripe request logs.
  3. Test representative resources, expansions, validation errors, authorization errors, and pagination against the target version.
  4. Test webhook payloads, signature handling, duplicate delivery, and the event types that drive business state.
  5. Update application types, parsing, fixtures, and error handling for changed fields or enum values.
  6. Deploy code that can understand the target response before changing the production default or endpoint version.
  7. Change one selector deliberately and verify the resulting Stripe-Version and request logs.
  8. Retain a rollback plan: know which code, SDK, account setting, or endpoint configuration must be restored and for how long the provider permits it.

Stripe's upgrade guidance is the appropriate source for current rollback and migration details. A rollback plan does not replace testing; it limits the impact of an unexpected response change.

The useful rule is simple: identify the component that selects the version for the exact request you are debugging. Do not use the SDK package number, account setting, request header, and webhook endpoint setting as interchangeable labels.

← All articles