Definition
When APIs evolve, you need a way to tell the server which version of the data you want - and there’s a surprisingly elegant way to do this using a mechanism that HTTP has had all along. Media type versioning puts the API version right inside the Accept header, the same header your browser uses to tell servers whether it wants HTML, JSON, or images.
Instead of putting version numbers in the URL (like /api/v1/users) or query parameters (?version=2), media type versioning uses custom content types. You send a header like Accept: application/vnd.mycompany.v2+json which says “I want version 2 of your API, formatted as JSON.” The “vnd” stands for “vendor” - it’s a signal that this is a custom media type defined by a specific organization.
This approach is considered the most “RESTful” because it uses HTTP’s built-in content negotiation system exactly as it was designed. The URL stays clean and focused on identifying the resource (/users/123), while the version is treated as a detail about how you want that resource represented. It’s like the difference between asking for “document #123” (the URL) versus asking for “document #123, but please give me the 2020 version in PDF format” (the media type). This separation makes your URLs timeless - they don’t need to change when you release a new API version.
Example
Media type versioning is used by some of the most developer-friendly APIs out there. Here’s where you’ll encounter it:
GitHub’s API: GitHub is the poster child for media type versioning. When you call their API, you specify Accept: application/vnd.github.v3+json to get version 3 of their API in JSON format. When GitHub releases version 4, you can switch by changing only that header - all your URLs stay the same. GitHub even supports requesting specific preview features with headers like Accept: application/vnd.github.squirrel-girl-preview+json (yes, that’s a real preview name for reactions).
Stripe’s API (hybrid approach): While Stripe primarily uses date-based versioning in headers, they also support content negotiation for format selection. This hybrid approach shows how media type concepts blend with other strategies in the real world.
Enterprise Systems: Many large enterprise APIs use media type versioning because it fits well with service meshes and API gateways that can route requests based on headers. A gateway can send v1 requests to the legacy servers and v2 requests to new microservices, all transparent to the client.
Document Management Systems: When retrieving documents through APIs, media types naturally handle the question of “what format do you want?” - JSON metadata, PDF download, or HTML preview of the same document resource.
Analogy
The Restaurant Menu with Languages: Imagine a restaurant where the menu item is the same (Resource: “Item #47”), but you can request it described in different languages and detail levels. You tell the waiter “I’d like item 47, in Spanish, with full ingredient details” - you’re specifying the representation you want, not changing what item you’re ordering. Media type versioning works similarly: same resource, different ways of describing it.
The Legal Document Versions: Think about how law firms handle contract versions. The underlying agreement (the resource) might be the same, but clients can request the 2022 revision with the updated liability clauses or the simpler 2020 format. You don’t create a new contract number for each revision - you ask for the version you need. Media types work the same way.
The Universal Remote: Modern universal remotes can control any TV, but you have to tell them which protocol to use. The button “power” (the resource) is the same, but the signal format changes based on the device. Media type versioning is like telling the remote “send this command using the Samsung 2023 protocol” - same command, adapted representation.
The Music Streaming Quality: When you stream music, you’re requesting the same song (resource), but services let you choose the quality: CD quality, high resolution, or compressed for mobile. You don’t get different song IDs for different qualities - you specify the format you want. Media type versioning brings this same concept to API data.
Code Example
// Media type versioning (GitHub style)
GET https://api.company.com/repositories/123
Accept: application/vnd.company.v1+json
GET https://api.company.com/repositories/123
Accept: application/vnd.company.v2+json
// With format negotiation
GET https://api.company.com/repositories/123
Accept: application/vnd.company.v2+xml
// Specific version with parameter
GET https://api.company.com/repositories/123
Accept: application/vnd.company+json; version=2
// Server response includes media type
[HTTP/1.1](https://reference.apios.info/terms/http-1-1/) 200 OK
Content-Type: application/vnd.company.v2+json; charset=utf-8
// Unsupported version
GET https://api.company.com/repositories/123
Accept: application/vnd.company.v5+json
HTTP/1.1 406 Not Acceptable
Content-Type: application/json
{
"error": "NotAcceptable",
"message": "API version 5 not available",
"supportedVersions": ["v1", "v2", "v3"]
}