Try the REST API Checker

API Versioning: URL Paths, Headers, Query Strings, and Why "Just Change the Endpoint" Always Comes Back to Haunt You

The moment you release a public API, you've made an implicit promise to every client that depends on it: "this won't break." Versioning is how you keep that promise while still being able to evolve. Here's how URL path, Accept-header, and query-string versioning actually differ in practice, when each fits, and why the deprecation plan matters more than the versioning scheme itself.

June 16, 2026 7 min read
Share: Facebook WhatsApp LinkedIn Email
API Versioning: URL Paths, Headers, Query Strings, and Why "Just Change the Endpoint" Always Comes Back to Haunt You

The moment a second client depends on your API, every breaking change becomes a coordination problem — and "just update all clients" stops being a real answer

The previous articles on this site covered HTTP status codes, API authentication, and rate limiting. This article addresses API versioning — the strategies for making breaking changes to an API without breaking existing clients — and why the choice of versioning strategy matters less than having a strategy (and, crucially, a deprecation plan) before you need one.


What counts as a "breaking change"

Not all API changes are breaking. Adding a new field to a response, adding a new optional request parameter, adding a new endpoint — these are generally backwards-compatible (existing clients that don't know about the new field/parameter/endpoint simply ignore it, or don't use it, and continue working as before).

