Anatomy of an HTTP request
Method, path, query string, headers and body: what each part means and how to read it when debugging.
8 min read · Updated 24 October 2026
Every HTTP request has the same four parts: a method, a target (path plus optional query string), a set of headers, and an optional body. Once you can read those four parts confidently, most integration bugs become visible within seconds of looking at a captured request.
PATCH /v1/customers/42?expand=address&dry_run=true HTTP/1.1
Host: api.example.com
Authorization: Bearer sk_test_…
Content-Type: application/json
Accept: application/json
Content-Length: 32
{"email":"ada@example.com"}The method
The method says what the client wants to do. Two properties defined by the HTTP specification matter in practice. A safe method does not change anything on the server. An idempotent method has the same effect whether it is sent once or several times, which matters whenever a request might be retried.
| Method | Typical use | Safe | Idempotent |
|---|---|---|---|
| GET | Read a resource | Yes | Yes |
| HEAD | Same as GET, but headers only | Yes | Yes |
| OPTIONS | Ask what is allowed; used for CORS preflight | Yes | Yes |
| POST | Create something or trigger processing | No | No |
| PUT | Replace a resource entirely | No | Yes |
| PATCH | Change part of a resource | No | Not necessarily |
| DELETE | Remove a resource | No | Yes |
Webhooks are almost always POST, which is not idempotent by definition. That is why webhook receivers need their own duplicate detection based on event IDs.
The path and the query string
The path identifies the resource: /v1/customers/42. Everything after the first ? is the query string, a list of name=value pairs separated by &. A few details regularly cause confusion:
- Encoding. Characters with special meaning must be percent-encoded. A space can appear as
%20, and in form-style query strings also as+. An ampersand inside a value must be%26, otherwise it splits the value in two. - Repeated keys.
?tag=a&tag=bis valid and means two values. Frameworks disagree on how to expose this: some give you the first value, some the last, some an array. An inspector shows you the raw string so you can see what was actually sent. - Empty values.
?debugand?debug=are different strings, and code that checks for a non-empty value treats them differently. - Secrets in URLs. Query strings end up in server logs, proxy logs and browser history. Never put API keys or tokens there if you can use a header instead.
Headers
Headers carry metadata about the request. Names are case-insensitive: Content-Type and content-type are the same header. HTTP/2 and HTTP/3 send all names in lowercase, and many tools, Tapwire included, display them that way.
| Header | What it tells you |
|---|---|
Content-Type | How to interpret the body, for example JSON, a form, or binary data |
Content-Length | Body size in bytes, when known in advance |
Authorization | Credentials, such as a bearer token or basic auth |
User-Agent | Which client or provider sent the request; useful for filtering |
Accept | Which response formats the client can handle |
Idempotency-Key | A client-chosen key some APIs use to make retries of POST safe |
Providers also add their own headers, commonly prefixed with their name, for the event type, a delivery ID and a signature. Those are usually the headers your code needs most.
The body
The body is a sequence of bytes. The Content-Type header tells the receiver how to decode it, and a mismatch between the two is one of the most common integration bugs. The formats you will meet most often:
application/json: structured data. See working with JSON payloads.application/x-www-form-urlencoded: the samename=value&…format as a query string, used by HTML forms and some older webhook providers.multipart/form-data: several parts separated by a boundary string declared in the header, used for file uploads.text/plainorapplication/octet-stream: raw text or raw bytes with no further structure.
GET and HEAD requests normally have no body. Some clients send one anyway, and many servers ignore it, so do not design an API that depends on it.
What an inspector can and cannot show
A request inspector records the request after the HTTP layer has parsed it. You see the method, the decoded target, every header value and the exact body bytes. A few things are outside its view: TLS details such as client certificates, the exact original order and capitalization of headers (HTTP/2 and the platform normalize them), and anything that happened on the sender's side before the request reached the network, such as a request that failed DNS lookup and was never sent. If a request never appears in the inspector, the problem is upstream of it.