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.
| Code | Meaning | When |
|---|---|---|
| 100 Continue | Server accepts a request body. | Used with Expect: 100-continue. |
| 101 Switching Protocols | Server upgrading the connection. | Used for WebSocket upgrades. |
| 103 Early Hints | Headers 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.
| Code | Meaning | When |
|---|---|---|
| 200 OK | Generic success with a body. | Default for GET and most POST results. |
| 201 Created | Resource was created. | POST or PUT that created a new entity; include the Location header. |
| 202 Accepted | Request accepted for async processing. | Job queued; return a job ID and a polling URL. |
| 204 No Content | Success, no response body. | DELETE, PUT that does not need to echo the resource. |
| 206 Partial Content | Range 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.
| Code | Meaning | When |
|---|---|---|
| 301 Moved Permanently | Resource has a new URL forever. | URL restructure; search engines update. |
| 302 Found | Temporary redirect; keeps method only by chance. | Avoid; pick 303 or 307. |
| 303 See Other | After POST, GET this URL. | Post-Redirect-Get pattern for form submissions. |
| 304 Not Modified | Cached copy is still valid. | Sent in response to If-None-Match or If-Modified-Since. |
| 307 Temporary Redirect | Temporary, keep the method. | Use for non-GET temporary redirects. |
| 308 Permanent Redirect | Permanent, 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.
| Code | Meaning | When |
|---|---|---|
| 400 Bad Request | Malformed request the server cannot parse. | JSON syntax error, missing required field. |
| 401 Unauthorized | No or bad credentials. | Authentication failure. The name is misleading; it means “unauthenticated.” |
| 402 Payment Required | Reserved; some APIs use for plan limits. | Stripe and a few others. |
| 403 Forbidden | Authenticated but not allowed. | Authorization failure. |
| 404 Not Found | Resource does not exist. | Unknown id, wrong path. |
| 405 Method Not Allowed | Wrong verb for this route. | Include Allow: header. |
| 406 Not Acceptable | No representation matches Accept. | Content negotiation failure. |
| 408 Request Timeout | Client took too long to send. | Idle connection; rare. |
| 409 Conflict | State conflict, retry will not help. | Optimistic concurrency, duplicate insert. |
| 410 Gone | Resource existed; intentionally removed. | Stronger signal than 404 for sunset URLs. |
| 411 Length Required | Server requires Content-Length. | Streaming uploads. |
| 412 Precondition Failed | If-Match or If-Unmodified-Since failed. | Optimistic locking. |
| 413 Payload Too Large | Body exceeds server limit. | File upload over the limit. |
| 414 URI Too Long | URL itself is too long. | Switch to POST body. |
| 415 Unsupported Media Type | Content-Type not handled. | Wrong serialization. |
| 422 Unprocessable Entity | Body parsed but semantically invalid. | Validation failure on parsed JSON. |
| 423 Locked | Resource is locked. | WebDAV; rare elsewhere. |
| 425 Too Early | Replay risk. | TLS 0-RTT. |
| 428 Precondition Required | Use If-Match or similar. | Force optimistic locking. |
| 429 Too Many Requests | Rate limit exceeded. | Include Retry-After: header. |
| 451 Unavailable For Legal Reasons | Blocked 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.
| Code | Meaning | When |
|---|---|---|
| 500 Internal Server Error | Unhandled exception. | The default when nothing else fits. |
| 501 Not Implemented | The method is not supported at all. | Stub endpoints. |
| 502 Bad Gateway | Upstream returned an invalid response. | Proxy or gateway error. |
| 503 Service Unavailable | Server is overloaded or in maintenance. | Include Retry-After:. |
| 504 Gateway Timeout | Upstream did not reply in time. | Slow database or downstream API. |
| 507 Insufficient Storage | Out of disk. | WebDAV; rare. |
| 511 Network Authentication Required | Captive 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.
| Action | Status |
|---|---|
| Created a resource | 201 with Location: header. |
| Updated a resource (no body returned) | 204. |
| Updated a resource (body returned) | 200. |
| Deleted a resource | 204 (or 200 with confirmation body). |
| Validation failed on JSON body | 422 with field errors. |
| Missing required header or query param | 400. |
| User not authenticated | 401 with WWW-Authenticate: header. |
| Authenticated user lacks permission | 403. |
| Resource missing | 404 (or 410 if it was deleted on purpose). |
| Duplicate insert / version conflict | 409. |
| Rate limit hit | 429 with Retry-After:. |
| Async job accepted | 202 with Location: to a status URL. |
| Maintenance window | 503 with Retry-After:. |
Common gotchas
200 OKwith{"error": "..."}in the body is wrong. The status code is part of the API.401 Unauthorizedis really “unauthenticated.” Use403when the user is known but lacks permission.302historically rewrotePOSTtoGET. Use303for the Post-Redirect-Get pattern or307for “same method.”- Returning
200from aPOSTthat created a resource loses information that201carries. 404and410are both “not here.” Use410when the URL is intentionally retired so caches and crawlers stop trying.Retry-After:is a header that pairs with429and503. Clients honor it; omitting it forces blind retries.