The shape of a request
An HTTP request is just text. If you opened a TCP connection to a server and typed the right characters, you'd be making a valid HTTP request by hand. The format hasn't fundamentally changed in three decades:
GET /api/orders/12345 HTTP/1.1
Host: api.example.com
Authorization: Bearer abc123
Accept: application/json
User-Agent: my-app/1.4.2
That's a complete request. The first line says what the client wants: the method (GET), the path (/api/orders/12345), and the protocol version. Everything after is headers — key-value metadata about the request. Headers end with a blank line; for requests that include a body (POST, PUT, PATCH), the body comes after that blank line.
The server's response has the same structure:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 87
{"id":"12345","status":"shipped","customer":"cust_42","total":4500}
First line is the status line: protocol version, status code (200), and a human-readable status message (OK). Then headers, then a blank line, then the body. The body's format is whatever the Content-Type header says — usually JSON for APIs in 2026.
Methods: the verbs
HTTP defines a small set of methods (also called verbs). The five that matter for APIs:
- GET — read. Should not have side effects. Caches and proxies assume GET is safe to repeat.
- POST — create something, or perform an action that doesn't fit the others. Not safe to repeat without coordination (see idempotency).
- PUT — replace a resource at a known URL. Idempotent: doing it twice has the same effect as once.
- PATCH — partial update. Idempotent if the patch describes the new state; not necessarily idempotent if it describes a delta.
- DELETE — remove a resource. Idempotent.
"Idempotent" means: if the request gets sent more than once (because the network failed and the client retried), the server ends up in the same state as if it had been sent once. This property matters because the network is unreliable and clients have to retry. The REST reference covers the conventions around method choice in detail.
Status codes: the grammar of responses
Status codes are three-digit numbers grouped by their first digit:
- 1xx — informational (rarely seen in practice).
- 2xx — success. Most often
200 OK, sometimes201 Createdor204 No Content. - 3xx — redirection. The resource is somewhere else.
- 4xx — client error. The request was wrong; don't retry without changing it.
- 5xx — server error. Something broke on the server side; retrying might work.
Clients should branch on the first digit before they branch on the specific code. A handler that doesn't recognize 422 should still treat it as "client error, don't retry" because of its 4xx prefix. The full set of status codes APIs actually use is in the REST reference.
Headers: the metadata channel
Headers carry everything that isn't the body. A few categories matter for APIs:
- Identity:
Authorization(the credential),User-Agent(which client made the request). - Content negotiation:
Content-Type(what the body is),Accept(what the client wants back),Accept-Encoding(whether the client supports gzip). - Caching:
Cache-Control,ETag,If-None-Match,Last-Modified. - Tracing:
X-Request-Idortraceparent— values that follow the request through your system for debugging. - Rate limiting:
X-RateLimit-Limit,X-RateLimit-Remaining,Retry-After.
Headers are case-insensitive in their names but case-sensitive in their values. Most servers normalize header names to lowercase internally; clients should not assume a specific casing in responses.
The body and content types
The Content-Type header tells the receiver how to parse the body. The common values for APIs:
application/json— JSON. The default for almost every API in 2026.application/x-www-form-urlencoded— form data, the way HTML forms submit. Used by some auth flows.multipart/form-data— file uploads.application/octet-stream— binary data, no structure.text/event-stream— Server-Sent Events.application/problem+json— RFC 7807 problem details, the standard for structured error responses.
The body's encoding (UTF-8, gzip, brotli) is separate from the Content-Type. Content-Encoding says how the bytes were compressed; the receiver decodes them, then parses the result according to Content-Type.
What's underneath
HTTP runs on TCP, which provides reliable, in-order delivery of bytes between two endpoints. TCP runs on IP, which routes packets between hosts. Each layer adds a small amount of overhead and a lot of capability.
Three details about the stack that affect API design:
- HTTP/1.1, HTTP/2, HTTP/3. Same semantic layer (methods, status codes, headers, bodies); different transport. HTTP/2 multiplexes many requests over one TCP connection. HTTP/3 runs over QUIC instead of TCP, which avoids head-of-line blocking when packets are lost. From the application's perspective, the differences are mostly transparent — your handler sees the same request regardless of which version was used.
- TLS. "HTTPS" is HTTP plus TLS — encryption and authentication of the connection itself. Not optional in 2026; any API exposed to the internet without TLS is broken. The TLS handshake adds latency on the first connection (one extra round trip in TLS 1.3, two in older versions); subsequent connections to the same server can resume the session.
- Connection reuse. Opening a TCP connection is expensive, especially with TLS. HTTP/1.1 keeps connections open after a response (
Connection: keep-alive) and HTTP/2 reuses one connection for many requests. Clients should reuse connections; clients that open a new one for each request will be slow.
Idempotency, safety, and what they mean for retries
Two related properties from the HTTP spec:
- Safe — the method shouldn't change anything on the server. GET, HEAD, OPTIONS.
- Idempotent — the method has the same effect on the server's state whether it's called once or many times. GET, HEAD, OPTIONS, PUT, DELETE.
POST is neither safe nor idempotent by default. PATCH is generally not idempotent. This matters because clients retry: if a request fails with no response (network timeout, gateway error), the client doesn't know whether the server processed it. Retrying a safe or idempotent request is risk-free. Retrying a POST might charge the customer twice. The convention that handles this is the Idempotency-Key header — covered in Idempotency Keys for APIs.
What clients actually do
When your code calls an API, here's the sequence:
- Resolve the hostname to an IP via DNS.
- Open a TCP connection to that IP on the right port (443 for HTTPS).
- Negotiate TLS — exchange certificates, derive a shared key.
- Send the HTTP request bytes over the encrypted connection.
- Read the response bytes.
- Parse the response.
Steps 1–3 are setup; step 6 is decoding. The request itself (steps 4–5) is small. For a series of requests to the same server, steps 1–3 happen once and are reused. For an API client calling many endpoints, the warm-connection performance matters far more than the cold-start performance.
What gets logged where
Three places API traffic shows up that affect what you can put in requests:
- Server access logs. Most servers log the request line (method + path + query string) and a few headers (User-Agent, Referer). Bodies are not logged by default. Anything in the URL — including query parameters — ends up in these logs. This is why credentials should not be in URLs.
- Client browser logs. Browsers log every request the page makes, visible in the network tab of dev tools. Anyone with access to the user's machine can see the URLs and most headers.
- Intermediate proxies and CDNs. Anything between the client and your server can see the headers and (for unencrypted HTTP) the body. With HTTPS, intermediaries see only the destination hostname and the encrypted bytes.
Where to go next
For how to design APIs on top of HTTP, see REST API Design. For when REST isn't the right fit, see GraphQL and WebSockets. For credentials and how to send them, see API Authentication. For the security model that surrounds all of this, see API security.