HTTP APIs

larsggu.meReference › API versioning

API versioning

/v1/... or Accept: application/vnd.example.v1+json

The mechanism by which an interface changes without breaking the callers already written against it, and the definition of which changes require it.

Description

Versioning is usually discussed as a choice between a path segment, a header and a query parameter, which is the least consequential part of it. The consequential part is the written definition of what counts as a breaking change, because that definition is what callers actually rely on when they decide how defensively to parse a response.

The workable definition is narrow. Adding an optional request field, adding a response field, and adding a value to an enumeration a caller is told to treat as open are compatible. Removing or renaming a field, tightening validation, changing a type, changing a default, changing pagination behaviour and adding a required field are not. Anything that makes a previously accepted request fail, or a previously parseable response fail to parse, is breaking regardless of how small it looks.

The path segment remains the common choice because it is visible in every log line, cacheable, and obvious in a browser. Header negotiation is more correct in the terms of the HTTP specification and considerably harder to debug, which in practice decides it for most published interfaces.

Whatever the mechanism, two commitments matter more than the syntax: a stated support window for each version, and a way to tell which callers are still on an old one. Without the second, the first is unenforceable, and a version that cannot be retired accumulates until every change has to be made in several places at once.

Fields

Fields of API versioning
FieldFormMeaning
Selectorpath or media typeWhere the version is expressed.
Defaultexplicit versionWhat an unversioned request receives. Ordinarily the oldest supported.
Compatible changeadditive onlyNew optional request fields, new response fields, new values in open enumerations.
Breaking changeeverything elseRemovals, renames, type changes, tightened validation, new required fields.
Support windowstated durationHow long a version remains callable after its successor ships.
Deprecationresponse headerAnnounces retirement on the responses of the version being retired.

Example

Announcing a retirement

GET /v1/invoices HTTP/1.1

HTTP/1.1 200 OK
Deprecation: true
Sunset: Wed, 30 Sep 2026 23:59:59 GMT
Link: </v2/invoices>; rel="successor-version"

# callers on v1 can be identified from these requests
# and told before the window closes

The retirement is announced on the responses of the version being retired, where the affected callers will see it.

Failure modes

  • Treating a tightened validation rule as compatible because no field changed shape.
  • Announcing retirement only in release notes, which the affected callers are not reading.
  • Leaving unversioned requests to follow the newest version, so callers break on a release they did not ask for.
  • Shipping a new version for an additive change, which multiplies versions without cause.

Topic: Data shape. Last modified 2026-09-06.