Developer Tools

Content-Type & Accept Headers: How Browsers and APIs Negotiate Response Formats

The same API endpoint can return JSON, XML, or HTML depending on one request header. Here is how Accept and Content-Type headers negotiate response format, and what a 406 actually means.

September 26, 2026 6 min read Toolio Editorial
Content-Type & Accept Headers: How Browsers and APIs Negotiate Response Formats
Summarize with:
Share:

The same API endpoint, hit with the exact same URL, can return a JSON object, an XML document, or a fully rendered HTML page — and which one you get is decided entirely by a single request header you set before the request even reaches the server. This mechanism, content negotiation, is one of HTTP's oldest and most underused features, and understanding it explains a category of bugs that look mysterious until you check the headers.

Content negotiation lets a single URL serve different representations of the same underlying resource, and it works through a simple but easily-confused pair of headers — one that the client sends to state what it wants, and one that the server sends back to state what it actually gave.

Direct Answer: The Accept header is sent by the client to tell the server which response formats it can handle, listed as MIME types with optional quality values indicating preference order (e.g., Accept: application/json, text/html;q=0.8 says "prefer JSON, but HTML is acceptable too"). The Content-Type header is sent by the server in its response to state what format the response body is actually in. These are not the same header serving two purposes — they are two distinct headers on two different sides of the exchange, and confusing them is a common source of integration bugs. When a server cannot produce any format the client's Accept header says it can handle, the correct response is 406 Not Acceptable, though in practice many APIs instead just fall back to a default format rather than strictly enforcing this.


1. How the Client States What It Wants

The Accept request header lists acceptable MIME types, optionally with a q (quality) value from 0 to 1 indicating relative preference — no q value means an implicit preference of 1 (highest).

GET /users/482 HTTP/1.1
Host: api.example.com
Accept: application/json, application/xml;q=0.9, text/html;q=0.5

This tells the server: "I most prefer JSON; XML is fine if JSON isn't available; HTML is acceptable as a last resort." A well-behaved server picks the highest-preference format from that list that it's actually capable of producing.


2. How the Server States What It Sent

The Content-Type response header states, unambiguously, what format the body actually is — this is what the receiving client should trust and parse against, not assume based on what it originally requested.

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{"id": 482, "name": "Jane Doe", "role": "admin"}

A common and confusing bug happens when a client sends a body in a request (say, a POST) and also needs to specify what format that body is in — this is a separate use of Content-Type, this time on the request side, describing the request body rather than negotiating the response:

POST /users HTTP/1.1
Content-Type: application/json
Accept: application/json

{"name": "New User"}

Here, Content-Type describes the format of the JSON being sent in this request, while Accept separately states what format the client wants the response to be in — the two headers can specify different formats entirely, and mixing up which one governs which direction is a frequent source of confusion.


3. The Header Roles at a Glance

Header Sent by Describes Example
Accept Client (in the request) What response formats the client can handle, in preference order Accept: application/json
Content-Type (on a request) Client (in the request) What format the request body itself is in Content-Type: application/json
Content-Type (on a response) Server (in the response) What format the response body actually is Content-Type: application/xml
406 Not Acceptable Server (as a response status) None of the client's acceptable formats can be produced HTTP/1.1 406 Not Acceptable

4. A Worked Example: One Endpoint, Three Formats

Consider a single endpoint GET /reports/quarterly that supports content negotiation across three formats:

Request 1:
GET /reports/quarterly HTTP/1.1
Accept: application/json
→ Response Content-Type: application/json
→ Body: {"quarter": "Q2", "revenue": 482000}

Request 2:
GET /reports/quarterly HTTP/1.1
Accept: application/xml
→ Response Content-Type: application/xml
→ Body: <report><quarter>Q2</quarter><revenue>482000</revenue></report>

Request 3:
GET /reports/quarterly HTTP/1.1
Accept: text/html
→ Response Content-Type: text/html
→ Body: <html>...a rendered report page...</html>

Same URL, same underlying data, three completely different representations — decided purely by what the client asked for in Accept. This is exactly how many public APIs support both a JSON API and a human-browsable HTML view from identical URL paths.


5. What Happens on a Mismatch: 406 Not Acceptable

If a client's Accept header lists only formats the server genuinely cannot produce for that resource, the technically correct response is:

HTTP/1.1 406 Not Acceptable
Content-Type: application/json

{"error": "Cannot produce a response matching the requested Accept header"}

In practice, 406 is relatively rare in the wild — many real-world APIs choose to be lenient and fall back to a sensible default format (often JSON) rather than strictly rejecting the request, treating strict enforcement as more likely to break integrations than help them. Still, encountering an actual 406 is a strong, specific signal to check exactly what your Accept header contains versus what the endpoint can actually produce.

You can inspect exactly what headers a request is sending and receiving using an HTTP header analyzer, and test how a specific endpoint responds to different Accept values directly with an API tester — invaluable for debugging a content-negotiation mismatch without needing to write a test script.


Frequently Asked Questions

What's the difference between Accept and Content-Type?

Accept is a request header stating what response formats the client can handle; Content-Type states what format a specific body (either the request body or the response body) actually is — they answer different questions and can specify different formats within the same exchange.

What does a 406 status code mean?

It means the server cannot produce a response in any of the formats listed in the client's Accept header — though in practice many APIs fall back to a default format instead of strictly returning 406.

If I don't send an Accept header, what happens?

Most servers treat a missing Accept header as "any format is acceptable" and return their default representation — commonly JSON for APIs — rather than rejecting the request.

Can Content-Type include more than just the format?

Yes — it commonly includes a charset parameter, like Content-Type: application/json; charset=utf-8, specifying the character encoding of the body alongside the MIME type itself.

Why would an API return HTML and JSON from the same URL?

This is a deliberate content-negotiation design choice, letting a browser navigating directly to the URL see a readable HTML page while a program calling the same URL with Accept: application/json gets a machine-parseable response — without needing two separate endpoints.


References: RFC 9110 (HTTP Semantics — Accept, Content-Type, and 406 Not Acceptable), RFC 2046 (MIME media types).

Free Calculator

Put this guide into action

Stop guessing — use our JSON Formatter to run real numbers, compare scenarios, and get instant results you can trust.

Use Free JSON Formatter
Toolio Editorial

Toolio Editorial Senior Technical Editors & UX Content Engineers

Digital Utilities, Web Engineering & Tool Guides

The Toolio Editorial Board is dedicated to delivering clear, transparent, and accurate technical guides across digital utilities, developer tools, unit conversion standards, date-time algorithms, and decision science. The board maintains rigorous editorial standards, factual accuracy, and step-by-step clarity for every guide published.

Try Calculator JSON Formatter
Use JSON Formatter

Continue Reading