Request Headers
Introduction
Whenever a client sends an HTTP request to a server, it sends more than a method, URL, and optional body. It also sends request headers. Request headers are metadata fields that help the server understand how the request should be processed. They can identify the target host, describe the format of the request body, send authentication credentials, state the preferred response format, send session cookies, describe the client application, request compression, control caching, and provide many other instructions.
For API testers, request headers are one of the most important parts of API testing because a request can fail even when the endpoint and payload are correct. A JSON body may be valid, but if the client sends no Content-Type header, the server may reject it or parse it incorrectly. A protected endpoint may exist and work correctly, but without a valid Authorization header the server should return 401 Unauthorized. A content-negotiated API may return a different format depending on the Accept header. A caching test may depend completely on conditional headers such as If-None-Match or If-Modified-Since.
Request headers make HTTP communication explicit. They prevent the server from guessing what the client means. They also make APIs more secure, predictable, testable, and interoperable. This tutorial explains request headers from a practical API testing point of view, including common headers such as Host, Authorization, Content-Type, Accept, User-Agent, Accept-Language, Accept-Encoding, Cookie, Cache-Control, If-None-Match, and If-Modified-Since.
What Are Request Headers?
Request headers are key-value pairs sent by the client along with an HTTP request. They are placed after the request line and before the blank line that separates headers from the request body. Each header has a name and a value. For example, Content-Type: application/json tells the server that the request body is JSON. Authorization: Bearer abc123 sends a bearer token. Accept: application/json tells the server that the client prefers a JSON response.
A simple definition is this: request headers are key-value pairs sent by the client to provide additional information about the HTTP request. They explain who is sending the request, what is being sent, what is expected in response, how the request should be authenticated, how the request should be cached, and how the server should handle the communication.
Request headers are not the same as response headers. Request headers go from client to server. Response headers go from server to client. Request headers describe the request. Response headers describe the response. This distinction matters in test design because testers must know which side is responsible for each header. For example, the client sends Authorization, while the server may send Set-Cookie. The client sends Accept, while the server sends Content-Type in the response.
Request Structure
An HTTP request has a predictable structure. It starts with the request line. The request line includes the HTTP method, request path, and HTTP version. After that come the request headers. Then there is a blank line. After the blank line, an optional request body may appear. Body data is common for methods such as POST, PUT, and PATCH, but GET requests usually do not contain a body in ordinary API design.
A complete request may look like this:
POST /login HTTP/1.1
Host: api.example.com
Authorization: Bearer abc123
Content-Type: application/json
Accept: application/json
{
"username": "john",
"password": "password123"
}
In this request, POST /login HTTP/1.1 is the request line. Host, Authorization, Content-Type, and Accept are request headers. The blank line separates the headers from the JSON body. The server uses these headers to identify the target application, authenticate the request, parse the JSON body, and decide which response format to send.
When troubleshooting an API request, testers should inspect this complete structure. A failure can occur because the method is wrong, the URL is wrong, the header is missing, the header value is malformed, the body is invalid, or the relationship between header and body is inconsistent. For example, sending JSON data with Content-Type: text/plain is a header-body mismatch that may produce 415 Unsupported Media Type or 400 Bad Request.
Why Request Headers Are Important
Request headers are important because they allow the client to communicate intent. The server may host many websites or APIs, so the Host header helps identify which application should receive the request. The server may accept multiple request-body formats, so Content-Type tells it how to parse the body. The server may support multiple response formats, so Accept tells it what the client prefers. The server may protect endpoints, so Authorization or Cookie tells it who the user is.
Headers also support localization and performance. Accept-Language tells the server which language the client prefers. Accept-Encoding tells the server which compression methods the client can handle. Conditional headers such as If-None-Match and If-Modified-Since help the server avoid sending unchanged content. These features make APIs faster and more user-friendly when implemented correctly.
Security also depends on headers. Authentication tokens, API keys, session cookies, tenant identifiers, idempotency keys, and request signatures are commonly sent through request headers. If these values are missing, invalid, leaked, or sent to the wrong service, the API can fail or become insecure. Request-header validation is therefore part of both functional testing and security testing.
Without request headers, many APIs could not function correctly. They would not know how to authenticate users, parse bodies, negotiate response formats, validate cache state, handle languages, compress responses, route requests, or maintain sessions. Headers are the control layer around the request body.
Common Request Headers
The most common request headers in API testing include Host, Authorization, Content-Type, Accept, User-Agent, Accept-Language, Accept-Encoding, Cookie, Cache-Control, If-None-Match, and If-Modified-Since. Some APIs also use custom headers such as X-API-Key, X-Tenant-Id, X-Correlation-Id, Idempotency-Key, or request-signature headers.
Not every request needs every header. A public GET request may need only basic routing and response-format headers. A protected POST request may need authorization, content type, accept format, idempotency, and correlation headers. A file upload may need multipart content type and size-related behavior. A cached resource request may need conditional headers. The correct set depends on the endpoint's purpose.
In test automation, headers are often configured globally in a request specification, base client, API helper, or framework utility. This avoids duplication, but it also requires care. If a global header is wrong, every test can fail for the same reason. If a test needs to verify a missing header, the test must intentionally override or remove the default header.
Host Header
The Host header identifies the server or virtual host that should process the request. It is especially important because multiple websites or APIs can run on the same server, IP address, load balancer, or reverse proxy. The Host header tells the infrastructure which application or route should receive the request.
A simple example is:
Host: api.example.com
In modern API environments, the Host header may be used by API gateways, ingress controllers, reverse proxies, web servers, and routing layers. If the Host header is wrong, the request may reach the wrong application, fail routing, return a default page, or produce a security error.
API testers rarely set the Host header manually in high-level tools because the client usually derives it from the URL. However, testers should understand it when debugging gateway routing, virtual-host issues, reverse proxy problems, environment mix-ups, and domain-related defects. For example, if a QA request accidentally points to a production host, the Host header and base URL can reveal the mistake quickly.
Authorization Header
The Authorization header carries authentication credentials. It allows the server to identify or validate the client. Common examples include bearer tokens, Basic authentication, API keys through custom headers, OAuth 2.0 access tokens, and signed authorization schemes.
A bearer token example looks like this:
Authorization: Bearer eyJhbGc...
A Basic authentication example looks like this:
Authorization: Basic dXNlcjpwYXNz
Some APIs use API keys in custom headers:
X-API-Key: ABC123XYZ
Testing authorization headers is essential. A protected API should reject missing credentials with 401 Unauthorized. It should reject expired, malformed, revoked, or invalid credentials. If the token is valid but the user lacks permission, the response should usually be 403 Forbidden. The exact behavior should match the API contract.
Authorization headers are sensitive. Test reports, logs, screenshots, downloadable files, CI output, and browser consoles should not expose real tokens. Automation frameworks should mask or avoid printing them. APIs should require HTTPS so credentials are protected in transit.
Content-Type Header
The Content-Type header specifies the format of the request body. It tells the server how to parse the data being sent. If the request body is JSON, the client should send Content-Type: application/json. If the request body is XML, it may send Content-Type: application/xml. For file uploads, the request may use multipart/form-data. For plain text, it may use text/plain.
For example:
POST /users
Content-Type: application/json
{
"name": "John"
}
Without the correct Content-Type, the server may reject the request, parse it incorrectly, or treat the body as an unsupported media type. In many APIs, sending JSON with Content-Type: text/plain should produce 415 Unsupported Media Type or 400 Bad Request, depending on the contract.
Testing Content-Type should include correct content type, missing content type, unsupported content type, mismatched body and content type, and boundary handling for multipart requests. A request without a body usually should not require Content-Type, but a request with a body usually should be explicit.
Accept Header
The Accept header tells the server which response format the client prefers. It is part of content negotiation. A client may request JSON with Accept: application/json, XML with Accept: application/xml, or HTML with Accept: text/html. The server can use that preference to decide which representation to return.
A simple flow looks like this:
Accept: application/json
The server returns:
{
"id": 101
}
If the API supports only JSON and the client requests XML, the server may return 406 Not Acceptable. Some APIs ignore unsupported Accept values and always return JSON. Either approach can be valid if it is documented, but the behavior should be consistent.
Content-Type and Accept are commonly confused. Content-Type describes what the client is sending. Accept describes what the client wants back. A POST request can send JSON and request JSON at the same time, but the two headers still have different meanings. Testers should validate both when they affect behavior.
User-Agent Header
The User-Agent header identifies the client application making the request. Browser requests often include long User-Agent strings that describe the browser and platform. API tools may send values such as PostmanRuntime/7.39. SDKs, mobile apps, command-line tools, and automated test frameworks may send their own client identifiers.
Examples include:
User-Agent: PostmanRuntime/7.39
User-Agent: Mozilla/5.0
Servers may use User-Agent for analytics, logging, debugging, compatibility handling, traffic filtering, or abuse detection. API teams may ask external consumers to send an identifiable User-Agent so support teams can trace client behavior.
Testing User-Agent is usually not central to business functionality, but it can matter when the API has client-specific behavior. If different mobile app versions receive different responses, or if a gateway blocks unknown clients, tests should include User-Agent validation. At minimum, automation should use a stable User-Agent when it helps logs and observability.
Accept-Language Header
The Accept-Language header specifies the client's preferred language or locale. A client may send Accept-Language: en-US or Accept-Language: fr-FR. The server may use this value to localize messages, labels, descriptions, currency formats, dates, or content.
For example:
Accept-Language: en-US
Localized APIs need careful testing because language affects user-facing content. If a validation error is expected in English, the same request with a French language header may return a French message. Tests should avoid brittle assertions on full localized text unless the test is specifically validating localization. It may be better to validate stable error codes and separately validate translations.
Test fallback behavior too. What happens when the client requests an unsupported language? Does the server return a default language, use the nearest supported locale, or return an error? The expected behavior should be defined by the product or API contract.
Accept-Encoding Header
The Accept-Encoding header tells the server which compression algorithms the client can handle. Common values include gzip and br. If the client sends Accept-Encoding: gzip, the server may compress the response using gzip and return Content-Encoding: gzip in the response.
Compression can significantly improve performance for large JSON responses, reports, and text-heavy resources. It reduces bandwidth and often improves perceived speed. However, it must be implemented correctly. If the server says a response is compressed but sends an uncompressed body, the client may fail to decode it. If a client asks for compression but cannot actually decode it, tests may fail for client-side reasons.
API testers should validate compressed and uncompressed responses where performance matters. Confirm that the response body is readable after decompression, the content matches the uncompressed version, and headers accurately describe the encoding. Also confirm that small responses are not compressed unnecessarily if the platform has such optimization rules.
Cookie Header
The Cookie header sends stored cookie values from the client to the server. Cookies are common in browser-based applications, session-based authentication, shopping carts, preferences, tracking consent, and CSRF protection. The server creates or updates cookies using response headers such as Set-Cookie, and the client sends them back using the request Cookie header.
An example request header is:
Cookie: sessionId=ABC123
For API testing, cookies matter when the application uses session-based authentication instead of pure bearer-token APIs. A login request may return a session cookie. Future requests must include that cookie to remain authenticated. A logout request should invalidate the session and usually expire the cookie.
Testing should cover missing cookies, expired cookies, tampered cookies, logout behavior, session renewal, and secure cookie attributes in the corresponding Set-Cookie response. If a cookie is missing or invalid, protected APIs should reject the request appropriately.
Cache-Control Header
The request Cache-Control header allows the client to specify caching behavior. For example, Cache-Control: no-cache asks caches to revalidate before using a stored response. Cache-Control: no-store indicates that the response should not be stored. Cache-Control: max-age=3600 can indicate acceptable freshness in some contexts.
Request cache directives are useful when clients want fresh data or when testing caching behavior. They work alongside response headers such as Cache-Control, ETag, and Last-Modified. In browser and CDN environments, caching behavior may involve several layers, including the browser cache, proxy cache, CDN edge, gateway, and origin server.
API testers should validate caching only for endpoints where caching is part of the requirement. Private account data should not be cached publicly. Public static resources can often be cached aggressively. Dynamic data may require revalidation. Request headers help drive those scenarios.
If-Modified-Since Header
If-Modified-Since is a conditional request header used for cache validation. The client sends a timestamp from a previous response, usually based on the server's Last-Modified response header. If the resource has not changed since that time, the server may return 304 Not Modified. If it has changed, the server returns the latest representation, usually with 200 OK.
Example:
If-Modified-Since: Tue, 30 Jun 2026 10:00:00 GMT
Testing this header requires at least two requests. First, retrieve the resource and capture the Last-Modified value. Second, send a conditional request using that value. If the resource is unchanged, verify the expected 304 response and absence of full body. Then change the resource and repeat the conditional request to verify that the server returns updated content.
This is useful for static files, documents, product catalogs, and other resources where re-downloading unchanged content would waste bandwidth. It is less suitable for sensitive or rapidly changing user-specific data unless the caching strategy is carefully designed.
If-None-Match Header
If-None-Match works with the ETag response header. An ETag is a resource version identifier. The client stores the ETag from a previous response and sends it back using If-None-Match. If the current resource version matches the ETag, the server may return 304 Not Modified. If it does not match, the server returns the updated resource.
Example:
If-None-Match: "abc123"
ETag-based caching is often more precise than timestamp-based caching because it represents resource version rather than modification time alone. It can also support concurrency behavior when paired with related headers such as If-Match.
Testing If-None-Match involves capturing ETag, sending conditional requests, verifying 304 for unchanged resources, verifying 200 for changed resources, and checking that the ETag value changes when the resource changes. If an API returns the same ETag for changed content, clients may incorrectly keep stale data.
Custom Request Headers
Many real APIs use custom request headers. Common examples include X-API-Key, X-Tenant-Id, X-Correlation-Id, X-Request-Id, Idempotency-Key, X-Client-Version, and request-signature headers. These headers are not always standard HTTP headers, but they are still part of the API contract when a system requires them.
A tenant header may tell the server which customer organization the request belongs to. A correlation ID may help trace a request across services. An idempotency key may prevent duplicate processing if the client retries a payment or order request. A client version header may allow the server to support compatibility behavior for older app versions.
Testing custom headers requires careful contract reading. Verify missing header behavior, invalid values, unauthorized tenant access, duplicate idempotency keys, replay attempts, correlation propagation, and version-specific behavior. Custom headers are powerful, but they can create serious defects if they are trusted without validation.
Complete Request Example
A complete request to create a user might look like this:
POST /users HTTP/1.1
Host: api.example.com
Authorization: Bearer abc123
Content-Type: application/json
Accept: application/json
User-Agent: PostmanRuntime/7.39
Accept-Language: en-US
Accept-Encoding: gzip
X-Correlation-Id: req-789
{
"name": "John"
}
Each header has a purpose. Host routes the request. Authorization authenticates the client. Content-Type tells the server how to parse the body. Accept requests JSON. User-Agent identifies the client. Accept-Language requests English content. Accept-Encoding allows compressed responses. X-Correlation-Id helps trace the request through logs.
In API testing, a complete request example is useful because it shows that headers work together. Removing one header may produce a different error. Changing one value may alter the response. A strong API test suite validates both the normal header set and important missing or invalid header scenarios.
Request Headers in REST APIs
Most REST APIs commonly use Authorization for authentication, Content-Type for request body format, Accept for expected response format, Host for destination routing, and User-Agent for client identification. APIs that support caching use conditional request headers. Browser-connected APIs may use cookies and CSRF headers. Distributed systems often use correlation IDs and tenant headers.
REST APIs should keep header usage consistent. If one POST endpoint requires Content-Type and another similar endpoint does not, clients become confused. If one service uses X-Request-Id and another uses X-Correlation-Id for the same purpose, tracing becomes harder. Platform-level standards improve both development and testing.
Documentation should list mandatory headers, optional headers, default behavior, error responses for missing headers, supported media types, authentication schemes, and caching rules. Testers should compare the implementation with the documentation and report differences clearly.
Request Headers in API Testing
API testers should validate request headers in several categories. Authentication testing checks whether the Authorization header is present, valid, expired, invalid, malformed, revoked, or insufficient for the requested operation. Missing or invalid authentication should usually return 401. Valid authentication without permission should usually return 403.
Content-Type testing verifies correct formats such as JSON, XML, multipart form data, or plain text. It also verifies missing Content-Type, unsupported Content-Type, and mismatch between declared format and actual body. Accept testing verifies correct response format, unsupported formats, and content negotiation behavior.
Language testing verifies localized responses and fallback behavior. Compression testing verifies compressed responses when requested and readable responses after decompression. Cookie testing verifies session handling, login state, logout, expired sessions, and tampered cookie behavior. Cache testing verifies conditional requests and 304 responses where applicable.
For automation, create reusable request specifications or helper methods, but do not hide important test intent. A test for missing Authorization should clearly remove the Authorization header. A test for wrong Content-Type should intentionally set the wrong value. The test name and assertion should explain the header behavior being validated.
Real-World Example
Suppose a user logs into an e-commerce application. The browser or mobile app sends a login request. The request includes Host to identify the website, Content-Type: application/json to explain the body format, Accept: application/json to request a JSON response, and a User-Agent that identifies the client. If the user already has a session or CSRF token, the request may also include cookies or security headers.
After login, future requests include authentication information. In a token-based API, the client sends Authorization: Bearer abc123. In a session-based application, the client sends Cookie: sessionId=ABC123. The server uses these headers to identify the user, check permissions, and return the correct account data.
If the user views order history, the client may request JSON, send language preferences, and accept compression. If the data has not changed and caching is supported, conditional headers may reduce unnecessary downloads. This single real-world flow shows how request headers support routing, authentication, parsing, response formatting, localization, compression, sessions, and caching.
Common Mistakes
A common mistake is sending JSON without Content-Type: application/json. The body may look correct to a human, but the server relies on headers to parse it reliably. Missing Content-Type can cause rejection or incorrect parsing.
Another mistake is missing Authorization for protected APIs. A secure API should not process protected operations without credentials. Missing, expired, or invalid authentication should be tested deliberately and should return the expected client error response.
A third mistake is using the wrong Accept header. If the API supports only JSON and the client requests XML, the result may be 406 Not Acceptable or a documented default JSON response. Testers should know which behavior the contract expects.
Another mistake is sending a body that does not match the declared Content-Type. For example, sending JSON while declaring Content-Type: text/plain can produce parsing defects. Similarly, multipart uploads must include correct multipart boundaries generated by the client.
Teams also sometimes put sensitive information in custom headers without protecting logs. API keys, user secrets, tokens, and personally identifiable values should not be exposed in test output, analytics, or error reports.
Best Practices
Always send the correct Content-Type when a request body is present. Include authentication headers for protected APIs. Specify the expected response format using Accept when the API supports content negotiation. Use HTTPS so sensitive headers are protected during transmission.
Keep header names and usage consistent across APIs. Use shared API client utilities or request specifications for common headers, but allow tests to override headers for negative scenarios. Document all mandatory and optional headers in the API specification.
Protect sensitive headers. Do not expose Authorization tokens, API keys, session cookies, or request signatures in logs or reports. Mask them in automation output. Be careful with redirects, because some clients may forward headers to redirected destinations if not configured safely.
Validate mandatory headers in automated tests. Header defects are often easy to automate and stable to run. Include tests for missing, invalid, unsupported, and mismatched headers. This improves confidence in authentication, content negotiation, parsing, caching, localization, compression, and session behavior.
Interview-Ready Explanation
Request headers are key-value pairs sent by the client along with an HTTP request to provide metadata about the request. They help the server understand how to process the request by specifying details such as the destination server, authentication credentials, request body format, expected response format, client information, preferred language, compression support, caching instructions, and session information.
Common request headers include Host, which identifies the target server; Authorization, which carries credentials; Content-Type, which describes the request body format; Accept, which describes the desired response format; User-Agent, which identifies the client; Accept-Language, which requests a preferred language; Accept-Encoding, which requests compression; Cookie, which sends session data; and conditional headers such as If-None-Match and If-Modified-Since, which support caching.
In API testing, request headers are essential because incorrect or missing headers can cause authentication failures, unsupported media type errors, parsing failures, incorrect response formats, broken sessions, or caching defects. A good tester validates both positive and negative header scenarios.
Key Takeaway
Request headers are the client-side metadata of an HTTP request. They tell the server who is calling, what is being sent, what response is expected, which session applies, what language is preferred, whether compression is supported, and whether cached data can be reused. They are not optional decoration; they are part of the API contract.
For API testers, the practical rule is simple: validate headers whenever they affect request behavior. Check required headers, missing headers, invalid values, unsupported formats, sensitive data handling, and consistency across endpoints. Strong request-header testing helps catch defects early and makes APIs more secure, predictable, and reliable.