HTTP Status Codes: A Developer's Complete Reference
June 10, 2026 · 7 min read
HTTP Status Codes: A Developer's Complete Reference
Every HTTP response carries a three-digit status code that tells the client exactly what happened with its request. Whether you're designing a REST API, debugging a broken integration, or figuring out why your redirect isn't passing PageRank, understanding status codes at a deep level saves hours of guesswork.
This guide covers all major classes with practical REST API context and the subtle differences that trip up even experienced developers.
How Status Codes Are Organized
HTTP status codes fall into five classes, defined by the first digit:
| Class | Range | Meaning |
|---|---|---|
| 1xx | 100–199 | Informational — request received, continuing |
| 2xx | 200–299 | Success — request received, understood, accepted |
| 3xx | 300–399 | Redirection — further action needed |
| 4xx | 400–499 | Client error — bad request |
| 5xx | 500–599 | Server error — server failed |
1xx Informational
These are rarely seen in day-to-day development but matter in specific protocols.
100 Continue — The server has received the request headers and the client should proceed to send the request body. Useful when sending large payloads: the client can check authorization before uploading a 500 MB file.
101 Switching Protocols — The server agrees to switch protocols as requested by the client. This is the response you get when upgrading an HTTP connection to WebSocket:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
2xx Success
These are the happy-path codes. Choosing the right one communicates intent clearly to API consumers.
200 OK — The all-purpose success response. Use it for GET requests that return data, and for POST/PUT/PATCH when you return the updated resource in the body.
201 Created — Use this instead of 200 when a POST request successfully creates a new resource. Pair it with a Location header pointing to the new resource:
HTTP/1.1 201 Created
Location: /api/users/42
{ "id": 42, "name": "Jane", "email": "[email protected]" }
204 No Content — Success, but nothing to return. Ideal for DELETE and for PUT/PATCH when you don't want to return the full resource. Returning a body with 204 violates the spec.
206 Partial Content — Used for range requests, such as video streaming or resumable file downloads. The client sends Range: bytes=0-1023 and gets back 206 with the requested slice plus a Content-Range header.
3xx Redirects
Redirects tell the client to look somewhere else. The differences between them have real SEO and caching consequences.
301 Moved Permanently — The resource has permanently moved to a new URL. Browsers cache this indefinitely. Search engines transfer PageRank to the new URL. Use this when you rename a URL for good.
302 Found — Temporary redirect. Browsers don't cache it, and search engines keep PageRank on the original URL. Use this for login redirects, A/B tests, or maintenance pages — anything temporary.
SEO impact: Mistakenly using 302 when you mean 301 is one of the most common SEO errors. A 302 tells Google "the old URL is still the canonical one," which splits authority between two URLs instead of consolidating it.
303 See Other — After a POST, redirect the client to a GET endpoint to retrieve the result. This breaks the POST/redirect/GET pattern cleanly and prevents form resubmission on browser back:
POST /checkout → 303 → GET /order/123/confirmation
304 Not Modified — The resource hasn't changed since the client last fetched it (based on If-Modified-Since or If-None-Match headers). No body is sent; the client uses its cached copy. Essential for performance.
307 Temporary Redirect — Like 302, but the method and body must not change. If you POST to a URL and get a 307, you POST to the new URL too. Use this when method preservation matters.
308 Permanent Redirect — Like 301, but method-preserving. Less common, but correct when you permanently move a POST endpoint.
4xx Client Errors
These tell the client it did something wrong. Being specific here helps API consumers debug faster.
400 Bad Request — The request is malformed: missing required fields, invalid JSON, wrong data types. Return a body explaining what's wrong:
{
"error": "validation_failed",
"fields": { "email": "must be a valid email address" }
}
401 Unauthorized — Despite the name, this means unauthenticated: the client hasn't provided valid credentials (or provided none at all). The response should include a WWW-Authenticate header indicating how to authenticate.
403 Forbidden — The client is authenticated but not authorized to access this resource. The server knows who you are; it just won't let you in. Key difference:
401: "Who are you? Prove it."403: "I know who you are. You don't have permission."
404 Not Found — The resource doesn't exist at this URL. Could be a typo, a deleted record, or a URL that never existed.
405 Method Not Allowed — The resource exists, but not for this HTTP method. GETting /api/users is fine; DELETEing /api/users is not. Return an Allow header listing valid methods:
Allow: GET, POST
409 Conflict — The request conflicts with current resource state. Classic use case: trying to create a user with an email that already exists, or a version conflict in optimistic locking.
410 Gone — Like 404, but permanent. The resource existed and has been deliberately removed. Search engines deindex 410 pages faster than 404s. Use 410 for intentionally retired URLs.
422 Unprocessable Entity — The request is well-formed syntactically, but the content fails business validation. Common in REST APIs for semantic errors (400 covers syntax errors; 422 covers logic errors).
429 Too Many Requests — Rate limit exceeded. Always include Retry-After and X-RateLimit-* headers:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1718100000
5xx Server Errors
These indicate the server failed to fulfill a valid request. The client did nothing wrong.
500 Internal Server Error — A catch-all for unhandled exceptions. Log the full error server-side; return a generic message to the client. Never expose stack traces in production responses.
502 Bad Gateway — A proxy or gateway (nginx, load balancer, API gateway) received an invalid response from an upstream server. Usually means the app server crashed or returned garbage.
503 Service Unavailable — The server is temporarily unable to handle requests: overloaded, in maintenance, or a dependency is down. Include a Retry-After header when possible.
504 Gateway Timeout — The proxy timed out waiting for the upstream server. The upstream is alive but too slow. Common when a database query or third-party API hangs.
Common Mistakes to Avoid
Returning 200 for errors — Never do this. APIs that return {"status": "error"} inside a 200 response force clients to parse the body to detect failures, breaking HTTP clients, monitoring tools, and caching layers.
404 vs 410 — Use 404 for "doesn't exist here." Use 410 for "existed, now gone." The distinction matters for SEO and API clients that need to know whether to retry.
401 vs 403 — The most confused pair. Ask yourself: does the server know the user's identity? If no identity provided → 401. Identity confirmed but lacking permission → 403.
Using 302 for permanent moves — Always audit your redirects. A 302 that should be a 301 costs you SEO equity every day it stays wrong.
Vague 400 responses — A 400 Bad Request with no body is useless. Always tell the client which field failed and why.
Quick Reference
Use the HTTP Status Codes Reference tool to look up any code instantly, including its spec definition and common use cases. When building API responses, the HTTP Header Generator helps you construct correct headers for rate limiting, redirects, and content negotiation.
Understanding these codes deeply makes you a better API designer, a faster debugger, and someone who writes integrations that handle edge cases gracefully instead of silently swallowing errors.