HTTP Status Codes: The Complete Developer Reference
HTTP status codes are the language servers use to tell clients what happened to their request. A three-digit number carries significant meaning — and using the wrong code is one of the most common mistakes in API design. This guide covers every important status code, when to use it, and the mistakes developers make most often.
The Five Classes of Status Codes
Status codes are grouped by their first digit:
- 1xx Informational: the request was received, processing continues
- 2xx Success: the request was received, understood, and accepted
- 3xx Redirection: further action is needed to complete the request
- 4xx Client Error: the request contains bad syntax or cannot be fulfilled
- 5xx Server Error: the server failed to fulfil a valid request
2xx Success Codes
200 OK — the standard success response. Use for GET and most other successful operations.
201 Created — a new resource was created. Use for successful POST requests that create a resource. Include a Location header pointing to the new resource URL.
204 No Content — success, but there's nothing to return. Use for DELETE requests and PUT/PATCH that don't need to return the updated resource.
206 Partial Content — used for range requests (streaming video, resumable downloads).
3xx Redirection Codes
301 Moved Permanently — the resource has moved to a new URL. Browsers and clients cache this permanently. Use when you've changed a URL forever.
302 Found — temporary redirect. Clients should not cache this. The original URL is still valid. Common for authentication redirects.
304 Not Modified — the cached version is still valid. The server returns this when the client sends If-None-Match or If-Modified-Since and nothing has changed — saving bandwidth.
307 Temporary Redirect — like 302, but explicitly preserves the HTTP method. A POST to a 307 URL should re-POST to the new URL. 302 historically broke this.
308 Permanent Redirect — like 301, but preserves the HTTP method.
4xx Client Error Codes
400 Bad Request — the request is malformed. Missing required fields, invalid JSON, wrong data types. Always include a body explaining what's wrong. Use our JSON Formatter to validate request bodies before sending.
401 Unauthorized — authentication is required and has either not been provided or has failed. Misleadingly named — it's actually about authentication, not authorisation.
403 Forbidden — authenticated, but you don't have permission. You know who the user is; they just can't do this.
404 Not Found — the resource doesn't exist. Use this, not 200 with an empty body or null result.
405 Method Not Allowed — the HTTP method isn't supported for this endpoint. Include an Allow header listing supported methods.
409 Conflict — the request conflicts with the current state. Use for duplicate creation attempts, concurrent edit conflicts, and state machine violations.
422 Unprocessable Entity — the request is syntactically valid JSON but semantically invalid (e.g., end date before start date). Many REST frameworks use this for validation errors instead of 400.
429 Too Many Requests — rate limit exceeded. Include Retry-After and X-RateLimit-* headers. Use our Timestamp Converter to interpret the Unix timestamp in Retry-After headers.
5xx Server Error Codes
500 Internal Server Error — something went wrong on the server. The catch-all error code. Never expose stack traces or internal details in the response body.
502 Bad Gateway — a proxy or gateway received an invalid response from an upstream server. Typically seen when your reverse proxy (Nginx, ALB) can't reach the application server.
503 Service Unavailable — the server is temporarily unable to handle requests. Use during maintenance, overload, or circuit-breaker trips. Include a Retry-After header if the outage is expected to be brief.
504 Gateway Timeout — the upstream server didn't respond in time. Common cause: database query running too slow, downstream service timing out.
Testing Status Codes with cURL
Use curl -I to see just the headers and status code, or curl -o /dev/null -w "%{http_code}" to print only the status code. Use our cURL Converter to build and understand cURL commands without memorising the flags.