Back to blog
Coding

API Versioning Strategies in 2026: What Stripe and GitHub Actually Do

5 min read

Every API versioning guide opens with the same four options — URL path, query parameter, header, and content negotiation — and then leaves you to guess which one to pick. What's more useful in 2026 is looking at how two of the most heavily used production APIs on the internet, Stripe and GitHub, actually solved this, because both have made deliberate, well-documented choices that diverge from the generic advice in instructive ways.

The four standard approaches

For completeness, the baseline options every API eventually chooses between:

Approach Example Pros Cons
URL path /api/v1/users Explicit, cacheable, visible in logs "Pollutes" the URL, implies resource identity changes with version
Query parameter /api/users?version=1 Keeps URI stable Easy to omit accidentally, less visible in routing
Header X-API-Version: 1 Clean URLs Invisible in browser/curl without extra flags, harder to test manually
Content negotiation Accept: application/vnd.api.v1+json Most "RESTful" per HTTP spec intent Most complex to implement and document

(OneUptime synthesis)

URL path versioning is the most common choice for its simplicity and visibility — Microsoft Graph and Twitter/X API v2 both use it (OneUptime synthesis). But the two APIs worth studying closest — Stripe and GitHub — both use header-based, date-stamped versioning instead of the URL path approach most tutorials default to.

Stripe: date-based versions, monthly minor releases

Stripe's API versions look like 2026-08-26.dahlia — a date plus a codename, not a simple integer (WebSearch synthesis). The mechanism has two tiers:

  • Monthly releases contain only backward-compatible changes. You can upgrade to a new monthly release without touching your integration code (WebSearch synthesis).
  • Major releases bundle breaking changes into a new dated version, shipped with a detailed changelog and migration guide (WebSearch synthesis).
2024-12-18.acacia   <- older major version
2025-08-27.basil    <- major version with breaking changes
2026-06-24.dahlia   <- newer major version
2026-08-26.dahlia   <- current, latest

Every Stripe account is pinned to a specific version at API-key creation time, and stays pinned until the integration explicitly upgrades — meaning Stripe can ship breaking changes constantly without breaking any live integration, because nobody moves version without opting in. This is meaningfully different from typical "v1/v2/v3" URL versioning, where the number of live major versions tends to stay artificially low because each one is expensive to maintain — Stripe's date-based scheme effectively supports as many pinned versions as there are active accounts, with the version-translation logic handled server-side.

GitHub: date-based headers with a hard support window

GitHub's REST API also uses date-based versioning (YYYY-MM-DD format), specified via an X-GitHub-Api-Version header rather than the URL (WebSearch synthesis). As of mid-2026 the latest version is 2026-03-10, with no sunset scheduled, while the legacy 2022-11-28 version remains supported until March 10, 2028 (WebSearch synthesis).

Note

GitHub's explicit policy: any API version is supported for at least 24 months after a newer version is released (WebSearch synthesis). That's a concrete, contractual SLA most API providers only gesture at vaguely — worth copying directly if you're writing your own versioning policy.

Why date-based versioning fits fast-moving platform APIs

The pattern that emerges from both Stripe and GitHub: date-based versioning specifically suits fast-evolving platform APIs with a large, heterogeneous integration base (DigitalApplied synthesis). The reasoning:

  1. No semantic ambiguity about severity — a version number like v2 tells you nothing about how much changed; a date tells you exactly when the API's behavior was frozen for you.
  2. No "which v2 do I mean" confusion — teams that ship frequent breaking changes under v1/v2 naming eventually run into disputes about what "v2" actually includes if it evolved before a v3 shipped. Dates are unambiguous.
  3. Per-account pinning without per-account infrastructure — the server can maintain one canonical latest implementation and translate for older pinned dates, rather than literally running parallel deployed versions.

Breaking vs. non-breaking, defined concretely

Both the generic guidance and the Stripe/GitHub examples converge on the same breaking-change definition:

Non-breaking (safe for a minor/monthly release):

  • Adding new optional response fields
  • Adding new endpoints
  • Adding new optional request parameters

Breaking (requires a new major/dated version):

  • Removing or renaming a response field
  • Changing a field's type
  • Making a previously optional request field required
  • Changing response status codes for existing conditions

(OneUptime synthesis)

Deprecation communication

The consistent recommendation across sources: support at least two versions simultaneously (current + previous) to give clients migration runway, and give at least 6-12 months notice before a version sunsets (OneUptime synthesis). GitHub's 24-month floor is more generous than this baseline — a signal of how seriously a platform with a massive long-tail of unmaintained integrations (abandoned scripts, old CI pipelines) needs to take backward compatibility.

The mechanical implementation for communicating deprecation: standard HTTP headers, Deprecation and Sunset, attached to responses from an aging version so client tooling can detect and warn automatically rather than relying on developers reading changelog emails (OneUptime synthesis).

HTTP/1.1 200 OK
Deprecation: true
Sunset: Wed, 10 Mar 2028 00:00:00 GMT
Link: <https://docs.example.com/api/migration-guide>; rel="deprecation"

Decision framework

  • Small public API, infrequent breaking changes: URL path versioning (/v1/, /v2/) — simplest to implement, easiest for consumers to understand at a glance.
  • High-frequency platform API with a large integration base: date-based header versioning, Stripe/GitHub-style — lets you ship continuously without forcing every integration onto a shared version number.
  • Internal/private APIs with controlled consumers: query parameter or header versioning is often overkill; a documented breaking-change policy with coordinated deploys may be simpler than any formal versioning scheme.
  • Whatever you choose: pick one primary strategy and don't mix it with others on the same API — mixing versioning styles across endpoints is a consistently cited source of consumer confusion (WebSearch synthesis).

Takeaway

The "URL vs header vs query param" framing most API versioning guides lead with understates the real decision, which is closer to "how many simultaneously live versions can you actually afford to support, and for how long." Stripe's account-level pinning and GitHub's 24-month floor are both answers to that harder question, and both are more instructive for a growing API than the generic four-option comparison. If your API will accumulate a long tail of integrations you don't control, copy the date-based, generously-supported model — not because it's more "RESTful," but because it's the one production evidence shows scales.


Sources: OneUptime — How to Version REST APIs Effectively, Hacker News — How does Stripe do date-based API versioning?, Stripe Documentation — Versioning

Get new posts as they publish

No spam — just the next post, straight to your inbox.

Keep reading

Discussion