πŸ—“οΈ 29042026 1200
πŸ“Ž #api #http

HTTP STATUS CODES SEMANTICS

The five status-code classes and the specific codes that carry distinct meaning. Most of the codes are forgettable; the ones that aren't (401 vs 403, 422 vs 400, 409, 429, 503) come up in real API decisions.

The Five Classes​

ABSTRACT

1xx Informational β€” interim, rarely surfaced to apps (e.g. 100 Continue, 101 Switching Protocols). 2xx Success β€” request completed as intended. 3xx Redirect β€” client must take additional action to complete. 4xx Client Error β€” request itself is faulty; do not retry without changing the request. 5xx Server Error β€” server failed; same request might succeed later.

Class semantics matter because clients, proxies, and SDKs auto-retry differently based on class. Returning the wrong class causes wrong retry behaviour.

2xx β€” The Useful Ones​

CodeWhen
200 OKGeneric success with body. Default for GET.
201 CreatedNew resource created. Include Location header pointing to the new resource. Default for POST creates.
202 AcceptedAsync work queued; not yet complete. Body should describe how to track.
204 No ContentSuccess with no body to return. Default for PUT/DELETE that have nothing to say.
206 Partial ContentRange request response (downloads, video).

3xx β€” Redirects​

CodeWhen
301 Moved PermanentlyResource has a new permanent URL. Browsers cache aggressively. Hard to undo.
302 FoundTemporary redirect. Browsers don't cache (mostly).
303 See OtherAfter POST, redirect client to GET a result resource.
304 Not ModifiedConditional GET β€” client's cached copy is still valid.
307 Temporary RedirectLike 302 but preserves method (302 may convert POST→GET historically).
308 Permanent RedirectLike 301 but preserves method.

Use 307/308 in API contexts to avoid the historical method-rewriting baggage of 301/302.

4xx β€” Client Errors​

CodeWhen
400 Bad RequestSyntactically invalid (malformed JSON, missing required field). Fix the request.
401 UnauthorizedAuthentication missing or invalid. Send credentials. Confusingly named β€” should be "Unauthenticated".
403 ForbiddenAuthenticated, but not allowed. Different user/scope/permission needed.
404 Not FoundResource doesn't exist (or you can't see it for privacy reasons).
405 Method Not AllowedEndpoint exists but doesn't accept this method. Must include Allow header.
409 ConflictState conflict (concurrent edit, duplicate creation). Common for optimistic concurrency violations.
410 GoneResource permanently removed; do not retry. Distinct from 404 (don't know).
412 Precondition FailedIf-Match / If-Unmodified-Since failed.
415 Unsupported Media TypeServer can't process the request body's content-type.
422 Unprocessable EntitySyntactically OK but semantically invalid (validation failure). Distinct from 400.
429 Too Many RequestsRate-limited. Include Retry-After header. See rate_limiting_algorithms.

401 vs 403 β€” the most-asked clarification​

  • 401: "I don't know who you are." β†’ log in / send a token.
  • 403: "I know who you are, you can't do this." β†’ switch user / request access.

Sending 403 when you mean 401 (or vice versa) breaks SSO redirect flows and SDK auth-refresh logic.

422 vs 400​

  • 400: bad syntax. Cannot parse. JSON malformed, required field missing.
  • 422: parsed fine, but the contents fail validation (negative age, invalid email format, business rule violation).

Many APIs use 400 for both. RFC 9110 added 422 to fit; using it cleanly improves error handling on the client side.

5xx β€” Server Errors​

CodeWhen
500 Internal Server ErrorUnhandled exception, generic failure. The "I don't know what went wrong" response.
501 Not ImplementedMethod recognised but not implemented. Distinct from 405.
502 Bad GatewayUpstream returned an invalid response (typically the reverse proxy says this).
503 Service UnavailableOverloaded / under maintenance. Include Retry-After.
504 Gateway TimeoutUpstream timed out. Common for slow downstream services.

5xx is the class clients/SDKs auto-retry. Don't return 5xx for "your input was wrong" β€” that's 4xx, and clients won't retry it.

What Each Class Means for Retries​

ClassRetry advice
2xxDon't retry. Done.
3xxFollow redirect (or not, per client policy).
4xxDo not retry without changing the request. Exception: 408 Request Timeout, 425 Too Early, 429 (after backoff).
5xxRetry with retry_backoff_jitter. Exception: 501 Not Implemented (request will never succeed).

429 is the special case β€” yes retry, but only after Retry-After.

Common Pitfalls​

  • 400 for everything 4xx-ish β€” collapses meaningful distinctions. Use the specific code so clients can react correctly (auth refresh on 401, retry on 429, etc.).
  • 200 with {"error": ...} body β€” a few APIs do this. Breaks every monitoring tool that filters by status. Use HTTP status codes.
  • 500 for validation failures β€” clients retry, server keeps failing the same way. Use 4xx.
  • Missing Retry-After on 429 / 503 β€” clients then guess. Worse, they hammer with default delays. Always set it.
  • No Location on 201 β€” clients can't find the resource they just created.
  • Custom 600+ codes β€” proxies and gateways drop or rewrite. Stay within standard ranges.
  • Conflating 503 and 504 β€” 503 means "I refuse" (overloaded); 504 means "upstream didn't answer". Different operational signals.
  • Allow header missing on 405 β€” spec requires it. Many implementations forget. Without it, clients can't programmatically discover the right method.

References​