API versioning looks simple until you're maintaining v1, v2, and v3 with different clients on each version, and you realize the problem compounds faster than you expected. There are multiple valid solutions, but the worst part is that teams often pick the wrong one and live with the consequences for years.

URL path versioning for REST

The most common REST API versioning strategy: include the version in the URL path (/api/v1/resources, /api/v2/resources). The benefits are simplicity and debuggability, the version is visible in every request URL, in logs, and in error messages. The cost is that routing rules must differentiate version paths and the URL does not strictly follow REST principles (the same resource should have a canonical URL). For public APIs with multiple major versions in simultaneous use, URL versioning is operationally clear.

Header versioning for maturity

Passing the version in a custom header (Api-Version: 2021-06-01) is the Microsoft Azure API convention and is used by Stripe and GitHub. The URL stays clean; the version is in the header. The trade-off: not visible in browser URL bars or most log formats without configuration. For developer-facing APIs with sophisticated clients, header versioning is cleaner; for simpler integration scenarios, URL versioning is easier to understand and debug.

Backwards compatibility as the goal

The best versioning strategy is not needing to version: designing APIs to be backwards compatible by default. Adding optional fields to responses is backwards compatible. Adding optional request parameters is backwards compatible. Removing fields, changing field types, or changing semantics require a version. Disciplines that maintain backwards compatibility: OpenAPI contract testing in CI, consumer-driven contract tests (Pact), and a formal deprecation process for removed capabilities.

Deprecation policy and sunset headers

When removing an API version, the process matters as much as the technical mechanism. Announced deprecation with a clear sunset date, the Sunset header (RFC 8594) in API responses that returns the sunset date, monitoring of calls to deprecated endpoints to identify clients that have not migrated, and communication to known API consumers. Microsoft and Stripe are examples of large API providers with explicit deprecation processes that balance developer trust with the ability to evolve the API.