2. Media types & versioning#
As your API evolves, clients need a stable way to understand which shape they’re getting and how to migrate when it changes. JsonDispatch solves this by using a request version header plus request media types, and signaling the exact served version in a response header.
2.1 Media type explained (with examples)#
For JsonDispatch JSON endpoints, send the vendor media type in Accept:
Accept: application/vnd.infocyph.jd.v1+json
Media type breakdown#
``application`` — application payload (static)
``vnd.infocyph`` — your vendor namespace (configurable)
``jd`` — JsonDispatch spec identifier (static for this spec)
``v1`` — major version of the request format (configurable)
``+json`` — JSON syntax suffix (static)
Note
Responses can simply use Content-Type: application/json; charset=utf-8 while still following the JsonDispatch envelope.
Examples#
Project “Acme”:
application/vnd.acme.jd.v1+jsonPersonal/OSS (not recommended for org APIs):
application/prs.yourname.jd.v1+json
2.2 Versioning strategy (major/minor/patch)#
JsonDispatch follows Semantic Versioning:
Major (
v1 → v2): breaking changes to the envelope or field typesMinor (
v1.1 → v1.2): backward-compatible additionsPatch (
v1.0.0 → v1.0.1): backward-compatible bug fixes
Tip
The request header X-Api-Version carries the desired full version (e.g., 1.3.0).
The request media type in Accept carries the request-format major version (e.g., …jd.v1+json).
The server’s served version is returned in X-Api-Version-Selected.
Do not use
Content-Typefor API version negotiation.For requests with a JSON body, use
Content-Type: application/json; charset=utf-8.
2.3 Required & recommended headers#
Requests#
MUST send:
X-Api-Version: <MAJOR.MINOR.PATCH>
Example:
X-Api-Version: 1.4.0
MUST send for JsonDispatch JSON endpoints:
Accept: application/vnd.<vendor>.jd.v<MAJOR>+json
Example:
Accept: application/vnd.infocyph.jd.v1+json
Clients MAY send multiple media types in
Accept(comma-separated). The server MUST select the first supported media type, or return406 Not Acceptablewhen none are supported.For requests with a JSON body, MUST send:
Content-Type: application/json; charset=utf-8
Responses#
MUST send:
X-Api-Version-Selected: <MAJOR.MINOR.PATCH>
Example:
X-Api-Version-Selected: 1.4.0
MAY send:
Content-Type: application/json; charset=utf-8
Note
Servers can set a vendor media type on responses if needed, but
application/json is sufficient and preferred.
2.3.1 Negotiation and version error matrix#
Use the following status codes consistently for protocol-level request problems:
Condition |
Status |
Required behavior |
|---|---|---|
|
|
Return |
JsonDispatch JSON endpoint receives unsupported |
|
Return |
Request includes JSON body with unsupported |
|
Return |
Requested version is retired (past sunset window) |
|
Return |
For deprecated-but-still-supported versions, continue serving responses and include Deprecation and Sunset
headers to signal migration timing.
X-Request-Id, X-Correlation-Id and other tracing headers are covered in Section 3.
2.4 Version selection & migration#
The server controls the response envelope version via
X-Api-Version-Selected.When you introduce a breaking change, bump the request major (e.g.,
v1 → v2), request the new full version viaX-Api-Version, and keep returningapplication/jsonwithX-Api-Version-Selected.
Create (client → server):
POST /articles
X-Api-Version: 1.4.0
Accept: application/vnd.infocyph.jd.v1+json
Content-Type: application/json; charset=utf-8
{ "title": "Hello JD" }
Response
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
X-Api-Version-Selected: 1.4.0
X-Request-Id: 1f1f6a2e-0c8f-4f7f-9b4b-5d2d0a3f5b99
{
"status": "success",
"data": { ... }
}
After a breaking change (client updates request major):
POST /articles
X-Api-Version: 2.0.0
Accept: application/vnd.infocyph.jd.v2+json
Content-Type: application/json; charset=utf-8
{ "title": "Hello JD v2" }
Response
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
X-Api-Version-Selected: 2.0.0
X-Request-Id: 6c2a3d7e-9d5a-4b61-9b05-d1d8f6a8f4a1
{
"status": "success",
"data": { ... }
}
Clients signal the desired API version via X-Api-Version and the request-format major via Accept. When sending
a JSON body, use Content-Type: application/json; charset=utf-8. Servers announce the exact implementation
served via X-Api-Version-Selected in the response.
2.5 Non-JSON responses (reports & exports)#
JsonDispatch defines the response envelope for JSON. For binary or tabular deliverables (CSV, PDF, ZIP, images), return the native media type directly and keep JsonDispatch for orchestration endpoints (job creation, metadata, links).
2.5.1 Direct file delivery#
When the endpoint returns a file stream:
Request:
GET /reports/activity/download?from=2025-09-01&to=2025-09-30
Accept: text/csv
X-Api-Version: 1.4.0
Response#
Response
HTTP/1.1 200 OK
Content-Type: text/csv
Content-Disposition: attachment; filename="activity-report-2025-09.csv"
X-Api-Version-Selected: 1.4.0
X-Request-Id: 7bfae01e-771c-41d4-b1cf-0ad52d8bce19
Note
Use the correct Content-Type (e.g., text/csv, application/pdf, application/zip) and add
Content-Disposition for downloads.
2.5.2 Orchestration via JsonDispatch (recommended)#
Create the report asynchronously and return a JsonDispatch envelope with status and links.
Request:
POST /reports/activity
X-Api-Version: 1.4.0
Accept: application/vnd.infocyph.jd.v1+json
Content-Type: application/json; charset=utf-8
{ "from": "2025-09-01", "to": "2025-09-30", "format": "csv" }
Response#
Response
HTTP/1.1 202 Accepted
Content-Type: application/json; charset=utf-8
X-Api-Version-Selected: 1.4.0
X-Request-Id: 3b2c7a5a-0b2e-4b69-b1a2-1a2c3d4e5f6a
Body#
{
"status": "success",
"message": "Report job accepted",
"data": {
"report_id": "rep_9KfGH2",
"state": "queued",
"format": "csv",
"expires_at": "2025-10-31T23:59:59Z"
},
"_links": {
"self": "https://api.example.com/reports/activity/rep_9KfGH2",
"download": {
"href": "https://cdn.example.com/reports/rep_9KfGH2.csv",
"meta": { "method": "GET", "expires": "2025-10-31T23:59:59Z" }
}
},
"_properties": {
"data": { "type": "object", "name": "report" }
}
}
2.5.3 Streaming & large datasets#
For very large exports, consider streaming formats:
CSV/TSV stream:
text/csvNDJSON stream:
application/x-ndjsonGzip: add
Content-Encoding: gzipwhen appropriate
Pair streaming/download endpoints with a JsonDispatch status endpoint so clients can poll readiness and discover _links.download.
Status polling:
GET /reports/activity/rep_9KfGH2
Accept: application/vnd.infocyph.jd.v1+json
X-Api-Version: 1.4.0
Response (ready)#
Response
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
X-Api-Version-Selected: 1.4.0
X-Request-Id: d1c9b15f-9c1e-42d5-9a9e-8b8e5a2b1c0a
Body#
{
"status": "success",
"data": {
"report_id": "rep_9KfGH2",
"state": "ready",
"size_bytes": 9421331
},
"_links": {
"download": "https://cdn.example.com/reports/rep_9KfGH2.csv",
"retry": "https://api.example.com/reports/activity/rep_9KfGH2/retry"
}
}
Tip
Rule of thumb: use JsonDispatch for control, status, and discovery; use native media types for the actual file bytes.