Compose HTTP calls visually — method, URL, headers, query, body — and copy the equivalent curl, fetch, axios, Python requests, or Node code. Send live to inspect status, headers, and body (subject to CORS). Runs in your browser.
Access-Control-Allow-Origin headers. Internal or auth-protected APIs will usually fail with a CORS error — copy the generated cURL or Python code and run it from a terminal instead.HTTP is the protocol layer every networked product runs on. Even when you are calling a "GraphQL API", a "gRPC service", or a "WebSocket endpoint", you are still riding HTTP/1.1, HTTP/2, or HTTP/3 underneath. Knowing the protocol cold pays off in every debugging session — every "why does this work in Postman but not in my code?" question, every CORS preflight mystery, every 401-when-it-should-be-403, every cached-response surprise. This guide is the working reference for the protocol fundamentals (RFC 9110), the headers that actually matter, the auth schemes that secure modern APIs, and the cURL → code patterns that live in every backend codebase.
| Method | Purpose | Body? | Safe? | Idempotent? |
|---|---|---|---|---|
GET | Read a resource | No (per RFC, ignored if present) | Yes | Yes |
HEAD | Read headers only (no body) | No | Yes | Yes |
POST | Create / non-idempotent action | Yes | No | No |
PUT | Replace a resource at a known URL | Yes | No | Yes |
PATCH | Partial update | Yes | No | No (typically) |
DELETE | Remove a resource | Usually no | No | Yes |
OPTIONS | Discover allowed methods, CORS preflight | No | Yes | Yes |
CONNECT | Tunnel (proxies use this) | — | No | No |
TRACE | Diagnostic loopback | No | Yes | Yes |
"Safe" means the request should not change server state. "Idempotent" means N identical requests have the same effect as one. These properties drive practical decisions:
| Header | Direction | Purpose |
|---|---|---|
Content-Type | Both | What format the body is. application/json, multipart/form-data, application/x-www-form-urlencoded. |
Accept | Request | What formats the client can handle. Most APIs only return one, but content-negotiation libraries respect it. |
Authorization | Request | Bearer <token> for JWT/OAuth, Basic <b64> for HTTP Basic. |
User-Agent | Request | Identifies your client. Many APIs require it; some rate-limit by it. |
Cache-Control | Both | Caching directives. no-store, max-age=300, private, public. |
ETag / If-None-Match | Both | Conditional requests; server returns 304 Not Modified. |
Last-Modified / If-Modified-Since | Both | Same idea, timestamp-based. |
Idempotency-Key | Request | Stripe, Square, Square Cash all support — safe POST retries. |
X-Request-Id / traceparent | Both | Distributed-tracing correlation. Echo it back in logs. |
Access-Control-* | Response | CORS headers. Server-controlled; clients read them. |
Content-Encoding | Response | gzip, br (Brotli), zstd. The server has compressed the body. |
Set-Cookie | Response | Set a cookie. HttpOnly; Secure; SameSite=Lax are the defaults you want. |
| Range | Class | Examples |
|---|---|---|
| 1xx | Informational | 100 Continue, 101 Switching Protocols (WebSocket upgrade) |
| 2xx | Success | 200 OK, 201 Created, 202 Accepted (async), 204 No Content |
| 3xx | Redirection | 301 Permanent, 302 Found (temp), 304 Not Modified, 308 Permanent (preserve method) |
| 4xx | Client error | 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 409 Conflict, 422 Unprocessable, 429 Too Many Requests |
| 5xx | Server error | 500 Internal, 502 Bad Gateway, 503 Service Unavailable, 504 Gateway Timeout |
Two distinctions every junior dev gets wrong:
Picking auth correctly the first time saves a rewrite later. For browser-facing APIs, Bearer JWTs (issued via OAuth 2.0 PKCE) are the modern default — short-lived access tokens with refresh tokens stored in HttpOnly cookies. For server-to-server, API keys with rotation or HMAC request-signing are simpler. To inspect or mint a Bearer token while you're testing here, the JWT decoder shows the payload claims and the JWT generator mints signed test tokens with HS256/RS256/ES256.
| Scheme | Header | Use for |
|---|---|---|
| Bearer (JWT / OAuth) | Authorization: Bearer <token> | Modern APIs; standard. |
| HTTP Basic | Authorization: Basic base64(user:pass) | Internal services, dev tools. Requires HTTPS. |
| API Key (header) | X-API-Key: ... or custom | Server-to-server. Rotate regularly. |
| API Key (query param) | ?api_key=... | Avoid — leaks into logs and Referer headers. |
| HMAC (request signing) | Authorization: AWS4-HMAC-SHA256 ... | AWS, Cloudflare, anywhere replay-protection matters. |
| Mutual TLS (mTLS) | Client cert | Service-to-service in zero-trust networks. |
| Cookies (Set-Cookie) | Implicit on every request | Browser-based apps; pair with CSRF tokens. |
The Same-Origin Policy stops a page on evil.com from reading responses from bank.com. CORS is the carve-out: a server can opt-in to allow specific cross-origin requests. The flow:
Access-Control-Allow-Origin: <origin> or *.OPTIONS preflight first. Server must respond with Access-Control-Allow-Methods, Access-Control-Allow-Headers, and Access-Control-Allow-Origin.Access-Control-Allow-Credentials: true AND a specific origin (not *).The single biggest debugging tip: CORS errors only happen in browsers. The same request from cURL, Postman, or your Node backend works fine. If your browser request fails but cURL succeeds, it's CORS — fix the server.
The cURL output is the de-facto sharing format. Common flags:
curl -X POST https://api.example.com/users \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"email":"alice@example.com","name":"Alice"}' \
-i # include response headers
-v # verbose: show request & response in detail
-L # follow redirects
-s # silent (no progress bar)
-w "%{http_code}\n" # write out specific values
--fail-with-body # exit non-zero on 4xx/5xx but still print body
--resolve api.example.com:443:127.0.0.1 # bypass DNS for local testing
For most APIs, HTTP/2 is the default, HTTP/3 is the upgrade path. From the application code's perspective the API is identical — you write fetch() or requests.get() the same way. Performance differences show up in p99 latency and concurrent-request scenarios.
Stripe, Square, Adyen, Paddle, and every modern payments API support idempotency keys. The client sends a unique key with the POST; the server stores the response keyed by that key. If the client retries (because the network dropped, or the server timed out), the server returns the cached response instead of double-charging. The pattern:
POST /charges HTTP/1.1
Idempotency-Key: 09cb3b3f-6e7f-4bba-8a4d-5d07c5b2c91a
Content-Type: application/json
{"amount": 1000, "currency": "usd"}
Use a UUID v4 generated once per logical operation. Don't reuse a key across distinct operations or you'll get the cached response from the previous one.
Authorization header.Content-Type on POST/PUT. Server can't parse the body. application/json is the right answer 95% of the time.2xx generally.Retry-After in the response — wait that long before retrying.application/json with application/x-www-form-urlencoded. Different body formats; the server cares which.JSON.stringify() in JS, but make sure the receiver parses it.\ line continuations for readability, browser fetch(), axios, Python requests (using json= when Content-Type is JSON, data= otherwise), and Node fetch. Each tab has its own copy button, so moving code into a script, notebook, or CI job takes a single click.fetch() calls only succeed when the target server responds with a permissive Access-Control-Allow-Origin header (and handles the CORS pre-flight for non-simple requests). Most internal or authenticated APIs don't, so the browser blocks the response — not because the server is down, but because the browser refuses to expose it. CORS only restricts browser JavaScript. Copy the generated cURL, Python, or Node snippet and run it from a terminal to bypass CORS entirely.'\'' pattern. Python output automatically switches to json= so requests serializes the payload and sets Content-Type for you.URLSearchParams semantics (the same rules the built-in URL object applies), so spaces become +, reserved characters are percent-encoded, and duplicate keys produce repeated parameters (?tag=a&tag=b) — the standard way most APIs expect array-valued params. If your URL already contains a query string, the new params are appended with & instead of ?.All tools run in your browser, no signup required, nothing sent to a server.