JSON MIME Type: Content-Type, +json, and API Errors
Set application/json correctly, understand JSON-based media types, and fix API failures caused by the wrong HTTP headers.
The short answer
The JSON MIME type for a normal HTTP API body is application/json. Send it in Content-Type when your request body is JSON. Use Accept: application/json when JSON is a response format your client can handle. Those headers are related, but they answer different questions.
In this guide
Content-Type, Accept, and response Content-Type are different
Most JSON header incidents are not spelling mistakes. They happen because a client, a server, or a proxy applies a correct header in the wrong direction of the exchange. This guide is for developers debugging a real request, where the request body, declared type, response body, and response type all need to agree.
| Header | Who sends it | Meaning |
|---|---|---|
| Content-Type | Request client | The format of the body being uploaded. |
| Accept | Request client | Response representations the client can process. |
| Content-Type | Response server | The representation the server actually returned. |
A useful counterexample is a GET request with no body. It usually needs no request Content-Type at all. Adding Content-Type: application/json does not ask the server for JSON; that is the job of Accept. Even then, the server may return HTML, CSV, or a JSON problem document, so check the actual response header before parsing.
application/json and UTF-8: the strict API edge case
For an ordinary JSON representation, use application/json. The IANA registration is the registry entry behind that value. RFC 8259 says JSON exchanged between systems outside a closed ecosystem must be UTF-8. UTF-8 is therefore the interoperable default, not a value a client should guess from an operating system locale.
You will still see application/json; charset=utf-8 in production. Many frameworks emit it and most clients accept it. The detail that catches teams is that the IANA registration defines no charset parameter for application/json; a compliant recipient does not need it to discover JSON encoding. A strict endpoint that compares the whole string to application/json can reject an otherwise usable request with 415 Unsupported Media Type.
A safer server rule
Parse the media type before the semicolon when parameters are allowed, then enforce an explicit allowlist. Follow a documented API contract when it requires the exact type. Do not "fix" a charset disagreement by decoding JSON as Latin-1 or silently dropping invalid bytes.
What the +json suffix means
A type ending in +json is not a typo for application/json. It is a structured syntax suffix defined by RFC 6839. The suffix tells a generic client that the representation uses JSON syntax while the complete media type keeps its more specific contract.
| Media type | Represents | When to use it |
|---|---|---|
| application/json | An ordinary JSON representation | Default for most API request and response bodies. |
| application/problem+json | RFC 9457 problem details | A JSON error document with a defined problem contract. |
| application/ld+json | Linked Data JSON | For JSON-LD documents, not a generic API response. |
| application/vnd.api+json | A JSON:API document | Only when the API implements JSON:API. |
| application/vnd.example.order+json | A vendor-specific JSON format | The suffix signals JSON syntax; the vendor contract defines fields. |
Treat the suffix as a parsing signal, not permission to ignore the schema. application/problem+json is JSON, but it describes an error according to RFC 9457. A success parser that assumes a data or items field will still fail on a valid problem document.
Send JSON correctly from curl, Node, and Python
These examples make the body and headers agree. Replace the example URL with an endpoint that accepts JSON. Once a curl request works, use the cURL Converter to create equivalent client code.
curl: show response headers and body
curl -i https://api.example.test/items \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
--data '{"name":"ByteJSON"}'The -i flag matters during debugging. It proves whether the server actually returned JSON, HTML, or a +json problem document. Do not infer a response type from the header you sent in the request.
Node and Express
app.use(express.json());
app.post("/items", (req, res) => {
res.status(201).json({ id: "item_123", name: req.body.name });
});
const response = await fetch("/items", {
method: "POST",
headers: { "Content-Type": "application/json", "Accept": "application/json" },
body: JSON.stringify({ name: "ByteJSON" }),
});In Express, res.json() serializes a value and sets a JSON response type. On the client, JSON.stringify and the request Content-Type are a pair. Setting the header while sending a JavaScript object directly does not create a JSON body.
Python requests
import requests
response = requests.post(
"https://api.example.test/items",
json={"name": "ByteJSON"},
headers={"Accept": "application/json"},
timeout=10,
)
response.raise_for_status()
print(response.headers.get("content-type"))
print(response.json())In requests, json= serializes the value and supplies the JSON content type. data= has different semantics and is appropriate only when you deliberately control the encoded body.
How to fix 415 Unsupported Media Type and parser failures
The header says JSON but the body is not JSON
This happens when a form string, an unstringified JavaScript object, or a template error is sent with application/json. Validate the exact request body with the JSON Validator, then compare it to the server log.
The endpoint expects form data or an upload
A file endpoint often expects multipart/form-data, not JSON. Do not manually set a multipart boundary in browser fetch; the browser sets it for FormData. Conversely, do not use multipart for a regular JSON API just because the body has several fields.
A proxy changes headers
The browser can show the header you intended while the application receives something different after an API gateway or reverse proxy. Compare an end-to-end curl request with headers logged at the application boundary.
response.json() hides an HTML error page
A login redirect or 500 page often returns HTML. Check status and response media type before parsing, especially when a client accepts both normal JSON and problem details.
const response = await fetch("/api/items");
const mediaType = (response.headers.get("content-type") || "")
.split(";", 1)[0].trim().toLowerCase();
if (!response.ok) {
const detail = mediaType === "application/json" || mediaType.endsWith("+json")
? await response.json() : await response.text();
throw new Error("Request failed: " + response.status + " " + JSON.stringify(detail));
}
if (mediaType !== "application/json" && !mediaType.endsWith("+json")) {
throw new Error("Expected JSON, got " + (mediaType || "no Content-Type"));
}
const data = await response.json();A JSON Content-Type debugging checklist
- 1.Inspect raw request and response with devtools or curl -i, including status, headers, and body.
- 2.Confirm the body is valid JSON before checking media types. A correct header cannot repair malformed syntax.
- 3.Match the endpoint contract: JSON, form encoding, and multipart uploads are different formats.
- 4.Compare the media type portion when parameters are allowed, while keeping endpoint-specific allowlists explicit.
- 5.Accept documented +json responses deliberately and parse them according to their specific contract.
- 6.When a response is not JSON, log a bounded text preview and status instead of calling response.json blindly.
The practical rule to remember
Use application/json for regular JSON. Use a more specific +json type only when its contract applies. Inspect response types before parsing, and treat 415 as evidence to compare the exact body and headers at the server boundary.
Frequently asked questions
What is the JSON MIME type?
Use application/json for normal JSON API bodies. Set it as request Content-Type when you send JSON and as response Content-Type when you return JSON.
Is application/problem+json a valid JSON response?
Yes. It is a JSON-based problem-details representation. A generic parser can read the syntax, but application code should handle its documented error fields rather than treating it as a success body.
Do I need Content-Type on every request?
No. It describes a body being sent. A GET request without a body usually needs no request Content-Type. Use Accept to state response formats your client can process.
Why do I get a 415 error?
Check the serialized body, endpoint contract, and header received by the application. Common causes are invalid JSON, a mismatch, a multipart endpoint, or a proxy changing headers.
Try These Tools
MIME Types Reference
Look up Content-Type values and media types while debugging an API response.
Open toolHTTP Status Codes
Check what 400, 406, 415, and 422 responses mean in an HTTP exchange.
Open toolJSON Validator
Validate a request body before blaming a Content-Type mismatch.
Open toolcURL Converter
Turn a working curl request into client code after confirming its headers.
Open toolAuthoritative references
Related tutorials
HTTP API Best Practices
Design response shapes, status handling, and contracts clients can use reliably.
JSON Parse Errors
Fix parsing errors when a server returns HTML or invalid JSON.
URL Decode and Percent-Encoding Errors
Debug encoded request data without confusing it with JSON serialization.
API Integration Examples
Use headers, retries, and error handling in a real API integration.