REST API HTTP Status Codes
Every HTTP response includes a status code — a three-digit number that tells the client whether the request succeeded, failed, or requires further action. Status codes are like traffic lights for API communication: they guide the client on what to do next.
Using the correct status code is essential. A wrong status code misleads the client and makes debugging painful.
The Five Status Code Categories
┌──────────────┬─────────────────────────────────────────────────────┐ │ Range │ Meaning │ ├──────────────┼─────────────────────────────────────────────────────┤ │ 1xx │ Informational – request received, still processing │ │ 2xx │ Success – the request worked │ │ 3xx │ Redirection – look elsewhere │ │ 4xx │ Client Error – you sent something wrong │ │ 5xx │ Server Error – we broke something on our end │ └──────────────┴─────────────────────────────────────────────────────┘
The first digit tells you the category. The remaining two digits give the specific code within that category.
2xx: Success Codes
These codes mean the request worked. Each 2xx code communicates a slightly different type of success.
┌───────┬──────────────────┬──────────────────────────────────────────┐ │ Code │ Name │ When to use │ ├───────┼──────────────────┼──────────────────────────────────────────┤ │ 200 │ OK │ GET, PUT, PATCH succeeded │ │ 201 │ Created │ POST created a new resource │ │ 202 │ Accepted │ Request accepted but processing later │ │ 204 │ No Content │ DELETE succeeded; no body to return │ └───────┴──────────────────┴──────────────────────────────────────────┘ Examples: GET /products/1 → 200 OK + product data in body POST /products → 201 Created + new product in body DELETE /products/1 → 204 No Content (empty body)
3xx: Redirection Codes
These codes tell the client to go to a different URL. They appear most often when a resource has moved.
┌───────┬────────────────────┬────────────────────────────────────────┐ │ Code │ Name │ When to use │ ├───────┼────────────────────┼────────────────────────────────────────┤ │ 301 │ Moved Permanently │ Resource has a new permanent URL │ │ 302 │ Found │ Temporary redirect │ │ 304 │ Not Modified │ Cached version is still valid │ └───────┴────────────────────┴────────────────────────────────────────┘ Example — API version migration: GET /api/v1/users → 301 Moved Permanently Location: /api/v2/users
4xx: Client Error Codes
The client sent something wrong. The problem is on the client's side — a typo in the URL, missing credentials, or sending the wrong data format.
┌───────┬──────────────────────┬──────────────────────────────────────┐ │ Code │ Name │ When to use │ ├───────┼──────────────────────┼──────────────────────────────────────┤ │ 400 │ Bad Request │ Invalid data sent in request body │ │ 401 │ Unauthorized │ No credentials or invalid token │ │ 403 │ Forbidden │ Valid credentials but no permission │ │ 404 │ Not Found │ Resource does not exist │ │ 405 │ Method Not Allowed │ Used wrong HTTP method on URL │ │ 409 │ Conflict │ Duplicate data or state conflict │ │ 422 │ Unprocessable │ Data is valid JSON but fails rules │ │ 429 │ Too Many Requests │ Rate limit exceeded │ └───────┴──────────────────────┴──────────────────────────────────────┘
401 vs 403: A Common Confusion
401 Unauthorized: Client has no credentials or provided wrong ones. "Who are you? Please log in." 403 Forbidden: Client is logged in, but not allowed to access this. "I know who you are, but you cannot do this." Example: GET /admin/users without a token → 401 GET /admin/users with a user token → 403 (only admins allowed)
5xx: Server Error Codes
The server made a mistake. The client sent a valid request, but something went wrong internally on the server.
┌───────┬──────────────────────────┬──────────────────────────────────┐
│ Code │ Name │ When to use │
├───────┼──────────────────────────┼──────────────────────────────────┤
│ 500 │ Internal Server Error │ Unexpected crash or bug │
│ 502 │ Bad Gateway │ Upstream service returned error │
│ 503 │ Service Unavailable │ Server is down or overloaded │
│ 504 │ Gateway Timeout │ Upstream service took too long │
└───────┴──────────────────────────┴──────────────────────────────────┘
Rule: Never return 500 for something the client did wrong.
Never return 400 for something your server broke.
Status Codes Mapped to API Actions
Action │ Happy Path │ Common Error ────────────────────────────────────┼──────────────┼─────────────── GET /products/42 (exists) │ 200 OK │ 404 Not Found GET /products/42 (no auth) │ — │ 401 POST /products (valid data) │ 201 Created │ 400 Bad Request POST /products (duplicate) │ — │ 409 Conflict PUT /products/42 (invalid fields) │ 200 OK │ 422 Unprocessable DELETE /products/42 (exists) │204 No Content│ 404 Not Found POST /products (rate limit hit) │ — │ 429 Too Many Requests
The Golden Rule of Status Codes
Never return 200 OK for an error. Some APIs do this and include an error message in the body. This is wrong. It breaks every client that checks the status code to determine success or failure — which is all of them.
❌ Wrong:
HTTP 200 OK
{ "error": "User not found" }
✅ Correct:
HTTP 404 Not Found
{ "error": "User not found", "code": "USER_NOT_FOUND" }
Key Points
- 2xx = success, 3xx = redirect, 4xx = client error, 5xx = server error
- Use 201 for successful POST and 204 for successful DELETE
- 401 means "who are you?" — 403 means "I know you but you cannot do this"
- Never return 200 OK when an error occurred
- Status codes are the first signal clients read — use them accurately
