Mystery DigitalTalk to us
API Versioning Isn't a URL Prefix: A Strategy for Platforms That Outlive Their First Contract
APIsArchitecture

API Versioning Isn't a URL Prefix: A Strategy for Platforms That Outlive Their First Contract

Marcus Ionescu · 2025-06-20 · 3 min read

When enterprise clients ask us to design their API strategy, they usually already have a versioning scheme — /v1/, /v2/ in the URL — and they usually already regret it. Putting the version in the path solves the easy problem (routing) and ignores the hard one: what actually counts as a breaking change, and who decides when to force a migration. A URL prefix is a filing system, not a strategy.

Define "breaking" before you ship v1

Most teams don't write down a compatibility contract until after the first breaking change already happened by accident. We require every platform engagement to produce a compatibility policy before the first external consumer integrates: which fields are guaranteed to remain present, which enums are closed versus open, whether new required fields are ever added to existing endpoints, and how nulls versus absent keys are treated. Consumers build brittle client code when the server's compatibility guarantees are implicit. Write the contract down, publish it alongside the docs, and enforce it in CI with contract tests that fail the build on an undocumented breaking change — not just a linter that checks the shape of a schema file.

Version the contract, not the surface

Rather than versioning entire endpoints, we version fields and behaviors independently using request-scoped feature flags or a API-Version header resolved server-side into a specific response-shaping layer. This lets you ship a breaking change to one field of one resource without forcing every consumer of every other endpoint through a migration. The blast radius of a version bump should match the blast radius of the actual change. A payments field rename shouldn't force a client that only reads shipping addresses to re-certify their integration.

Deprecation is a relationship, not a header

Deprecation and Sunset headers are necessary but not sufficient — nobody reads response headers until something breaks. For enterprise consumers specifically, the sunset process that works is direct: instrument actual usage per API key, identify which named accounts are still calling the deprecated path, and reach out to them individually with a migration guide and a deadline before you ever flip the switch. We've seen "properly deprecated" endpoints get shut off on schedule and take down a client's production system anyway, because the deprecation notice went to an inbox nobody monitored. Treat the sunset date as a commitment you make to specific accounts, not a broadcast.

Design for additive by default

The versioning schemes that age well share one property: the common case — adding a field, adding an endpoint, adding an enum value in an open enum — never requires a version bump at all. You only pay the versioning cost for genuinely breaking changes: removing a field, changing a type, tightening a validation rule. If your team is bumping the major version every quarter, the object model was under-designed at v1, not that your product is evolving unusually fast. Push new optionality into additive extension points — extra fields, sub-resources, capability flags — and reserve breaking versions for the handful of times per year they're truly unavoidable.

Keep the old version running longer than feels comfortable

The instinct after cutting v2 is to fast-track v1's shutdown to reduce maintenance surface. For a consumer platform this is fine. For an enterprise-integration platform, it's usually a mistake — the accounts still on v1 are disproportionately your largest, slowest-moving, highest-revenue integrations, exactly the ones you can't afford to force into an emergency migration. Budget for running two major versions in parallel for longer than your engineering team wants to, because the cost of that overlap is almost always smaller than the cost of an enterprise account's emergency escalation.

← Back to blog