What every HTTP status code actually means
Every HTTP response carries a three digit status code. The code is a contract: it tells the client whether the request worked, and if it did not, why. Get the code right and clients can react correctly without parsing your error prose. Get it wrong and you push retry logic, caching decisions, and authentication flows into guesswork.
This guide walks the five classes, then covers the codes that actually come up in production and the pairs people confuse most often. For each one, the focus is the same: what it means, when to send it, and what the client should do when it sees it.
The five classes
The first digit defines the class. Knowing the class alone tells a client most of what it needs.
- 1xx Informational. The request was received and processing continues. These are rare in everyday APIs.
100 Continuelets a client check whether a server will accept a large body before sending it.101 Switching Protocolsis what you see during a WebSocket upgrade. - 2xx Success. The request was received, understood, and accepted.
- 3xx Redirection. Further action is needed to complete the request, usually following a different URL.
- 4xx Client error. The request was malformed, unauthorized, or otherwise something the caller must fix. Retrying the same request unchanged will fail again.
- 5xx Server error. The request looked fine but the server failed to fulfill it. The client did nothing wrong and a retry may succeed later.
That client versus server split in the 4xx and 5xx ranges is the single most useful distinction. It tells automated clients whether to retry or to surface the error to a developer.
2xx: success, with nuance
200 vs 204
200 OK is the default success. It means the request succeeded and there is a response body to read.
204 No Content also means success, but explicitly tells the client there is no body. Use it when the action completed and you have nothing meaningful to return: a DELETE that removed a resource, a PUT that updated one without echoing it back, a settings save. A client receiving 204 should not try to parse a body. Sending 200 with an empty body works but is less honest about intent, and some clients will still attempt to parse the empty payload.
201 Created is the right answer to a POST that created a resource. Include a Location header pointing to the new resource so the client can fetch it.
3xx: redirection, and why the code matters
The redirect codes differ in two ways that have real consequences: whether the move is permanent, and whether the HTTP method is preserved.
- 301 Moved Permanently. The resource has a new permanent URL. Clients and search engines should update their references. Browsers and many clients may change the method to
GETon the followup, which is why a301on aPOSTcan silently drop the body. - 302 Found. A temporary redirect. The original URL is still canonical. Like
301, the method is often rewritten toGET, which is historical behavior rather than what the spec intended. - 308 Permanent Redirect. Same permanence as
301, but the method and body are guaranteed to be preserved. APOSTstays aPOST.
If you are redirecting an API call and need the method and body intact, reach for 308 (or 307 for the temporary case). If you are permanently moving a page and a GET followup is fine, 301 is correct and SEO friendly.
4xx: client errors, and the ones people get wrong
401 vs 403
This is the most misused pair in HTTP.
401 Unauthorized actually means unauthenticated. The server does not know who you are. Either no credentials were sent, or the ones sent were invalid or expired. The correct client response is to authenticate and try again: log in, refresh the token, prompt for credentials. A 401 should include a WWW-Authenticate header describing how to authenticate.
403 Forbidden means the server knows who you are and you are not allowed. Authentication succeeded but authorization failed. Retrying with the same identity will not help. The client should not re-prompt for login; it should tell the user they lack permission.
A quick rule: if logging in again could fix it, it is 401. If the user is already logged in and simply cannot do this thing, it is 403. When you are debugging token problems, decoding the token to check its claims and expiry helps, and you can do that locally with a JWT Decoder without sending the token anywhere.
400 vs 422
400 Bad Request means the request was malformed at a level the server could not even process. Broken JSON, a missing required parameter, a syntactically invalid payload. The server could not understand the request well enough to act on it. If you are unsure your payload is even valid JSON, run it through a JSON Formatter first to catch the syntax error before blaming the API.
422 Unprocessable Entity means the request was well formed and understood, but the contents failed validation. The JSON parsed cleanly, the fields were all present, but an email address was not a valid email, or a date was in the past, or a value violated a business rule. The shape was right; the meaning was wrong.
The practical split: 400 for "I cannot read this," 422 for "I read it, and it breaks the rules." A client should treat both as non retryable without changes, but 422 responses usually carry field level error details the client can map back to form inputs.
429 Too Many Requests
The client has sent too many requests in a window and is being rate limited. A well behaved server sends a Retry-After header telling the client how long to wait. The correct client behavior is to back off, ideally with exponential backoff plus jitter, and retry after the indicated delay rather than hammering the endpoint.
404 Not Found
The resource does not exist at this URL. Note that 404 is sometimes used deliberately instead of 403 to avoid revealing that a resource exists at all to an unauthorized caller.
5xx: server errors, and what to retry
500 Internal Server Error is the generic catch all: the server hit an unexpected condition. It tells the client nothing specific. A single retry may help if the cause was transient, but repeated 500s mean a bug to fix server side.
The gateway errors are more precise and worth distinguishing:
- 502 Bad Gateway. A server acting as a proxy got an invalid response from an upstream server. The upstream is broken or returned garbage.
- 503 Service Unavailable. The server is temporarily unable to handle the request, often due to overload or maintenance. This is explicitly temporary and may include a
Retry-Afterheader. It is the most retry friendly 5xx. - 504 Gateway Timeout. A proxy waited for an upstream response and gave up. The upstream is too slow or unreachable, rather than returning bad data.
For clients, 503 and 504 are the strongest signals to retry with backoff. A 502 may also be transient. A bare 500 should be retried cautiously, since the cause is unknown.
Pick the right code, every time
Status codes are a small vocabulary that does a lot of work. Sending the precise one means clients can authenticate, retry, redirect, and surface errors correctly without reading your documentation line by line.
When you need a fast lookup with the correct usage notes and the common confusions called out, use the HTTP Status Codes reference. Like every tool on toolhq, it runs entirely in your browser; nothing you look up is uploaded anywhere. While you are working through request and response details, the URL tools are handy for inspecting and decoding the endpoints those codes come back from.