1. Why Version Your API?

Once an API is in production and clients are depending on it, you cannot simply change it. A client that calls /users/123 and expects a full_name field will break if you rename it to name. API versioning solves this by letting you introduce breaking changes in a new version while existing clients continue using the old version.

The key principle: you are not versioning your code, you are versioning the contract between your API and its clients. A version bump signals that the contract has changed in a way that requires client updates.

2. Breaking vs Non-Breaking Changes

Change TypeBreaking?Examples
Add optional field to responseNoAdding "profile_picture" to user object
Add new optional request parameterNoAdding optional "include_deleted=true" param
Add new endpointNoNew /v1/subscriptions endpoint
Remove field from responseYesRemoving "full_name", client code breaks
Rename a fieldYes"full_name" → "name"
Change field data typeYesamount: string → amount: integer
Remove an endpointYesDELETE /v1/legacy-reports
Change required→optional paramsNoMaking "email" optional
Change optional→required paramsYesMaking "phone" required

3. Strategy 1 — URL Versioning

The version number is embedded in the URL path. This is the most common strategy and the easiest to implement, route, and document.

  URL Versioning examples:
  GET  https://api.example.com/v1/users/123
  POST https://api.example.com/v2/payments
  GET  https://api.example.com/v3/products?page=1

  At the API Gateway / load balancer level:
  /v1/* → service-v1 (legacy)
  /v2/* → service-v2 (current)
  /v3/* → service-v3 (beta)

  Pros: explicit, easy to route, easy to cache, curl/browser friendly
  Cons: clutters URLs, can lead to parallel codebases, versioned links
        in bookmarks/docs go stale

4. Strategy 2 — Header Versioning

The version is specified in a custom HTTP request header. The URL stays clean, but the version is less discoverable and harder to test in a browser.

HTTP — header versioning examples # Custom version header: GET /users/123 HTTP/1.1 Host: api.example.com API-Version: 2 # Accept header (content negotiation): GET /users/123 HTTP/1.1 Host: api.example.com Accept: application/vnd.example.v2+json # Stripe's date-based header: POST /v1/charges HTTP/1.1 Host: api.stripe.com Stripe-Version: 2024-06-20 Authorization: Bearer sk_live_...

Stripe's Date-Based Versioning

Stripe uses date-based version strings (e.g. 2024-06-20) instead of v1/v2/v3. Each API key has a default version locked at the time it was created. Developers can test new versions by setting the Stripe-Version header, then upgrade their API key's default once they have validated compatibility. This approach avoids the "when does v3 become v4?" question — every change that needs a version gets a new date.

5. Strategy 3 — Query Parameter Versioning

The version is passed as a URL query parameter. Simple to implement but considered less clean than URL or header versioning.

HTTP — query parameter versioning GET /users/123?version=2 HTTP/1.1 GET /users/123?api_version=2026-06-13 HTTP/1.1 # Pros: easy to implement, no extra headers needed # Cons: ugly URLs, parameters can be stripped by caches/proxies, # pollutes query string alongside business parameters # Common in older APIs (Google Maps API uses this)

6. Strategy 4 — Content Negotiation

The version is expressed through the Accept and Content-Type headers using media type versioning. This is the most REST-pure approach but the least practical for most teams.

HTTP — content negotiation versioning # Request specific version via Accept header: GET /users/123 HTTP/1.1 Accept: application/vnd.myapi.user.v2+json # Server responds with versioned content type: HTTP/1.1 200 OK Content-Type: application/vnd.myapi.user.v2+json { "id": 123, "name": "Alice" # v2 field (was "full_name" in v1) } # GitHub API example: Accept: application/vnd.github.v3+json

7. Versioning Strategy Comparison

StrategyURL CleanlinessDiscoverabilityCachingUsed By
URL versioningClutteredExcellentNative (URLs differ)Stripe, Twilio, AWS, most APIs
Header versioningCleanPoor (hidden in header)Requires Vary headerStripe (Stripe-Version), custom APIs
Query parameterOKGoodWorks (URL differs)Google Maps, older APIs
Content negotiationVery cleanPoorRequires Vary headerGitHub v3 (Accept header)

8. API Deprecation — Sunset Headers

When you decide to retire an old API version, you must communicate the timeline to clients. The Sunset HTTP header (RFC 8594) provides a machine-readable deprecation date:

HTTP — deprecation and sunset headers HTTP/1.1 200 OK Content-Type: application/json Deprecation: true Sunset: Sun, 31 Dec 2026 23:59:59 GMT Link: <https://api.example.com/v2/users>; rel="successor-version" # Best practice deprecation timeline: # T-12 months: add Deprecation: true header to all v1 responses # T-6 months: add Sunset header with exact date # T-3 months: email all active clients using v1 # T-0: v1 returns 410 Gone

Never Break Existing Versions Without Notice

Removing or changing an API version without adequate notice destroys developer trust. Follow industry standard: minimum 6–12 months notice for deprecation of publicly documented API versions. Even with notice, keep the old version available as long as traffic exists. Stripe has maintained some API versions for over a decade because enterprise clients cannot update quickly. Build your versioning infrastructure to support long-lived parallel versions.

9. API Gateway Versioning

In a microservices architecture, the API gateway (Kong, AWS API Gateway, Nginx) handles version routing so individual services do not need to be aware of versioning:

  • Route /v1/* to the v1 service cluster
  • Route /v2/* to the v2 service cluster
  • Strip the version prefix before forwarding to the upstream service
  • Add deprecation headers at the gateway level for old versions
  • Rate-limit old versions more aggressively to encourage migration

This separation means you can run v1 and v2 of a service in parallel without changing the service code — the gateway handles the routing and clients are isolated from the underlying service topology.

How We Research and Update This Guide

We test the underlying formula or workflow, compare outputs with reliable references, and revise examples whenever the page content changes.

  • The workflow or formula is tested directly in the tool and compared against independent reference examples.
  • Examples are kept practical so readers can verify the result without hidden assumptions.
  • Pages are revised whenever the interface, calculation flow, or surrounding guidance materially changes.

Frequently Asked Questions — API Versioning