Every API evolves. Fields get renamed, response shapes change, authentication mechanisms improve. The question is not whether breaking changes will happen — it is how your API communicates them, how much time customers get to migrate, and what happens when they do not.
The Three Versioning Approaches
URL versioning (/v1/, /v2/)
Simplest and most common. The version is in the URL path, visible in every log, every bookmark, every curl command. Drawback: it forces every integration to update their base URL on version changes. Benefit: explicit, impossible to miss, easy to route at the gateway layer.
Header versioning (Accept: application/vnd.api.v2+json)
Version negotiation via HTTP headers. The URL stays stable; the version is in the Accept or API-Version header. Used by GitHub and Stripe. Benefit: clean URLs. Drawback: more complex to implement, version information is invisible in URLs shared in logs or documentation.
Date-based versioning (Stripe model)
Stripe uses a date-based versioning system where each API key is pinned to a version date. New customers get the latest version. Existing integrations keep their pinned version until they opt into a migration. Breaking changes ship on a date, not a version number. This is sophisticated to build but excellent for customer experience.
The Sunset Process
Whatever versioning scheme you use, sunsetting an old version requires: a deprecation announcement with a specific sunset date (minimum 12 months for production APIs), the Sunset HTTP response header on all deprecated endpoint responses, proactive outreach to customers still using the deprecated version, and a hard removal date you actually enforce.
The hardest part of API versioning is not the technical implementation — it is the customer communication and the discipline to actually remove deprecated endpoints. An API graveyard of endpoints you said you were deprecating in 2023 undermines trust in your deprecation process.
