API changes

Stripe API versioning: how it works and what to copy

7 min read

Stripe API versioning works by date. Every account is pinned to an API version named after a release date, and any single request can override that pin with a Stripe-Version header. At the time of writing (October 2026), the current version in Stripe’s docs is 2026-09-30.endive, and the same scheme is something a much smaller API can copy in a weekend.

Every Stripe fact below comes from Stripe’s own pages, linked where it is used.

MechanismWhat Stripe doesSource
Version nameA date, plus a release name since 2024 (2026-09-30.endive)Versioning
Default versionPinned on the account, changed in WorkbenchVersioning
Per-request overrideStripe-Version header, or the SDK optionUpgrades
WebhooksRendered in the version set on the endpointUpgrades
CadenceMonthly releases with no breaking changes, a major release twice a yearVersioning
Old versionsKept working through internal version change modulesEngineering post

How does Stripe API versioning work?

Stripe gives every account a default API version, and every request that does not name a version uses it. Callers choose when to move, by changing the default or by setting a version on individual requests.

Stripe’s engineering post says the account is pinned the first time it makes an API request: the account is “automatically pinned to the most recent version available”, and from then on every call is assigned that version implicitly.

The version string is a date. Since the 2024-09-30.acacia release, it also carries a name, as in 2026-09-30.endive. The date orders the versions, and the name tells you which major release family a version belongs to.

How do you choose a version per request?

Send the Stripe-Version header on the request, or set the version in the SDK. Stripe’s upgrade guide shows the header form, and the same call works in live and test environments.

curl https://api.stripe.com/v1/charges \
  -u "$STRIPE_SECRET_KEY:" \
  -H "Stripe-Version: 2026-09-30.endive"

Stripe’s guide notes that when you set the version globally or per request in an SDK, the response objects come back in that version.

Stripe also recommends against leaning on the account default. In its words, specify the version for each request, with the header or a pinned SDK, so that your code decides the version and a dashboard setting does not.

SDKs pin differently by language. The docs say recent versions of the dynamically typed libraries use the API version that was latest when that SDK release shipped, and strongly typed ones (Java, Go and .NET) are fixed to it. Installing a library version is, in effect, choosing an API version.

What happens to webhooks when the version changes?

A webhook event is rendered in the API version attached to its endpoint, not the version your server code uses. Stripe’s docs say events use the version set when the endpoint was created, and otherwise the account default. Changing your SDK version does not change what your webhook handler receives.

Your request path and your event path can therefore sit on two different versions. For event destinations, you set snapshot_api_version only when you create the destination, so a different version means a new destination.

Stripe’s upgrade path for this is a parallel run. Create a new endpoint at the target version, send the same events to both, teach the handler to process one and ignore the other, then switch and disable the old endpoint. Because every event arrives twice during the overlap, the handler has to be idempotent. That is a good pattern to copy for any API that emits events, and a webhook changelog is where you announce the payload changes that make it necessary.

What are the monthly and major releases?

Since the 2024-09-30.acacia release, Stripe releases a new API version monthly with no breaking changes, and issues a new major release twice a year that starts with a version containing breaking changes. Its versioning page says you can upgrade to any monthly release without updating your code, while a major release can require changes.

Major releases carry names. The versioning page gives Basil as an example, and Stripe’s announcement of the process says the names come from plants, starting with Acacia, and that monthly releases keep the name of the major release before them so the name signals they are safe to upgrade to. Stripe’s changelog lists the names in use, and at the time of writing the newest entry is 2026-09-30.endive.

So the date answers “how new”, and the name answers “is this a breaking boundary”. Stripe’s announcement also keeps room for exceptions: it reserves the right to ship an out-of-cycle breaking change where an integration would be severely impacted without it. The announcement is at Stripe’s new API release process.

What is the latest version of the Stripe API?

At the time of writing (October 2026), Stripe’s versioning page states that the current version is 2026-09-30.endive, and its changelog lists the same version as the newest. Stripe publishes a new version monthly, so any string printed in an article ages quickly. Read the live changelog before you pin anything, and pin the version you tested against.

How does Stripe keep old versions working?

Stripe keeps old versions alive by writing every breaking change as a self-contained version change module and applying the modules backward from the newest shape of the data. Its engineering post on API versioning describes the mechanism.

Each module declares what it changes, documents the change, and includes a transformation function. The post gives the example of a field changing from a string to a hash. To build a response, the system works out the target version, then walks back through time and applies each module it finds along the way until it reaches that version.

Two side effects follow from that design, and the post names both. Because modules declare the fields and resources they touch, Stripe can generate its API changelog from them on deployment. And because the account’s version is known, the documentation can adapt to it and warn about backwards-incompatible changes since that version.

What does it cost, and what should a smaller API copy?

Versioning costs engineering attention, and Stripe says so. The engineering post acknowledges a maintenance burden and states the goal that the less thought needed for old behaviour while writing new code, the better. It also describes lightweight API reviews before release, to avoid needing a version change at all.

A small API cannot afford a module chain for every old version, and does not need one. Copy the parts that carry the value:

  1. Dated versions. A date needs no judgment about what counts as “major”, and callers can read it. The versioning best practices article compares this with URL and header schemes.
  2. A pinned default. Fix the account or key to the version at first use, so the API never shifts under a working integration.
  3. A per-request override. A header that lets a caller test a new version on one call, in production, before committing.
  4. A version on the webhook endpoint. Event payloads are the place callers are surprised most.
  5. One changelog entry per version. Make it name the version, the date, who is affected and what to do. What counts as breaking is the test for what belongs in a new version at all, and the API changelog article covers the entry itself.

Skip the module chain until the number of supported versions forces it. Two or three live versions can be handled with a few branches and a sunset date, which sunsetting an API version walks through.

If you publish a dated changelog, the version history is only as good as its entries. In Changeloop, a draft entry is created from each merged pull request and held for a human to approve before it is published to the changelog page and feed. That is where a per-version entry gets written, and the one human gate is the review that says what a caller must do.

FAQ

What is the latest version of the Stripe API? At the time of writing (October 2026), Stripe’s versioning page states that the current version is 2026-09-30.endive. Stripe issues a new version monthly, so check its changelog before pinning, and write the version into your code instead of relying on the account default.

How do I set the Stripe API version on a request? Send the Stripe-Version header, for example Stripe-Version: 2026-09-30.endive, or set the version in your server-side SDK globally or per request. Without either, a request uses your account’s default version, which you set in Workbench.

Do webhooks use the same Stripe API version as my requests? Not necessarily. Webhook events use the version set when the endpoint was created, and the account default if none was set. Upgrading your SDK does not change the payload your webhook handler receives, so upgrade endpoints separately and test them in parallel.

Is Stripe-style date versioning right for a small API? Dated versions, a pinned default, a per-request header and one changelog entry per version are cheap and worth copying. The internal chain of version change modules is not, until you support many old versions at once. Start with two live versions and a sunset date for the older one.


The technical claims in this article have not been independently reviewed. If something here is wrong, tell us and we will correct it.

Related on changeloop: Developer docs

changeloop
The team building a closed-loop changelog. Your users ask, your team ships, the person who asked gets told.