Every single HTTP response includes a status code — a 3-digit number that tells the client exactly what happened with their request. Did it succeed? Was the resource moved? Was there an authentication problem? Did the server crash? Status codes answer all of these questions instantly, without the client needing to parse the response body.
This guide covers every important HTTP status code with real-world explanations, REST API best practices, common mistakes, and a decision guide for choosing the right code. Whether you're building APIs, debugging network issues, or preparing for interviews — this is your complete reference.
What Are HTTP Status Codes?
An HTTP status code is a standardized number that the server includes in the first line of every response. It immediately tells the client the outcome of the request before they even look at the body. The status line looks like this:
HTTP/1.1 200 OK
^^^ ^^
| └── Reason phrase (human-readable, optional)
└─────── Status code (machine-readable, always 3 digits)The first digit defines the category. You can immediately tell the general outcome by looking at just the first digit: 2 = success, 3 = redirect, 4 = client error, 5 = server error.
Status Code Categories
| Range | Category | Meaning | Examples |
|---|---|---|---|
| 1xx | Informational | Request received, processing continues | 100 Continue, 101 Switching Protocols |
| 2xx | Success | Request was successful | 200 OK, 201 Created, 204 No Content |
| 3xx | Redirection | Further action needed (different URL) | 301 Moved, 302 Found, 304 Not Modified |
| 4xx | Client Error | Problem with the request from client | 400 Bad Request, 401, 403, 404, 422 |
| 5xx | Server Error | Server failed to fulfill valid request | 500 Internal Error, 502, 503, 504 |
2xx Success Codes
These codes indicate the request was received, understood, and processed successfully.
200 OK
The request succeeded. The most common status code — used for successful GET, PUT, and PATCH requests. The response body contains the requested data or confirmation of the action.
Use when: GET returns data, PUT/PATCH updates succeed, any successful operation with a response body.
201 Created
A new resource was successfully created. Should always be returned for successful POST requests that create something. The response should include the created resource (or at minimum its ID and location).
Use when: POST creates a new user, order, post, file, or any new entity. Include a Location header pointing to the new resource.
204 No Content
The request succeeded but there is nothing to return. The response has no body. Used for DELETE operations and updates where the client doesn't need confirmation data.
Use when: DELETE removes a resource successfully, PUT updates but client doesn't need the updated object back.
206 Partial Content
Only part of the resource is returned, based on the Range header in the request. Used for video streaming, file downloads that can be resumed, and pagination of binary content.
Use when: Client requests a byte range (video seeking, resumable downloads).
3xx Redirection Codes
These codes tell the client to look elsewhere — the resource has moved or can be found at a different URL.
301 Moved Permanently
The resource has permanently moved to a new URL. Browsers and search engines update their records. All future requests should use the new URL. SEO value transfers to the new URL.
Use when: Domain change, URL restructuring, www to non-www redirect. Search engines transfer ranking to the new URL.
302 Found (Temporary Redirect)
The resource is temporarily at a different URL. The original URL is still the canonical version. Search engines keep indexing the original URL.
Use when: Temporary maintenance page, A/B testing, geolocation-based redirect. The original URL should still be bookmarked.
304 Not Modified
The resource hasn't changed since the client's last request. The browser should use its cached version. No body is sent — saves bandwidth significantly. Works with ETag/If-None-Match and Last-Modified/If-Modified-Since headers.
Use when: Client sends conditional request (If-None-Match with ETag) and the content is unchanged.
307 Temporary Redirect (preserves method)
Like 302, but guarantees the HTTP method is preserved. A POST to the original URL will remain a POST to the new URL. 302 historically could change POST to GET in some browsers.
Use when: Temporary redirect of API endpoints where you need to preserve the HTTP method (POST stays POST).
4xx Client Error Codes
These indicate something is wrong with the request — the client needs to fix it before retrying.
400 Bad Request
The server cannot understand the request due to malformed syntax. The JSON is invalid, required parameters are missing, or the request structure is wrong. The client should not retry without modifications.
Use when: Invalid JSON body, missing required query parameters, malformed URL, wrong data types.
401 Unauthorized (Unauthenticated)
The request requires authentication but none was provided, or the credentials are invalid. Despite the name "Unauthorized," it actually means "unauthenticated" — the server doesn't know who you are.
Use when: No token provided, expired token, invalid credentials. Client should login or refresh their token.
403 Forbidden
The server knows who you are (authenticated) but you do not have permission to access this resource. Unlike 401, re-authenticating won't help — you simply don't have the required role or permission.
Use when: Authenticated user tries to access admin-only resource, user tries to edit another user's data, insufficient role/permission.
404 Not Found
The server cannot find the requested resource. The URL may be wrong, the resource may have been deleted, or it never existed. The most recognized error code on the internet.
Use when: GET /users/99999 where user doesn't exist, wrong URL path, deleted resource. Some APIs use 404 instead of 403 to hide the existence of resources (security through obscurity).
409 Conflict
The request conflicts with the current state of the server. Most commonly: trying to create a resource that already exists (duplicate email, username taken) or concurrent edit conflicts.
Use when: Duplicate unique field (email already registered), optimistic locking conflict, resource state prevents the action.
422 Unprocessable Content
The server understands the content type and syntax (valid JSON), but cannot process the data due to semantic/validation errors. The most appropriate code for form validation failures in APIs.
Use when: Email format invalid, password too short, age is negative, required business rules not met. Include error details in the response body.
429 Too Many Requests
The client has sent too many requests in a given time period (rate limited). The server should include a Retry-After header indicating when the client can try again.
Use when: Rate limit exceeded, API quota reached. Include Retry-After header. Client should implement exponential backoff.
5xx Server Error Codes
These indicate the server failed to fulfill a valid request. The problem is on the server side — the client did nothing wrong.
500 Internal Server Error
A generic "something crashed" error. The server encountered an unexpected condition that prevented it from fulfilling the request. Usually caused by unhandled exceptions, null pointer errors, or database connection failures.
When you see it: Bug in server code, uncaught exception, database down. Never expose error details to the client in production — log them server-side.
502 Bad Gateway
The server (acting as a gateway/proxy) received an invalid response from the upstream server. Your Nginx/load balancer is running, but the application server behind it is down or returning garbage.
When you see it: Backend app crashed but reverse proxy (Nginx) is still running, upstream timeout, Docker container restarting.
503 Service Unavailable
The server is temporarily unable to handle requests. Usually due to maintenance, overload, or the server starting up. Should include a Retry-After header indicating when to try again.
When you see it: Planned maintenance, server overloaded, auto-scaling hasn't caught up with traffic spike, health check failing.
504 Gateway Timeout
The server (acting as a gateway) did not receive a timely response from the upstream server. The backend is taking too long — perhaps a slow database query, infinite loop, or network issue between services.
When you see it: Slow database query exceeds proxy timeout, upstream service hanging, network partition between services.
Status Code Decision Guide for REST APIs
Use this as a quick reference when building API endpoints:
| Scenario | Status Code | Example |
|---|---|---|
| GET succeeds, returning data | 200 OK | GET /users → list of users |
| POST creates a new resource | 201 Created | POST /users → new user created |
| DELETE succeeds, nothing to return | 204 No Content | DELETE /users/123 → user removed |
| PUT/PATCH update succeeds | 200 OK | PUT /users/123 → updated user returned |
| Resource permanently moved | 301 Moved | Old URL → new URL (SEO transfer) |
| Resource not changed (cached) | 304 Not Modified | Browser uses cached version |
| Invalid request body (bad JSON) | 400 Bad Request | Malformed JSON, wrong types |
| No authentication provided | 401 Unauthorized | Missing or expired token |
| Authenticated but no permission | 403 Forbidden | User can't access admin route |
| Resource doesn't exist | 404 Not Found | GET /users/99999 (no such user) |
| Duplicate resource conflict | 409 Conflict | Email already registered |
| Validation fails (business rules) | 422 Unprocessable | Invalid email format, password too short |
| Too many requests (rate limit) | 429 Too Many Requests | Client exceeded 100 req/min |
| Server bug or crash | 500 Internal Error | Unhandled exception in code |
| Upstream server down | 502 Bad Gateway | App server crashed behind Nginx |
| Server temporarily unavailable | 503 Service Unavailable | Maintenance mode, overloaded |
Common Developer Mistakes
⚠️ Returning 200 for everything (even errors)
Some APIs return 200 with {error: 'Not found'} in the body. This breaks client error handling — fetch() won't throw, Axios won't catch it. Clients rely on status codes for error detection. Always use proper codes.
✅ Fix: Use 4xx for client errors, 5xx for server errors. Reserve 200 for actual success.
⚠️ Using 500 for validation errors
Validation failures are not server crashes — they are client errors (the client sent bad data). Returning 500 makes it impossible to distinguish between 'your input is wrong' and 'our server is broken'.
✅ Fix: Use 400 for malformed requests, 422 for validation failures. Reserve 500 for unexpected server errors.
⚠️ Returning 404 when you mean 403
If a user requests a resource they can't access, returning 404 ('not found') instead of 403 ('forbidden') confuses the client — they'll think the URL is wrong instead of realizing they need different permissions.
✅ Fix: Use 403 when the user is authenticated but lacks permission. Use 404 only when the resource genuinely doesn't exist. (Exception: use 404 to hide resource existence for security-sensitive APIs.)
⚠️ Using 302 instead of 301 for permanent moves
After a domain change or URL restructuring, using 302 (temporary) instead of 301 (permanent) means search engines don't transfer SEO ranking to the new URL. Your old URLs keep ranking while new ones get no credit.
✅ Fix: Use 301 for permanent URL changes. Use 302 only for genuinely temporary redirects (maintenance, A/B tests).
⚠️ Not returning 201 for POST creation
Returning 200 after creating a new resource loses valuable semantic information. Clients can't reliably distinguish 'updated' from 'created' if both return 200.
✅ Fix: Always return 201 Created for successful POST requests that create a new resource. Include a Location header with the new resource's URL.
⚠️ Returning 200 with empty body instead of 204
A 200 with an empty body is ambiguous — did the operation succeed with no data, or did something go wrong? 204 explicitly says 'success, and I intentionally have nothing to send you'.
✅ Fix: Use 204 No Content for DELETE operations and updates where no response body is needed.
Interview Questions
Q: What is the difference between 401 and 403?
A: 401 = not authenticated (provide credentials). 403 = authenticated but not authorized (you don't have permission). 401 means 'who are you?', 403 means 'I know who you are, but you can't do this'.
Q: What is the difference between 301 and 302?
A: 301 = permanent redirect (SEO transfers, browsers cache it forever). 302 = temporary redirect (SEO stays with original, browser re-checks next time).
Q: When should you use 201 instead of 200?
A: Use 201 when a POST request successfully creates a new resource. 200 is for general success (GET, PUT). 201 specifically signals 'a new entity now exists that didn't before'.
Q: What is 422 and when do you use it?
A: 422 Unprocessable Content — the request is syntactically valid (good JSON) but semantically invalid (fails business validation like invalid email format). Use it for form/input validation errors.
Q: 500 vs 502 vs 503 — what's the difference?
A: 500 = your application code crashed. 502 = your reverse proxy/gateway is fine but the app behind it is down. 503 = server is temporarily unavailable (maintenance/overload). 504 = gateway timeout (upstream too slow).
Q: What does 304 Not Modified mean?
A: The resource hasn't changed. The browser sent a conditional request (with If-None-Match/ETag), and the server confirmed the cached version is still current. No body is returned — browser uses its cache.
Q: What is 429 and how should clients handle it?
A: 429 = rate limited (too many requests). Clients should read the Retry-After header, wait the specified time, then retry. Implement exponential backoff for repeated 429s.
Q: Why should APIs never return 200 for errors?
A: HTTP clients use status codes for error detection. fetch() only rejects on network errors, but response.ok checks the status. Axios throws on 4xx/5xx. If you return 200 with an error body, client error handling breaks.
Complete HTTP Status Code Cheat Sheet
Quick reference for all important codes by category:
| Code | Name | When to use |
|---|---|---|
| 100 | Continue | Large request body — server says 'go ahead' |
| 101 | Switching Protocols | WebSocket upgrade |
| 200 | OK | Successful GET, PUT, PATCH |
| 201 | Created | Successful POST that creates resource |
| 202 | Accepted | Request queued for async processing |
| 204 | No Content | Successful DELETE, nothing to return |
| 206 | Partial Content | Range request (video streaming) |
| 301 | Moved Permanently | Permanent URL change (SEO transfers) |
| 302 | Found | Temporary redirect |
| 304 | Not Modified | Cached version is still valid |
| 307 | Temporary Redirect | Like 302 but preserves HTTP method |
| 308 | Permanent Redirect | Like 301 but preserves HTTP method |
| 400 | Bad Request | Malformed request syntax |
| 401 | Unauthorized | Not authenticated |
| 403 | Forbidden | Authenticated but no permission |
| 404 | Not Found | Resource doesn't exist |
| 405 | Method Not Allowed | Wrong HTTP method for endpoint |
| 409 | Conflict | Duplicate resource, state conflict |
| 410 | Gone | Resource permanently deleted (vs 404 which might return) |
| 413 | Payload Too Large | Request body exceeds server limit |
| 415 | Unsupported Media Type | Wrong Content-Type |
| 418 | I'm a Teapot | Easter egg (RFC 2324, for fun) |
| 422 | Unprocessable Content | Validation failed |
| 429 | Too Many Requests | Rate limit exceeded |
| 451 | Unavailable for Legal Reasons | Censored/blocked content |
| 500 | Internal Server Error | Server bug/crash |
| 501 | Not Implemented | Feature not supported yet |
| 502 | Bad Gateway | Upstream server returned bad response |
| 503 | Service Unavailable | Server temporarily down |
| 504 | Gateway Timeout | Upstream server too slow |
Frequently Asked Questions
What is an HTTP status code?
What is the most common HTTP status code?
What does 404 Not Found mean?
What is the difference between 401 and 403?
What does 500 Internal Server Error mean?
What is 301 vs 302 redirect?
What is 429 Too Many Requests?
Why is 304 Not Modified important?
When should a REST API return 201 vs 200?
What is 422 Unprocessable Content?
Related Articles & Tools
Conclusion
HTTP status codes are the language of the web — they instantly communicate the outcome of every request without requiring the client to parse response bodies. Using the correct status code is not optional — it is how clients, browsers, proxies, and monitoring tools understand what happened.
The essential codes every developer must know: 200 (success), 201 (created), 204 (no content), 301 (permanent redirect), 304 (not modified), 400 (bad request), 401 (unauthenticated), 403 (forbidden), 404 (not found), 422 (validation failed), 429 (rate limited), 500 (server error), and 503 (service unavailable). Master these 13 codes and you can handle 99% of real-world situations.
Build APIs that use proper status codes from day one — your frontend developers, mobile developers, and future self will thank you when debugging at 2 AM.
