The Problem
In 2012, Twitter changed their API from v1 to v1.1 and gave developers nine months to migrate. Even with that generous timeline, thousands of third-party apps broke on the deadline. Some developers had abandoned their apps. Some missed the announcement. Some did not have time to test. The Twitter developer community was furious. API versioning is not just a technical decision - it is a social contract with everyone who depends on your API.
The Three Main Strategies
1. URL Path Versioning (Most Common)
The most explicit and widely adopted approach:
GET /v1/users/42 <-- Original version
GET /v2/users/42 <-- Breaking changes in user response
# Who uses this:
# Stripe: https://api.stripe.com/v1/charges
# GitHub: https://api.github.com/v3/repos
# Twilio: https://api.twilio.com/2010-04-01/Accounts
Pros: crystal clear which version you are using. Easy to route in load balancers. Easy to test (paste URL in browser). Can run v1 and v2 on completely different servers.
Cons: pollutes URLs, makes it harder to maintain multiple versions of internal logic. Purists argue the URL should identify the resource, not the API version.
2. Header Versioning
GET /users/42
Accept: application/vnd.myapi.v2+json
# Or a custom header:
GET /users/42
X-API-Version: 2
# Who uses this:
# GitHub (also): Accept: application/vnd.github.v3+json
Pros: clean URLs, version is metadata not part of the resource identity.
Cons: harder to test (cannot just paste URL in browser), less discoverable, some proxy caches ignore custom headers.
3. Query Parameter Versioning
GET /users/42?version=2
# Who uses this:
# Google APIs: ?v=3
# Amazon: ?Version=2012-11-05
Pros: easy to test, optional (can default to latest or oldest).
Cons: messy with other query parameters, caching gets complicated because the version changes the cache key.
Comparison at a Glance
Strategy Clarity Cacheable Testable Used By
-------------- -------- ---------- --------- ----------------
URL path High Yes Yes Stripe, Twilio
Header Medium Varies No* GitHub
Query param Medium Careful Yes Google, AWS
Date-based High Yes Yes Twilio, Stripe
* Requires curl or Postman to test with custom headers
The Practical Recommendation
For most teams: use URL path versioning (/v1/, /v2/). It is the most widely understood pattern, works with every tool, and makes it impossible to accidentally call the wrong version.
But do not version every change. Only create a new version when you make a BREAKING change:
BREAKING changes (require new version):
- Removing a field from the response
- Changing a field's type (string -> integer)
- Renaming a field (user_name -> username)
- Changing response structure ({"users": [...]} -> [{...}])
- Changing error format
- Making a previously optional field required
NON-BREAKING changes (backwards compatible, no new version needed):
+ Adding a new optional field to the response
+ Adding a new endpoint
+ Adding a new optional query parameter
+ Adding a new optional request body field
+ Adding new enum values (if clients handle unknown values)
+ Adding new error codes (if clients have a default handler)
Deprecation Strategy
When releasing v2, follow this playbook:
- Announce deprecation of v1 with a timeline (e.g., 12 months). Post in changelog, send emails, show in dashboard.
- Add a Sunset header to v1 responses indicating the shutdown date: Sunset: Sat, 01 Mar 2026 00:00:00 GMT
- Add a Deprecation header: Deprecation: true
- Monitor v1 usage analytics. Identify your top 20 consumers by volume and reach out directly.
- Start returning warning headers on v1: Warning: 299 - 'API v1 will be retired on 2026-03-01. Please migrate to v2.'
- After the deprecation period, return 410 Gone with a body explaining how to migrate.
Stripe's Versioning: The Gold Standard
Stripe uses a unique date-based approach: each API key is pinned to a specific API version (e.g., 2024-06-20). Your integration keeps working even as Stripe releases updates. You upgrade at your own pace by changing the version in your dashboard. Every version difference is documented in their changelog. When you override the version in a request header, you can test the new version without affecting production. This is the most developer-friendly versioning strategy in the industry.
Interview Tip
When asked about API versioning in an interview, say: 'I use URL path versioning for clarity. I only bump versions for breaking changes like removing fields or changing types. Adding new optional fields is backwards-compatible and does not need a new version. For the deprecation timeline, I give clients 12 months with automated warnings in response headers, usage monitoring, and direct outreach to top consumers.' Then mention Stripe's date-based versioning as an advanced approach.
Key Takeaway
Version your API in the URL path. Only bump versions for breaking changes. Additive changes (new fields, new endpoints) are backwards-compatible and do not need a new version. Give clients generous deprecation timelines and include Sunset headers so automated tools can detect upcoming retirements.