Breaking changes are those that cause existing clients, without modification, to fail or produce incorrect results:

  • Removing or renaming a field in a response (clients that read that field now get null/undefined/an error)
  • Changing a field's type (a field that was a string becomes an integer — clients expecting a string may break)
  • Changing the meaning of a field's value (a status field that had values "active"/"inactive" now has "enabled"/"disabled" — the values the client checks for no longer match)
  • Removing or renaming an endpoint (clients calling it get 404s)
  • Changing required vs optional parameters (a field that was optional becomes required — clients that don't send it now get errors)

Strategy 1: URL path versioning — /v1/, /v2/

The most common, most visible versioning approach: the version number is part of the URL path itself — https://api.example.com/v1/users, https://api.example.com/v2/users.

Advantages:

  • Extremely visible and unambiguous — anyone reading a URL or a codebase immediately knows which version is being called
  • Easy to test/explore in a browser or any HTTP tool — no special headers needed
  • Simple caching — the version is part of the URL, so CDNs and caches can treat /v1/ and /v2/ as entirely separate resources with no ambiguity
  • Easy to run both versions simultaneously — route /v1/ to old code, /v2/ to new code, independently

Disadvantages:

  • "REST purist" objection: the resource (/users) hasn't changed — it's the representation of that resource that changed — purists argue the URL should identify the resource, not the representation version, and that versioning belongs in headers
  • URLs proliferate in documentation, bookmarks, client code — all need updating when clients upgrade

Strategy 2: Accept header versioning — Accept: application/vnd.api+json;version=2

Version information is conveyed via HTTP request headers — typically using Accept (the client specifies what response format/version it's willing to accept) or a custom header like API-Version: 2.

Advantages:

  • "Cleaner" URLs — the same URL (/api/users) serves all versions; the request specifies which version it wants
  • More aligned with HTTP semantics (content negotiation via Accept is a built-in HTTP mechanism)

Disadvantages:

  • Much harder to test/share — you can't simply paste a URL to demonstrate "this is v2 of the users endpoint"; the header is invisible in a URL
  • Caching complications — caches that don't correctly consider the Accept header as part of the cache key may serve the wrong version to clients that sent different headers — the Vary: Accept response header is required to handle this correctly (covered in previous HTTP-headers articles), but isn't universally respected by all caching layers
  • Discoverability — clients need documentation to even know what header to send and what values are valid

Strategy 3: Query string versioning — ?version=2 or ?v=2

The version is a query parameter: https://api.example.com/users?v=2.

Advantages:

  • Visible (like URL path versioning — it's in the URL)
  • Easy to test — just add ?v=2 to any URL in a browser/tool
  • No URL structure changes — no /v1///v2/ prefix to route at the server

Disadvantages:

  • Cache behavior is version-dependent — caches should include query strings as part of cache keys, but some caching configurations ignore query strings entirely (or strip them) — risking serving the wrong cached version
  • Less "official"-looking than URL path versioning — often feels more ad-hoc to API consumers
  • Query string pollution — if an endpoint already uses query parameters (pagination, filtering, etc.), adding a ?v= parameter alongside them is functional but messy

Which strategy "wins"? The practical answer

There is no universal consensus. URL path versioning is arguably the most widely adopted in practice (by major public APIs), largely due to its simplicity and visibility — the "REST purist" objection to it is theoretically valid but practically less relevant for most teams. Header-based versioning is theoretically cleaner but operationally more complex to test and cache correctly. Query-string versioning occupies a middle ground that works fine but feels less intentional to many API consumers.

The more important question: regardless of which strategy you choose, do you have:

  1. A clear definition of what constitutes a "breaking change" (so your team agrees on when versioning is required vs when a change can be made without a version bump)?
  2. A deprecation policy (how long will v1 continue to work, once v2 exists)?
  3. Communication to clients about where v1 is, what changed in v2, and when v1 will be removed?

These operational questions matter more than the versioning scheme itself.


Deprecation: the part most API designers underplan

Releasing v2 creates two APIs to maintainv1 and v2both receiving (potentially different) bug fixes, both needing security patches, both consuming infrastructure. Without a deprecation timeline, v1 can persist indefinitely, accumulating maintenance burden.

A typical deprecation lifecycle:

  1. Announce deprecation of v1 — with a specific, committed sunset date
  2. Communicate to clients (API keys that are calling v1 should ideally get direct notification — many APIs add a Deprecation or Sunset response header to deprecated-version responses, providing the sunset date in machine-readable form)
  3. At (or after) the sunset date: return 410 Gone (or 404) for deprecated-version requests — not a silent redirect to v2, since clients expecting v1 semantics may mishandle v2 responses even if they're redirected to them

How long before sunset to announce — varies widely by API and client ecosystem — public APIs with many clients (especially third-party clients the API publisher doesn't control) typically need longer deprecation windows than internal APIs where you do control all clients.


How to use the REST API Checker on sadiqbd.com

  1. Testing versioned endpoints: explicitly set the version-indicating element (URL path, header, or query parameter) in each request — to ensure you're testing the intended version and not relying on a default that may differ in production
  2. Comparing v1 vs v2 responses: run identical requests against both versions, comparing responses — this is exactly the scenario this tool enables, and is the most direct way to understand what actually changed between versions (beyond what documentation says)
  3. Checking Deprecation/Sunset headers: if an endpoint you're testing returns these headers — note the sunset date; this is a signal your client integration will need updating before that date

Frequently Asked Questions

Should I version my API from the very beginning, or wait until I actually need a v2? Starting with /v1/ from day one is generally recommended — even if you hope never to need v2 — because retrofitting versioning into an existing, unversioned API is harder than starting versioned (clients would have to update URLs to add /v1/, which is itself a breaking change if they were calling unversioned endpoints). The cost of starting with /v1/ is nearly zero; the cost of not having done so, when v2 becomes necessary, can be significant. Starting versioned is a cheap, one-time decision that buys future flexibility.

Is the REST API Checker free? Yes — completely free, no sign-up required.

Try the REST API Checker free at sadiqbd.com — test, compare, and debug any REST API endpoint directly in your browser.

Share: Facebook WhatsApp LinkedIn Email

REST API Checker

Free, instant results — no sign-up required.

Open REST API Checker →
Similar Tools
Cron Explainer JWT Decoder Regex Tester JSON Formatter Timestamp Converter UUID Generator Base64 Encoder/Decoder JSON Unescape & Cleaner
REST API Checker — Test Any REST API Instantly in Your Browser
Developer
REST API Checker — Test Any REST API Instantly in Your Browser
HTTP Status Codes Explained: A Complete Debugging Guide for API Work
Developer
HTTP Status Codes Explained: A Complete Debugging Guide for API Work
API Authentication Methods Compared: Keys, Bearer Tokens, OAuth 2.0, and HMAC
Developer
API Authentication Methods Compared: Keys, Bearer Tokens, OAuth 2.0, and HMAC
API Rate Limiting: How It Works, How to Read Rate Limit Headers, and Exponential Backoff Strategies
Developer
API Rate Limiting: How It Works, How to Read Rate Limit Headers, and Exponential Backoff Strategies
The Most Revealing API Tests Aren't Successful Requests — A Systematic Error-Path Testing Guide
Developer
The Most Revealing API Tests Aren't Successful Requests — A Systematic Error-Path Testing Guide