The request headers are fine; send the body.
Almost never set by hand. A client sends Expect: 100-continue before a large body so it can be rejected before uploading.
The connection is changing protocol, usually to WebSocket.
Emitted by the server during a WebSocket handshake. Not something an application returns.
Preliminary headers while the real response is prepared.
To send Link headers so the browser can preload assets before the page itself is ready.
The request succeeded and the body carries the result.
The default for a successful GET, or a PUT or POST that returns content.
The request succeeded and a new resource now exists.
A POST or PUT that created something. Send a Location header pointing at it — that is the part usually forgotten.
Often confused with 200 OK · 202 Accepted
The request was accepted but has not been carried out yet.
Queued work. Use it when you cannot promise the result, and give the caller somewhere to check progress.
Often confused with 201 Created · 200 OK
Succeeded, and there is deliberately no body.
A DELETE that worked, or a PUT with nothing to return. A 204 with a body is a contradiction and some clients will drop it.
Often confused with 200 OK · 205 Reset Content
Succeeded, and the client should clear the form it sent.
Rare, and genuinely different from 204: 204 says "nothing to show", 205 says "nothing to show AND reset your input". Also carries no body.
Often confused with 204 No Content
Part of the resource, in response to a Range request.
Video seeking and resumable downloads. Must echo Content-Range.
The resource has a new URL, for good.
A permanent move. Crawlers transfer ranking signals to the new URL. **Cached aggressively and hard to undo** — be sure before sending one.
Often confused with 302 Found · 308 Permanent Redirect
The resource is temporarily elsewhere.
A temporary move. Historically it let clients change POST to GET, which is why 307 exists.
Often confused with 301 Moved Permanently · 307 Temporary Redirect
Look at this other URL, with a GET.
After a successful POST, to stop a refresh resubmitting the form. The POST-redirect-GET pattern.
Often confused with 302 Found · 307 Temporary Redirect
Your cached copy is still good.
In reply to a conditional request carrying If-None-Match or If-Modified-Since. Carries no body by design.
Temporarily elsewhere, and keep the method.
Like 302 but the method and body must be preserved — a POST stays a POST. Use it when that matters.
Often confused with 302 Found · 308 Permanent Redirect
Permanently elsewhere, and keep the method.
Like 301 but the method is preserved. The right choice for a permanently moved API endpoint.
Often confused with 301 Moved Permanently · 307 Temporary Redirect
The request is malformed and the server will not process it.
Syntax errors — unparseable JSON, a missing required field. Not for a request that is well-formed but refused.
Often confused with 422 Unprocessable Content · 404 Not Found
You are not authenticated. The name is wrong — it means unauthenticated.
No credentials, or bad ones. Signing in could fix it. Must carry a WWW-Authenticate header.
Often confused with 403 Forbidden
You are authenticated and still not allowed.
Signing in again will not help. **The distinction from 401 is the single most muddled pair in HTTP**: 401 is "who are you?", 403 is "I know who you are, and no".
Often confused with 401 Unauthorized · 404 Not Found
No resource at this URL.
Also the right answer when you do not wish to confirm a resource exists to someone with no right to it — better than 403 there, because a 403 confirms it.
Often confused with 403 Forbidden · 410 Gone
The URL exists; that verb does not apply to it.
A POST to a read-only endpoint. Must list the permitted verbs in an Allow header.
Often confused with 404 Not Found · 501 Not Implemented
The request clashes with the current state.
An edit against a version that has since moved, or a duplicate unique value. Say what conflicted.
Often confused with 422 Unprocessable Content · 412 Precondition Failed
It was here and has been deliberately removed.
Stronger than 404: it tells a crawler to drop the URL rather than keep retrying. Only when you know it is permanent.
Often confused with 404 Not Found
A condition you attached did not hold.
The other half of optimistic concurrency, with If-Match. Stops a blind overwrite.
Often confused with 409 Conflict · 428 Precondition Required
The body is bigger than the server will take.
Upload limits. Formerly "Payload Too Large".
The Content-Type is not one this endpoint accepts.
A form posted to a JSON-only endpoint. About the format, never about the values.
Often confused with 400 Bad Request · 422 Unprocessable Content
Well-formed, understood, and semantically wrong.
Validation failures — a date in the past where a future one is required. **This is the code most APIs should use where they send 400.**
Often confused with 400 Bad Request · 409 Conflict
The server insists the request be conditional.
Forces a client to send If-Match, so concurrent edits cannot silently overwrite each other.
You are being rate limited.
Send Retry-After. A 429 with no indication of when to try again leaves a client guessing or hammering.
Blocked for legal reasons.
Court orders and statutory blocks. The number is a Fahrenheit 451 reference and that is deliberate.
Something broke and the server cannot be more specific.
The catch-all for an unhandled exception. Never leak the stack trace to the caller.
Often confused with 502 Bad Gateway · 503 Service Unavailable
The server does not support the method at all.
For a verb the server does not implement anywhere. Not for one that merely does not apply here — that is 405.
Often confused with 405 Method Not Allowed
A proxy got an invalid response from upstream.
The upstream answered with rubbish, or died mid-response. Your application is probably the upstream.
Often confused with 503 Service Unavailable · 504 Gateway Timeout
Temporarily unable to handle the request.
Maintenance or overload. Send Retry-After. **Use this rather than 500 during a deploy** — it tells a crawler to come back rather than to drop the page.
Often confused with 500 Internal Server Error · 502 Bad Gateway
A proxy gave up waiting for upstream.
The upstream never answered. 502 means a bad answer; 504 means no answer at all.
Often confused with 502 Bad Gateway · 503 Service Unavailable
The names are not the hard part. Everybody knows 404 is Not Found. What costs time is the pairs that are easy to confuse.
401 against 403 is the most muddled pair in HTTP, and the name is to blame: 401 says "Unauthorized" and means unauthenticated. 401 is "who are you?"; 403 is "I know who you are, and no".
400 against 422 is another. 400 is for a request the server cannot parse; 422 is for one that is perfectly well-formed and semantically wrong. Most APIs send 400 for both, and most of those cases are really 422.
So every entry here carries when to use it rather than just what it means — and names the neighbour it gets mistaken for.
401 means the server does not know who you are — no credentials, or bad ones — and signing in could fix it. 403 means it knows exactly who you are and you still may not. The name of 401 is the problem: it says “Unauthorized” and means unauthenticated. A 401 must also carry a WWW-Authenticate header saying how to authenticate, which is the part usually left off.
404 is usually the better answer. A 403 confirms the resource exists, which tells someone with no right to it that they have found a real URL — that is how an attacker enumerates what is worth attacking. Returning 404 gives away nothing. This site does the same for another member’s saved data.
400 is for a request the server cannot parse — malformed JSON, a missing required field, the wrong shape entirely. 422 is for a request that is perfectly well-formed and semantically wrong, such as a date in the past where a future one is required. Most APIs send 400 for both, and most of those cases are really 422.
Ask two questions: is it permanent, and must the method survive? 301 is permanent and historically allowed clients to turn a POST into a GET. 308 is permanent and preserves the method. 302 is temporary with the same method ambiguity; 307 is temporary and preserves it. For a moved API endpoint you almost always want 308. Be careful with 301 — it is cached aggressively and hard to undo.
Both come from something sitting in front of your application. 502 means the upstream answered with something invalid, or died mid-response. 504 means the upstream never answered at all before the proxy gave up. If you are debugging your own service behind a proxy, 502 usually points at a crash and 504 at something slow.
503 Service Unavailable, with a Retry-After header. It tells a crawler the page is temporarily away and to come back, whereas a 500 suggests something is broken and a 404 suggests the page is gone. Returning the wrong one during a few minutes of maintenance can cost pages from the index.
It is a genuine registered code from an April Fool’s specification in 1998, and it is deliberately not in this list. It has no use in a real API, and including it alongside codes people are trying to choose between adds noise to a reference.
4xx against 5xx is the real division: a 4xx says change the request, a 5xx says the request was fine and the server is at fault.
Send 503 with Retry-After. It tells a crawler the page is temporarily away and to come back. A 500 suggests something is broken; a 404 suggests the page is gone. Picking the wrong one during a few minutes of maintenance can cost pages from the index.
A reference, not a specification. Every code cites the RFC it comes from — read that where the exact wording matters. Nothing you type here is sent to our servers — the calculation runs entirely in your browser.