Walk through HTTP status codes an API should actually use correctly (not just 200 and 500)
Most APIs use maybe six status codes correctly and paper over everything else with 200 or 500 — here's the vocabulary interviewers actually expect you to know.
LEARN BY DOINGPut your intuition to work3 steps
Walk through HTTP status codes an API should actually use correctly (not just 200 and 500)
Use the lesson’s examples and explanation to check your idea.
Personal reflection. Nothing is sent to an AI service.#A status code is a contract, not decoration
HTTP status codes are the one piece of a response that every layer in the chain — browsers, SDKs, load balancers, CDNs, monitoring, retry middleware — is guaranteed to look at, even when it has no idea what your JSON body means. A 200 tells every one of those layers "this succeeded, cache it if applicable, don't retry." A 503 tells them "this is temporary, back off and retry later." A 401 can trigger a client to refresh a token and replay the request automatically. When an API returns 200 OK with { "error": "insufficient funds" } in the body, every one of those generic layers gets the wrong signal, no matter how clear the JSON looks to a human reading it directly.
#2xx — success, but which kind
| Code | Meaning | When to actually use it |
|---|---|---|
| 200 OK | Generic success with a body | Reads, and writes that don't fit the more specific codes below |
| 201 Created | A new resource now exists | After a POST that creates something — pair it with a Location header pointing at the new resource |
| 202 Accepted | Request is valid, work is queued | Async/background processing — there is no result yet to return |
| 204 No Content | Success, nothing to send back | DELETE, or a PUT/PATCH with no meaningful body to return — the response must not include one |
The most common miss here isn't picking the wrong 2xx — it's never leaving 200 at all. An API that returns 200 for creation, deletion, and async acceptance alike is throwing away information a client could otherwise act on automatically.
#3xx — redirection, and it matters which one
| Code | Meaning | Gotcha |
|---|---|---|
| 301 Moved Permanently | Resource lives at a new URL, forever | Clients and crawlers are expected to update stored links |
| 302 Found | Temporary redirect | Legacy clients historically rewrite the following request to GET, dropping the original method and body |
| 303 See Other | "Redo this as a GET, somewhere else" | The correct code for a post/redirect/get flow after a form submission |
| 307 Temporary Redirect | Temporary, but preserves method and body | The safe choice when redirecting a POST and you need the body to survive |
| 308 Permanent Redirect | Like 301, but preserves method and body |
The 302-vs-307 distinction is a real interview trap: reach for 302 out of habit on a POST endpoint and some clients will silently turn it into a bodiless GET.
#4xx — the client did something, and the code should say what
| Code | Meaning | Gotcha |
|---|---|---|
| 400 Bad Request | The request is malformed — can't even be parsed | Not for valid-but-wrong data — that's 422 |
| 401 Unauthorized | Actually means unauthenticated — missing or invalid credentials | The name in the spec is famously misleading |
| 403 Forbidden | Authenticated, but not allowed to do this | The classic 401-vs-403 pair interviewers ask about |
| 404 Not Found | Resource doesn't exist | Some APIs deliberately return 404 instead of 403 to avoid confirming a resource exists at all |
| 405 Method Not Allowed | Right URL, wrong verb | |
| 409 Conflict | The request conflicts with current server state | Optimistic-concurrency failures, duplicate-resource creation |
| 410 Gone | Existed once, intentionally and permanently removed | Distinct from 404, which just means "unknown" |
| 422 Unprocessable Entity | Well-formed request, semantically invalid | Field-level validation errors on a syntactically valid JSON body |
| 429 Too Many Requests | Rate limit hit | Should come with a Retry-After header |
#5xx — something broke on the server side, but where
| Code | Meaning | Where it usually comes from |
|---|---|---|
| 500 Internal Server Error | Generic catch-all | An unhandled exception — the honest "we don't know" code |
| 501 Not Implemented | Server doesn't support the requested capability | Rare outside of partially-implemented APIs |
| 502 Bad Gateway | A reverse proxy/gateway got an invalid response from upstream | The upstream service, not the gateway itself, is usually broken |
| 503 Service Unavailable | Server temporarily can't handle the request | Overload or planned maintenance — pair with Retry-After |
| 504 Gateway Timeout | Upstream didn't respond in time | Distinguishes "upstream is slow" from "upstream sent garbage" (502) |
#Retry logic should branch on the status class
Not every non-2xx is worth retrying, and treating them all the same is a real production hazard. 429, 503, and 504 are meant to be retried, ideally with backoff and by honoring Retry-After. 400, 401, 403, 404, 409, and 422 will not succeed on retry — the request itself is the problem, not the timing — so retrying them just adds load to a system that's already telling you something is wrong. A well-built HTTP client branches its retry policy on the status class rather than firing the same backoff loop at anything that isn't 200.
🧠 Check your understanding
0/4 · 0/4 answered1. A client submits a well-formed JSON body, but the "email" field fails a validation rule. Which status code fits best?
2. A request carries a valid, current auth token, but that user isn't allowed to delete this particular resource. What should the API return?
3. Why is redirecting a POST with 302 risky?
4. A rate-limited client keeps retrying immediately after getting 429s and makes things worse. What's missing from the API's response?