Status codes are HTTP's entire error-communication system compressed into three digits, and they're a favorite interview topic precisely because they reveal whether you understand what's happening between browser and server. This guide covers the codes you'll actually encounter — with the distinctions that trip people up.

The five classes in one look

ClassMeaningWho's involved
1xxInformational — request received, keep goingRarely seen directly
2xxSuccessEveryone's favorite
3xxRedirection — the resource is elsewhereBrowser follows automatically
4xxClient error — the request is the problemCaller must fix
5xxServer error — the server is the problemServer owner must fix

That last distinction — 4xx blames the caller, 5xx blames the server — is the single most important idea. Return the wrong class and every monitoring dashboard, retry policy, and debugging session downstream draws the wrong conclusion.

2xx: more than just 200

  • 200 OK — success, response body included.
  • 201 Created — success and a new resource exists; the right response to a POST that created something (with a Location header pointing at it). APIs that return 200 for everything are leaving information on the table.
  • 204 No Content — success with nothing to say; the natural response to a DELETE.

3xx: the redirect family (and the SEO trap)

  • 301 Moved Permanently — "update your records." Browsers cache it aggressively, and search engines transfer the old URL's ranking to the new one.
  • 302 Found (temporary) — "it's over there for now, keep the old address." No ranking transfer, no assumption of permanence.
  • 304 Not Modified — the browser's cached copy is still valid; the server sends headers only, saving the body transfer. This is conditional caching working as designed, not an error.

The trap: using 302 where 301 belongs. When we restructured URLs on this site, every old URL got an explicit 301 — a 302 would have told Google to keep the dead URLs indexed indefinitely. The reverse trap is worse: a 301 you later regret is nearly impossible to un-teach to browsers that cached it. Rule of thumb — 301 only when you're sure, and test redirects with curl -I before shipping them.

4xx: the precise vocabulary of "you did it wrong"

  • 400 Bad Request — malformed input: invalid JSON, missing required fields.
  • 401 Unauthorized — misnamed; it really means unauthenticated: "I don't know who you are." Missing or expired credentials.
  • 403 Forbidden — authenticated but not allowed: "I know exactly who you are, and no." The 401-vs-403 distinction is a perennial interview question because using them correctly requires understanding authentication vs authorization.
  • 404 Not Found — no such resource. Also used deliberately instead of 403 when confirming a resource exists would itself leak information (private repos on GitHub return 404, not 403, to strangers).
  • 422 Unprocessable Entity — syntactically valid but semantically wrong: well-formed JSON whose email field isn't an email. Laravel's validation errors use it, distinguishing "your JSON is broken" (400) from "your data is wrong" (422).
  • 429 Too Many Requests — rate limited; well-behaved clients read the Retry-After header and back off.

5xx: when it's not their fault

  • 500 Internal Server Error — the generic "something threw an exception." If your API returns 500 for bad user input, you're mislabeling caller errors as server bugs — and your error monitoring will page you for typos in other people's requests.
  • 502 Bad Gateway — a proxy (nginx, a load balancer, a CDN) reached your backend and got garbage or nothing. Classic cause: the application process is down while the web server is up.
  • 503 Service Unavailable — deliberately down: maintenance mode, overload shedding. Laravel's artisan down returns this.
  • 504 Gateway Timeout — the proxy gave up waiting. Usually a slow query or an external call without a timeout, surfacing at the infrastructure layer.

Debugging heuristic for the 502/503/504 family: the problem is almost never in the proxy that reported it — the proxy is the messenger. Look at what sits behind it.

Choosing codes in your own APIs

Three habits produce APIs people trust: use the most specific correct code (401 vs 403, 400 vs 422 — clients build logic on these distinctions); never return 200 with an error in the body{"status": "error"} under HTTP 200 breaks every generic client, cache, and monitor that reasonably trusts the status line; and pair machine-readable codes with human-readable bodies, so the status says what kind of problem and the body says which one exactly. Get these right and your API documents itself one response at a time.