Overview

Pick the status code by intent, not by tradition. The class (1xx, 2xx, 3xx, 4xx, 5xx) tells the client what to do next; the specific code adds a reason. This card lists every code worth using in an API plus the “what to use when” map. For the umbrella API rules, see fastapi.

1xx Informational

Rare in app code; mostly handled by the protocol layer.

CodeMeaningWhen
100 ContinueServer accepts a request body.Used with Expect: 100-continue.
101 Switching ProtocolsServer upgrading the connection.Used for WebSocket upgrades.
103 Early HintsHeaders sent before final response.Preload hints during slow processing.

Almost no application code should emit a 1xx response directly.

2xx Success

Pick the most specific success code.

CodeMeaningWhen
200 OKGeneric success with a body.Default for GET and most POST results.
201 CreatedResource was created.POST or PUT that created a new entity; include the Location header.
202 AcceptedRequest accepted for async processing.Job queued; return a job ID and a polling URL.
204 No ContentSuccess, no response body.DELETE, PUT that does not need to echo the resource.
206 Partial ContentRange request honored.Video streaming, resumable downloads.

201 is correct for resource creation. 200 is acceptable but loses the “newly created” signal.

3xx Redirection

The browser usually handles these without app code looking.

CodeMeaningWhen
301 Moved PermanentlyResource has a new URL forever.URL restructure; search engines update.
302 FoundTemporary redirect; keeps method only by chance.Avoid; pick 303 or 307.
303 See OtherAfter POST, GET this URL.Post-Redirect-Get pattern for form submissions.
304 Not ModifiedCached copy is still valid.Sent in response to If-None-Match or If-Modified-Since.
307 Temporary RedirectTemporary, keep the method.Use for non-GET temporary redirects.
308 Permanent RedirectPermanent, keep the method.Permanent redirect for POST and PUT.

Use 308 for permanent redirects that must keep the request method. 301 rewrote POST to GET in old clients.

4xx Client errors

The most common API responses. Be specific; clients debug from the code.

CodeMeaningWhen
400 Bad RequestMalformed request the server cannot parse.JSON syntax error, missing required field.
401 UnauthorizedNo or bad credentials.Authentication failure. The name is misleading; it means “unauthenticated.”
402 Payment RequiredReserved; some APIs use for plan limits.Stripe and a few others.
403 ForbiddenAuthenticated but not allowed.Authorization failure.
404 Not FoundResource does not exist.Unknown id, wrong path.
405 Method Not AllowedWrong verb for this route.Include Allow: header.
406 Not AcceptableNo representation matches Accept.Content negotiation failure.
408 Request TimeoutClient took too long to send.Idle connection; rare.
409 ConflictState conflict, retry will not help.Optimistic concurrency, duplicate insert.
410 GoneResource existed; intentionally removed.Stronger signal than 404 for sunset URLs.
411 Length RequiredServer requires Content-Length.Streaming uploads.
412 Precondition FailedIf-Match or If-Unmodified-Since failed.Optimistic locking.
413 Payload Too LargeBody exceeds server limit.File upload over the limit.
414 URI Too LongURL itself is too long.Switch to POST body.
415 Unsupported Media TypeContent-Type not handled.Wrong serialization.
422 Unprocessable EntityBody parsed but semantically invalid.Validation failure on parsed JSON.
423 LockedResource is locked.WebDAV; rare elsewhere.
425 Too EarlyReplay risk.TLS 0-RTT.
428 Precondition RequiredUse If-Match or similar.Force optimistic locking.
429 Too Many RequestsRate limit exceeded.Include Retry-After: header.
451 Unavailable For Legal ReasonsBlocked by legal demand.Censorship, takedowns.

401 vs 403 trips engineers up. 401 means “the server does not know who you are.” 403 means “I know who you are; you cannot do this.”

5xx Server errors

Server bugs or upstream failures. These should page someone.

CodeMeaningWhen
500 Internal Server ErrorUnhandled exception.The default when nothing else fits.
501 Not ImplementedThe method is not supported at all.Stub endpoints.
502 Bad GatewayUpstream returned an invalid response.Proxy or gateway error.
503 Service UnavailableServer is overloaded or in maintenance.Include Retry-After:.
504 Gateway TimeoutUpstream did not reply in time.Slow database or downstream API.
507 Insufficient StorageOut of disk.WebDAV; rare.
511 Network Authentication RequiredCaptive portal.Cafe Wi-Fi.

503 is the correct choice for planned maintenance; 500 is the wrong code for “we are deploying.”

API design: what to use when

The most common decisions in one place.

ActionStatus
Created a resource201 with Location: header.
Updated a resource (no body returned)204.
Updated a resource (body returned)200.
Deleted a resource204 (or 200 with confirmation body).
Validation failed on JSON body422 with field errors.
Missing required header or query param400.
User not authenticated401 with WWW-Authenticate: header.
Authenticated user lacks permission403.
Resource missing404 (or 410 if it was deleted on purpose).
Duplicate insert / version conflict409.
Rate limit hit429 with Retry-After:.
Async job accepted202 with Location: to a status URL.
Maintenance window503 with Retry-After:.

Common gotchas

  • 200 OK with {"error": "..."} in the body is wrong. The status code is part of the API.
  • 401 Unauthorized is really “unauthenticated.” Use 403 when the user is known but lacks permission.
  • 302 historically rewrote POST to GET. Use 303 for the Post-Redirect-Get pattern or 307 for “same method.”
  • Returning 200 from a POST that created a resource loses information that 201 carries.
  • 404 and 410 are both “not here.” Use 410 when the URL is intentionally retired so caches and crawlers stop trying.
  • Retry-After: is a header that pairs with 429 and 503. Clients honor it; omitting it forces blind retries.