HTTP Status Codes Explained
An HTTP status code is the three-digit number a server sends with every response to say what happened to the request. The first digit gives the class — success, redirect, client error, server error — and the full code gives the specific reason. Reading them correctly is the fastest way to diagnose an API problem, and choosing them correctly is one of the clearest signs of a well-designed API.
This guide explains the five classes, the codes you meet daily, the difference between look-alikes (401 vs 403, 301 vs 302, 502 vs 504), and which code your own API should return in each situation.
The five classes
- 1xx Informational — the request was received and processing continues (100 Continue, 101 Switching Protocols). Rarely seen by application code.
- 2xx Success — the request was understood and accepted.
- 3xx Redirection — the client must do something else, usually follow a new URL.
- 4xx Client error — the request is wrong: bad syntax, missing auth, no such resource. The client should not retry it unchanged.
- 5xx Server error — the request was valid but the server failed. The client may retry, ideally with backoff.
2xx: success codes
- 200 OK — the standard success; the body contains the result.
- 201 Created — a resource was created (after POST or PUT); the Location header points at it.
- 202 Accepted — the request was queued for asynchronous processing; not done yet.
- 204 No Content — success with no body (typical for DELETE and some PUT/PATCH).
- 206 Partial Content — a byte range was returned, used for resumable downloads and video.
3xx: redirects
- 301 Moved Permanently — the URL has changed for good; browsers and search engines update their records. Use for canonical URL changes.
- 302 Found — temporary redirect; the original URL stays the canonical one. The method may change to GET.
- 303 See Other — after a POST, go and GET this other URL (the post/redirect/get pattern).
- 304 Not Modified — the cached copy is still valid; no body is sent. A sign that caching works.
- 307 / 308 — temporary and permanent redirects that guarantee the method and body are preserved. Prefer 308 over 301 for APIs.
4xx: client errors
- 400 Bad Request — malformed syntax or invalid parameters; the general validation error.
- 401 Unauthorized — no valid credentials. Despite the name it means "not authenticated". Send a WWW-Authenticate header.
- 403 Forbidden — authenticated, but not allowed to do this. Retrying with the same credentials will not help.
- 404 Not Found — no resource at this URL (or the server prefers not to say whether it exists).
- 405 Method Not Allowed — the URL exists but not for this method (e.g. DELETE on a read-only resource). Include an Allow header.
- 409 Conflict — the request clashes with current state: duplicate unique key, stale version, already processed.
- 410 Gone — existed once, removed on purpose, will not return.
- 415 Unsupported Media Type — wrong Content-Type on the request body.
- 422 Unprocessable Entity — the syntax is fine but the values fail validation. Widely used for field-level errors.
- 429 Too Many Requests — rate limit hit; the Retry-After header says when to try again.
Try it: API Status Code Simulator Try it: HTTP Status Analyzer
5xx: server errors
- 500 Internal Server Error — an unhandled exception. Never the correct answer to bad input; it means validation is missing.
- 501 Not Implemented — the server does not support the method at all.
- 502 Bad Gateway — a proxy or load balancer got an invalid response from the upstream server (it crashed, or sent garbage).
- 503 Service Unavailable — the server is overloaded or in maintenance; temporary. Send Retry-After.
- 504 Gateway Timeout — the proxy waited for the upstream and it never answered in time.
Codes people confuse
- 401 vs 403 — 401: who are you? (log in). 403: I know who you are, and the answer is no.
- 301 vs 302 vs 308 — permanent vs temporary; 308 also keeps POST as POST.
- 400 vs 422 — 400 for unparseable or structurally wrong requests, 422 for well-formed requests with invalid values. Pick one convention and keep it.
- 502 vs 503 vs 504 — upstream returned junk vs server unavailable vs upstream too slow.
- 404 vs 410 — unknown vs deliberately removed.
Which code should your API return?
Return the most specific code that is true, use it consistently, and always send a JSON error body with a stable machine-readable code and a human-readable message. Never wrap a failure in 200 — clients and monitoring both depend on the status line. Rate-limit with 429 and Retry-After, validate with 400/422, authenticate with 401, authorize with 403, and reserve 500 for bugs you intend to fix.
Try it: API Request Builder Try it: API Status Code Simulator
Frequently asked questions
What does HTTP status 200 mean?
OK — the request succeeded and the response body carries the result. It is the default success code for GET.
What is the difference between 401 and 403?
401 means the request has no valid authentication (log in or send a token). 403 means the identity is known but that action is not permitted.
What does a 502 Bad Gateway mean?
A proxy or load balancer in front of the application received an invalid response from it — usually the application server crashed, restarted or timed out at the connection level.
What does 429 Too Many Requests mean?
The client has exceeded a rate limit. Wait for the time in the Retry-After header before sending more requests.
Should validation errors return 400 or 422?
Either is acceptable; 400 is the classic choice, 422 is common in modern APIs for field-level validation. Consistency across the API matters more than the choice.
Is 304 Not Modified an error?
No. It means the client's cached copy is still current, so the server sent no body. It saves bandwidth and is a sign that caching headers are working.
Tools mentioned in this guide
Look up any HTTP status code with its meaning, RFC reference and when to use it.
Analyze the HTTP status code and headers of a response and get an explanation of whether it is correct for the situation.
Get a public endpoint that returns any HTTP status code, with optional delay and custom JSON body, to test client error handling.
Trace redirect chains (301/302/307/308) and see every hop, status and final URL.
Compose and send HTTP requests (method, URL, headers, auth, body) and inspect the response — a lightweight Postman in your browser.
Generate example responses for any HTTP status code with appropriate headers and bodies.
Test CORS configuration: send preflight and simple requests from a given origin and inspect the Access-Control-* headers.