What Are HTTP Status Codes?
Every HTTP response includes a three-digit status code that tells the client whether the request succeeded, failed, or requires further action. Status codes are grouped into five classes, each identified by the first digit:
- 1xx — Informational: The request was received and processing is continuing.
- 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.
Understanding status codes is fundamental to building and consuming REST APIs. Using the wrong status code misleads API consumers, breaks client error handling, and causes subtle bugs that are hard to diagnose.
1xx — Informational
Informational responses are rarely seen in everyday API work but are important in certain scenarios.
100 Continue
The server has received the request headers and the client should proceed to send the request body. Used when a client sends a large payload and wants to confirm the server will accept it before transmitting all the data.
101 Switching Protocols
The server agrees to switch protocols as requested by the client. Most commonly seen when upgrading an HTTP connection to a WebSocket connection.
2xx — Success
The 2xx class indicates the request was successfully received, understood, and accepted.
200 OK
The most common success response. The request succeeded and the response body contains the requested data. Used for successful GET, PUT, PATCH, and DELETE requests.
GET /users/1
HTTP/1.1 200 OK
{ "id": 1, "name": "Alice Johnson" }
201 Created
A new resource was successfully created as a result of the request. Should be returned for successful POST requests. Best practice is to include a Location header pointing to the new resource.
POST /users
HTTP/1.1 201 Created
Location: /users/42
{ "id": 42, "name": "Bob Smith" }
202 Accepted
The request has been accepted for processing but processing has not been completed. Used for asynchronous operations — for example, when a job has been queued and the result will be available later.
204 No Content
The request succeeded but there is no content to return. Commonly used for successful DELETE operations and PATCH operations where no updated resource is returned.
DELETE /users/42
HTTP/1.1 204 No Content
206 Partial Content
The server is returning only part of the resource, as requested by the client using a Range header. Used in video streaming and large file downloads to support resumable transfers.
3xx — Redirection
Redirection responses tell the client to take additional action, usually by following a different URL.
301 Moved Permanently
The resource has been permanently moved to a new URL. Clients and search engines should update their bookmarks. All future requests should use the new URL provided in the Location header.
302 Found
The resource is temporarily available at a different URL. Clients should continue to use the original URL for future requests. Commonly used for temporary redirects in web applications.
304 Not Modified
The cached version of the resource is still valid. The client sent a conditional GET request (using If-Modified-Since or ETag) and the resource has not changed. No response body is returned — the client uses its cached copy.
307 Temporary Redirect
Similar to 302, but the client must use the same HTTP method for the redirected request. A POST to a 307-redirected URL must POST to the new URL, not GET.
308 Permanent Redirect
Like 301, but the HTTP method must not change. A POST to a 308-redirected URL must POST to the new URL.
4xx — Client Errors
Client errors indicate the request contains bad syntax, is missing required data, or cannot be fulfilled for a reason attributable to the client.
400 Bad Request
The server cannot process the request due to malformed syntax, invalid data, or missing required fields. Return a clear error message explaining what is wrong so the client can fix it.
POST /users
HTTP/1.1 400 Bad Request
{ "error": "email is required" }
401 Unauthorized
Despite the name, this code means unauthenticated — the client has not provided valid credentials. The client should authenticate and retry. Do not use this to indicate insufficient permissions (use 403 for that).
GET /account
HTTP/1.1 401 Unauthorized
{ "error": "Authentication required" }
403 Forbidden
The client is authenticated but does not have permission to access the resource. Unlike 401, re-authenticating will not help. This is the correct code for authorisation failures.
404 Not Found
The requested resource does not exist on the server. Also used to deliberately hide the existence of a resource that the client is not authorised to know about (instead of returning 403).
GET /users/9999
HTTP/1.1 404 Not Found
{ "error": "User not found" }
405 Method Not Allowed
The HTTP method used is not supported for this endpoint. For example, sending a DELETE request to an endpoint that only supports GET and POST. The response should include an Allow header listing permitted methods.
409 Conflict
The request conflicts with the current state of the resource. Commonly returned when trying to create a resource that already exists — for example, registering with an email address that is already in use.
POST /users
HTTP/1.1 409 Conflict
{ "error": "An account with this email already exists" }
410 Gone
The resource has been permanently deleted and will not be available again. Unlike 404, this explicitly tells the client the resource previously existed. Useful for deprecated API versions.
422 Unprocessable Entity
The request was well-formed but failed validation. Use this when the syntax is correct but the semantic content is invalid — for example, a valid JSON body that fails business logic validation.
POST /orders
HTTP/1.1 422 Unprocessable Entity
{
"errors": {
"quantity": "must be greater than 0",
"shippingAddress": "is required"
}
}
429 Too Many Requests
The client has sent too many requests in a given time period (rate limiting). The response should include a Retry-After header indicating when the client can try again.
HTTP/1.1 429 Too Many Requests
Retry-After: 60
{ "error": "Rate limit exceeded. Try again in 60 seconds." }
5xx — Server Errors
Server errors indicate the server failed to fulfil a valid request. These are never the client's fault.
500 Internal Server Error
A generic catch-all error for unexpected server failures. Use this when something goes wrong that does not fit a more specific 5xx code. Never expose stack traces or internal error details in the response body — log them server-side instead.
501 Not Implemented
The server does not support the functionality required to fulfil the request. Often returned when a client uses an HTTP method the server does not support at all (different from 405, which is per-endpoint).
502 Bad Gateway
The server, acting as a gateway or proxy, received an invalid response from an upstream server. Common in microservice architectures when a downstream service is unavailable or returns garbage.
503 Service Unavailable
The server is temporarily unable to handle the request due to overload or maintenance. Should include a Retry-After header when the outage duration is known.
504 Gateway Timeout
The server, acting as a gateway, did not receive a timely response from an upstream server. Common when a downstream service is too slow to respond within the timeout window.
Cheat Sheet: Most Common Status Codes
| Code | Name | When to Use |
|---|---|---|
| 200 | OK | Successful GET, PUT, PATCH |
| 201 | Created | Successful POST that creates a resource |
| 204 | No Content | Successful DELETE or update with no body |
| 400 | Bad Request | Invalid input or missing required fields |
| 401 | Unauthorized | Not authenticated |
| 403 | Forbidden | Authenticated but not authorised |
| 404 | Not Found | Resource does not exist |
| 409 | Conflict | Duplicate resource |
| 422 | Unprocessable Entity | Validation errors |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Unexpected server failure |
| 503 | Service Unavailable | Server down or overloaded |
Common Mistakes to Avoid
- Returning 200 for errors — Never put an error message inside a 200 response. Status codes exist precisely so clients do not have to parse the body to detect failures.
- Confusing 401 and 403 — 401 means "you are not logged in." 403 means "you are logged in but not allowed." They require different client behaviour.
- Using 400 for everything — Use 409 for conflicts, 422 for validation errors, and 404 for missing resources instead of defaulting to 400 for all failures.
- Exposing internals in 500 responses — Log the full error server-side; return only a safe, generic message to the client.
Conclusion
HTTP status codes are the universal language of the web. Using them correctly makes your API self-documenting, enables automatic error handling in client code, and signals professionalism to every developer who consumes your service.
When building or testing an API, mock your error responses too — not just the happy path. Create a free mock API on Mockable to simulate any status code and test how your application handles each one.