Different clients may need the same information in different formats. For example, a bookstore's mobile app might want book details as JSON, while a partner needs them as CSV. Both can request the same resource, but the server needs to know which representation each client can use and label the response accurately.
Headers carry that information.
This chapter explains how header fields describe messages, how media types identify content, and how clients and servers negotiate representations without confusing request input with response output.
A header field supplies named metadata about a request, response, or its content. Different fields serve different purposes: Authorization supplies credentials, Content-Type describes content, and Accept can express a client's response preferences.
In HTTP/1.1, a field appears as a name, a colon, and a value. For example, Content-Type: application/json identifies JSON content. Field names are case-insensitive, so content-type names the same field. Values follow field-specific rules; do not lowercase credentials or other arbitrary values.
Do not assume you can merge every repeated header into a comma-separated string. List-valued fields such as Accept support lists, but fields such as Set-Cookie have different rules. Use the HTTP library's header interfaces rather than treating headers as a dictionary where every field follows the same rules.
Prefer standard fields when they already express the required meaning. If an API introduces custom metadata, document its name, value format, and behavior when absent. Clients cannot infer a custom field's semantics from a plausible-looking name.
Header values also cross a trust boundary. A caller-supplied role or user identifier is not proof of identity. The bookstore must validate credentials and permissions regardless of which format a client requests.
A media type, or MIME type, identifies a content format. Its basic structure is type/subtype, with optional parameters afterward. In text/csv; charset=utf-8, text is the type, csv is the subtype, and charset is a parameter describing character encoding.
Common formats serve different API needs:
The label describes the content; it does not transform it. Labeling a JSON object as text/csv does not produce a CSV file. A server must serialize the selected representation into the format it advertises.
Parameters have meanings the media type defines. JSON that systems exchange outside a closed ecosystem must use UTF-8. The application/json registration defines no charset parameter, so Content-Type: application/json is sufficient for ordinary JSON APIs. There is no need to invent a character-encoding negotiation scheme for JSON.
For multipart/form-data, the boundary parameter identifies the delimiter separating parts. A client library generating a multipart body should also generate the matching content type. Manually setting only Content-Type: multipart/form-data can leave out the boundary the receiver needs to parse the upload.
A structured suffix adds information about a specialized format. For example, application/merge-patch+json uses JSON syntax with merge-patch semantics. The +json suffix does not mean every JSON document is a valid merge patch for the target, or that every API supporting application/json supports this specialized media type. JSON syntax and the application contract are separate checks.
Content-Type describes the content in the message carrying it. In a request, it describes what the client sends. In a response, it describes what the server sends back.
The request's Accept field expresses acceptable response media types. It neither labels the request body nor requires the request and response to use the same format.
This diagram shows the two directions for an order submission:
The server must understand the incoming content and choose an appropriate outgoing representation. Those decisions can succeed or fail independently.
For example, the bookstore accepts JSON orders at https://api.bookstore.example/orders. A valid request can include both Content-Type: application/json and Accept: application/json, but the matching values are a choice, not a protocol requirement. An API could accept an uploaded image and return JSON metadata about it.
For requests with content, the bookstore requires a supported Content-Type. If it is missing, this API rejects the request according to its documented input policy rather than guessing from the first character. This is an API policy; HTTP does not universally require every message to carry that field.
Content negotiation is the selection of a representation suitable for a request. In server-driven negotiation, the client sends preferences and the server selects among representations it can produce. Accept handles media-type preferences.
An illustrative request header is:
The q parameter is a preference weight from 0 to 1, with at most three decimal places. Its default is 1, and 0 means not acceptable. This client prefers CSV but accepts JSON at a lower weight. These values are relative preferences, not percentages or probabilities.
Media ranges can match a single type, a group such as text/*, or any media type through */*. A more specific matching range determines the quality for a particular representation. For example:
These preferences explicitly exclude JSON. The broader application wildcard does not make JSON acceptable again. A parser that simply picks the largest number from any matching entry gets this case wrong. The standard wildcard forms also do not define application/*+json as a suffix-matching shortcut.
The bookstore selects a format as follows:
This API documents JSON as the default when Accept is absent and as the tie-breaker between equally preferred supported formats. An absent Accept imposes no media-type preference; it does not universally mean JSON. Asking for an unsupported format does not make the server capable of generating it.
The diagram describes a policy that honors the client's acceptable formats and rejects a request when none is available. HTTP also permits a server to disregard Accept instead of rejecting the request. A predictable API should document its behavior, and clients should inspect the actual response Content-Type.
Assume the public endpoint https://api.bookstore.example/books/book_1042/details supports JSON and CSV representations of the same bibliographic data. It requires no credentials, returns no personalized information, and uses JSON as its default.
The app requests JSON:
The service returns:
A partner instead requests CSV with JSON as a fallback:
Since the server supports CSV and the client prefers it, the response is:
These are HTTP/1.1 messages the client and server send over HTTPS. JSON bodies in this chapter have no trailing newline. The CSV body uses one CRLF line ending between its header row and data row, with no trailing line ending, giving 60 bytes. Its columns and their ordering are part of this bookstore's CSV contract.
The resource remains the same book detail resource. Negotiation changes its representation, not the book's identity. Both formats describe the same identifier, title, and author.
415 Unsupported Media Type concerns the request content. 406 Not Acceptable concerns the available response representations under the server's negotiation policy.
Consider an intentionally mislabeled order submission. Assume the caller has a valid identity and permission to create orders, but the client declares plain text even though it sends JSON-shaped data:
EXAMPLE_TOKEN is a nonfunctional placeholder. The order endpoint accepts JSON input, so it rejects this declared format:
The correction is to send this JSON body with Content-Type: application/json. Changing Accept would not fix how the client labels the input. The error itself can be JSON because the client accepts JSON responses.
Now a caller asks the public book-detail endpoint for PDF only:
The endpoint supports only JSON and CSV. Under its documented rejection policy, it returns:
This API uses an empty body for that negotiation failure, avoiding an error document in a format the caller excluded. Its documentation lists supported formats. Another API can document a different error representation policy.
Format rejection is also distinct from data validation. If the order has Content-Type: application/json but contains malformed JSON, this bookstore returns 400 Bad Request. If the JSON is valid but quantity is zero, it returns 422 Unprocessable Content. A valid format and value still do not grant order-creation permission; an identified account without that permission receives 403 Forbidden under this API's authorization policy.
Negotiation can select more than the media type. Accept-Encoding describes acceptable content codings, such as gzip compression. If the server compresses JSON with gzip, the response retains Content-Type: application/json and adds Content-Encoding: gzip.
Compression changes the transmitted bytes, not the underlying JSON format. The receiver removes the content coding before interpreting the JSON. Many HTTP libraries do that automatically. If a compressed response includes Content-Length, it describes the compressed content length, not the uncompressed JSON length.
For example, Accept-Encoding: gzip allows gzip but does not require the server to compress every response. Unencoded content (identity in negotiation) remains acceptable unless the client excludes it. The server may send a small response without compression. Do not label readable JSON as gzip unless the content actually has that encoding.
Accept-Language expresses language preferences. A request carrying Accept-Language: fr, en;q=0.8 prefers French and accepts English as a fallback. A service selecting a French-language description can indicate its intended audience with Content-Language: fr.
Language selection should have documented fallbacks. It does not determine the caller's country, currency, time zone, or access rights. In the bookstore, choosing a French description must not silently change a price's currency or the stable identifiers in the response. The bibliographic JSON/CSV example does not vary by language; this is a separate capability an endpoint could support.
The animation below shows how request headers help a client and server choose a response format.
When response selection depends on request headers, a cache must account for those headers before reusing a stored response. Vary identifies the relevant request field names.
The book-detail responses include Vary: Accept because one URL can produce JSON or CSV. The following diagram shows the distinction a cache must preserve:
Without appropriate variation handling, a cache could incorrectly reuse the partner’s stored response for the JSON-only app. Vary: Content-Type would not express this selection rule: the controlling request field is Accept, while the response's Content-Type reports the chosen format.
If an endpoint also varies by compression and language, its selection metadata can include Vary: Accept, Accept-Encoding, Accept-Language. Send consistent variation information across that endpoint's variants, including its default response, so caches can identify the selection dimensions.
Vary does not make a response cacheable or establish how long it remains fresh. It also does not authorize sharing private data. It only contributes to deciding whether a stored representation matches a later request. Add the fields that actually affect selection; unnecessary variation splits requests across more cache entries and reduces reuse.
Headers describe messages and guide their handling. Media types identify content formats, while request preferences let a server select among supported representations. Content-Type labels actual content; request Accept describes acceptable output.
Keep input validation separate from output negotiation, distinguish format from compression and language, and use Vary when header-based selection affects reusable responses. Document defaults and rejection behavior so clients can predict which representation they will receive and handle it correctly.