skip to content

Status-Code Selection

Picking the right code for each API scenario: creation, async acceptance, validation failure, authorization, conflicts, throttling. Interviewers run scenario drills here because the fine distinctions (400 vs 422, 404 vs 403) show whether you think about client behavior and information leakage.

part ofAPI stylesoverview, primer and where to startread it →
on this pageshow

questions

6

You are specifying the successful responses for create, update and delete endpoints in an HTTP API. How do you choose between status 200, 201 with a Location header, and 204, and when would you return a body at all?

level: juniorimportance: must knowfreq 74%

answer

  1. 201 + Location = created
  2. 200 = success with a body
  3. 204 = success, no body ever
  4. DELETE → 204 (or 200/202), be consistent
  5. Never 200 with success:false

basics

~20 s

201 plus a Location header when the request created a new resource; 200 with a body when you have something useful to return; 204 when the operation succeeded and there is genuinely nothing to send. Deletes typically return 204.

solid answer

~50 s

- **201 Created** — the request brought a new resource into existence. Include `Location` pointing at it, and usually the representation in the body so the client does not need a second round trip. - **200 OK** — success with a body. Use it for updates that return the stored representation, and for creates only when there is no single new resource URL to point at. - **204 No Content** — success, and the response deliberately has no body. Typical for `DELETE`, and for updates where the client already knows the resulting state. Guidance I apply: prefer returning the representation on writes (`200`/`201` with a body) because servers normalize, set timestamps, and compute derived fields — sending them back saves a GET and prevents client-side drift. Reserve `204` for cases with truly nothing to say. Never return `200` with an error payload inside; the status line is the contract.

go deeper

for a junior

Know the three codes and their triggers: created → 201 with Location, success with data → 200, success with nothing to return → 204.

for a middle

Explain why returning the representation on writes is usually better than 204, and how PUT-upsert uses 201 versus 200 to signal insert versus replace.

for a senior

Talk about generic consumers — retries, gateways, monitoring — and enforcing consistency across services rather than per controller.

for a principal

Set a house rule for write responses and encode it in the API guidelines and linter so every team's creates and deletes look the same.

## The status line is part of the contract Generic clients — proxies, SDK generators, retry libraries, monitoring — read the status code, not your JSON. Choosing 2xx codes deliberately is what lets them behave correctly without understanding your domain. ## 201 Created Meaning: the request resulted in one or more new resources. The response should carry `Location` with the URL of the primary new resource: ``` POST /orders HTTP/1.1 201 Created Location: /orders/42 Content-Type: application/json {"id":42,"status":"new","createdAt":"2026-08-12T10:00:00Z"} ``` Two practical points. First, `Location` is what makes 201 useful — a 201 without it forces the client to parse the body and guess the URL template, which couples it to your routing. Second, including the body is optional but almost always right: the server has just computed the id, timestamps, defaults, and any normalization, and returning them saves a follow-up GET. 201 also applies to PUT when the PUT created the resource rather than replacing one — that distinction is exactly how a client learns whether its upsert was an insert. ## 200 OK The default success with a body. Use it for: - reads, - updates (`PUT`/`PATCH`) where you return the resulting representation, - POST that performed a *process* rather than creating an addressable resource (a validation call, a calculation, a search). A POST that creates several resources, or creates something with no meaningful individual URL, is better served by 200 with a body describing what happened than by a 201 whose `Location` would be a lie. ## 204 No Content Success, and the client must not expect a body — the response has none, and headers such as `Content-Type` are meaningless. It is the natural answer to `DELETE`, and to writes where returning state is pointless (a toggle the client already knows the outcome of, a bulk no-op). The cost is diagnostic: 204 gives an operator nothing in a log or a browser network tab, and gives the client nothing to reconcile against. That is why many teams' default is "return the representation" and 204 is the exception, not the rule. A subtlety worth knowing: 204 must not have a body, so if you later want to add one you must change the status code too — a contract change for clients that assert on it. ## Deletes Three defensible answers, and consistency matters more than the choice: - `204 No Content` — deleted, nothing to say. Most common. - `200 OK` with a small body — deleted, and here is what was deleted or a summary. - `202 Accepted` — deletion was queued (cascades, GDPR erasure, large object cleanup). Deleting something that is already gone is the classic question. `404` is defensible and honest; `204` is defensible on the grounds that DELETE is idempotent and the client's goal — "it is not there" — is satisfied. Pick one, document it, and be uniform, because clients write retry logic against it. ## Anti-patterns **200 with an error inside.** `HTTP/1.1 200 OK` + `{"success": false}` breaks every generic consumer: retries do not trigger, dashboards show a healthy service, and gateways cache the failure. The status line must reflect the outcome. **201 for updates.** Some frameworks default to it. It tells the client something new exists when nothing did. **204 with a body.** Some stacks will happily write bytes after a 204; intermediaries may drop or mangle them, and clients that respect the spec never read them. **Inconsistency across endpoints.** One create returning 201, another 200, a third 204 forces every client to special-case your API. Fix it at the framework level, not per controller. ## Quick decision rule Did something new come into existence at a URL? → **201 + Location** (body recommended). Otherwise, do you have anything useful to return? → **200 with body** if yes, **204** if genuinely no.

  • What should DELETE return when the resource is already gone?
    Either 404 (honest about the current state) or 204 (the client's desired end state holds, which fits DELETE's idempotency). Both are used in practice; what matters is picking one, documenting it, and applying it uniformly, because clients build retry logic on it. 404 is slightly more informative for debugging, 204 is friendlier to retries.
  • Should a POST that creates a resource return the created representation in the body?
    Usually yes. The server has just assigned the id, timestamps, defaults and any normalized values, so returning them saves the client a GET and prevents its local copy from drifting. The exception is very large representations or fan-out creates, where a 201 with Location alone keeps the response small and lets the client fetch on demand.

