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.

16 min readHTTP and APIs

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

  1. Content-Type, Accept, and responses
  2. application/json and UTF-8
  3. What +json means
  4. Runnable request examples
  5. 415 and parser failures
  6. Production checklist

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.

HeaderWho sends itMeaning
Content-TypeRequest clientThe format of the body being uploaded.
AcceptRequest clientResponse representations the client can process.
Content-TypeResponse serverThe 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 typeRepresentsWhen to use it
application/jsonAn ordinary JSON representationDefault for most API request and response bodies.
application/problem+jsonRFC 9457 problem detailsA JSON error document with a defined problem contract.
application/ld+jsonLinked Data JSONFor JSON-LD documents, not a generic API response.
application/vnd.api+jsonA JSON:API documentOnly when the API implements JSON:API.
application/vnd.example.order+jsonA vendor-specific JSON formatThe 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. 1.Inspect raw request and response with devtools or curl -i, including status, headers, and body.
  2. 2.Confirm the body is valid JSON before checking media types. A correct header cannot repair malformed syntax.
  3. 3.Match the endpoint contract: JSON, form encoding, and multipart uploads are different formats.
  4. 4.Compare the media type portion when parameters are allowed, while keeping endpoint-specific allowlists explicit.
  5. 5.Accept documented +json responses deliberately and parse them according to their specific contract.
  6. 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.

Authoritative references

Related tutorials

Back to TutorialsWritten by Zhisan, July 2026