case-study

Stripe: Versioning by Account Pinning

also called Stripe API Versions

Stripe pins each account to the API version it first integrated against and maintains compatibility transformations, so integrations built years ago continue to work unchanged.

stripeapi-designcompatibilitymigration

The problem

A payments API cannot break its integrations. Merchants have code they wrote years ago, running in production, that nobody is going to revisit — and a breaking change means their payments stop.

But an API that never changes accumulates design mistakes permanently, and a payments platform's domain evolves continuously as products, regulations and payment methods change.

What they did

Stripe pins each account to the API version current when it first integrated. Requests are served according to that version unless the caller explicitly requests a newer one.

Internally, the current version is the one that exists, and a chain of transformations converts requests and responses to and from older versions. Adding a new version means writing the transformation that maps between it and its predecessor, so the compatibility burden is incremental rather than requiring parallel implementations.

Upgrading is an explicit action a merchant takes when ready, having read the changelog — not something imposed on them.

The trade-off

The cost is real and ongoing. Stripe maintains a large number of versions and their transformations, and every new change must be expressible as a transformation from the previous shape. That constrains what changes are possible: a change that cannot be expressed as a transformation of the old contract cannot be made this way.

It also means the internal model and the external contract diverge, requiring discipline to keep the transformation layer thin rather than accumulating business logic.

The transferable lesson

Decide who bears the cost of change. Most APIs push it onto consumers: version, deprecate, and require everyone to migrate by a date. Stripe absorbs it centrally, which is a substantial engineering commitment made because the alternative — merchants' payments breaking — is commercially unacceptable.

For an internal API with a handful of known consumers, pushing the cost outward is reasonable and cheaper. For a public API where consumers are numerous, unknown and unmotivated to migrate, absorbing it centrally may be the only approach that works.

The general point: the best versioning strategy is one you rarely need. A team versioning frequently usually has a modelling problem — the contract is exposing internal structure that keeps changing — rather than a versioning problem.