saying these in an interview costs you the question

  • Returning 200 with an error object in the body instead of a 4xx/5xx status
  • Omitting the Location header from a 201 response
  • Sending a body with 204
  • Using 201 for an update that created nothing
  • Choosing a different success code per endpoint with no rule behind it

context

open as a page

A request to your API is syntactically valid JSON but fails a business rule — for example an end date before the start date. Would you answer with HTTP status 400 or 422, and how do you draw the line between them in a contract?

level: middleimportance: must knowfreq 56%

basics

~20 s

400 for a request the server cannot parse or that is malformed — bad JSON, wrong type, missing required field. 422 for a well-formed request whose content violates semantic rules. Both are client errors; consistency and a machine-readable error body matter more than the choice.

open as a page

How do you decide between HTTP status 401, 403 and 404 when a caller is refused, and when would you deliberately return 404 for something that exists but the caller may not see?

level: middleimportance: must knowfreq 64%

basics

~20 s

401 means "I don't know who you are — authenticate" and must carry WWW-Authenticate. 403 means "I know who you are and you still may not". 404 hides existence: return it instead of 403 when merely confirming a resource exists leaks information.

open as a page

An API operation cannot finish within the request — it kicks off a video encode that takes minutes. How would you design the response contract around HTTP status 202 Accepted, and what must the client be able to do afterwards?

level: middleimportance: should knowfreq 40%

basics

~20 s

Return 202 Accepted with a pointer to a job or status resource (Location or a body link). The client polls that resource, which reports pending/running/succeeded/failed and links to the result. 202 means accepted for processing, not done and not guaranteed to succeed.

open as a page

When is HTTP status 409 Conflict the right answer in an API contract, and how does it differ from 422 and from 412 Precondition Failed?

level: seniorimportance: should knowfreq 42%

basics

~20 s

409 means the request is valid in itself but clashes with the resource's current state — a duplicate unique key, an illegal state transition, a concurrent edit. 422 means the request is invalid on its own terms; 412 means an explicit precondition header the client sent did not hold.

open as a page

Your service is overloaded and starts shedding traffic. How do you decide between HTTP status 429, 503 and 500 for those responses, and what do the codes tell a client to do?

level: seniorimportance: should knowfreq 48%

basics

~20 s

429 means this caller exceeded its rate or quota — retry after backing off. 503 means the service as a whole is unavailable or overloaded — retry later, ideally per Retry-After. 500 means an unexpected bug; retrying probably will not help and it should page someone.

open as a page