HTTP Status Codes: Complete Reference Guide (2026)
HTTP status codes are the language servers use to tell clients what happened to their request. Choosing the right code matters for caching behavior, SEO, client side error handling, and API usability. This complete reference covers every code class with examples and the right code for every scenario.
How HTTP Status Codes Work
Every HTTP response begins with a three-digit status code. The first digit defines the class of response:
- 1xx - Informational: Request received, processing continues
- 2xx - Success: Request was received, understood, and accepted
- 3xx - Redirection: Further action 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 an apparently valid request
Understanding which code to return - and which code you are receiving - is fundamental to building and consuming APIs correctly.
1xx: Informational
Informational codes are rarely seen directly by application developers. They are used during protocol negotiation.
100 Continue
The server has received the request headers and the client should proceed to send the request body. Used when the client sends Expect: 100-continue before sending a large request body, allowing the server to reject it early (e.g., if authentication fails) before the body is transmitted.
101 Switching Protocols
The server agrees to switch protocols as requested by the client. Used when upgrading from HTTP/1.1 to WebSockets:
Request: Upgrade: websocket, Connection: Upgrade
Response: HTTP/1.1 101 Switching Protocols
103 Early Hints
A relatively new code (RFC 8297) that allows the server to send preliminary headers before the final response. Used to push Link headers for resource preloading while the server is still processing the main response, improving page load performance.
2xx: Success
200 OK
The most common success code. The request succeeded and the response body contains the result. Used for successful GET, POST (when not creating a resource), PUT, and PATCH responses.
GET /api/users/42 → 200 OK + user object
POST /api/search → 200 OK + search results
201 Created
A new resource was successfully created as a result of the request. The Location header should point to the URL of the new resource.
POST /api/users → 201 Created
Location: /api/users/43
Use 201 instead of 200 for POST requests that create resources. This distinction matters for RESTful API design and allows clients to distinguish between "action completed" and "resource created."
202 Accepted
The request has been accepted for processing, but processing has not been completed. Used for asynchronous operations where the work is queued and will be done later.
POST /api/reports/generate → 202 Accepted
{ "jobId": "abc123", "statusUrl": "/api/jobs/abc123" }
204 No Content
The request succeeded but there is no content to send in the response body. Used for DELETE requests, CORS preflight OPTIONS responses, and actions that do not return data.
DELETE /api/users/42 → 204 No Content (no body)
OPTIONS /api/data → 204 No Content (CORS preflight)
206 Partial Content
The server is delivering only part of the resource due to a range request. Used for resumable downloads, video streaming, and chunked file transfers.
Request: Range: bytes=0-1023
Response: HTTP/1.1 206 Partial Content
Content-Range: bytes 0-1023/146515
3xx: Redirection
301 Moved Permanently
The resource has been permanently moved to a new URL. Browsers and search engines update their records. The client should use the new URL for all future requests. Pass link equity in SEO.
HTTP/1.1 301 Moved Permanently
Location: https://www.example.com/new-path
Important: Browsers cache 301 responses aggressively. If you redirect incorrectly and later need to change it, users may have the old redirect cached until they clear their browser cache.
302 Found (Temporary Redirect)
The resource is temporarily at a different URL. The original URL should continue to be used for future requests. Browsers do not cache 302 responses. Often misused when a 301 is more appropriate.
303 See Other
The response to the request can be found at a different URI and should be retrieved using a GET request. Used after a POST/PUT/DELETE to redirect the client to a confirmation page, preventing the browser from resubmitting the form on reload (the Post-Redirect-Get pattern).
304 Not Modified
The resource has not been modified since the version specified by the request headers (If-Modified-Since or If-None-Match). The client should use its cached version. No response body is sent, saving bandwidth.
307 Temporary Redirect
Like 302, but explicitly guarantees that the HTTP method will not change. A POST to a URL redirected with 307 will result in a POST to the new URL. With 302, some older clients changed POST to GET on redirect.
308 Permanent Redirect
Like 301, but explicitly preserves the HTTP method. The modern replacement for 301 when you need to permanently redirect non-GET requests and ensure the method is preserved.
Look Up Any HTTP Status Code Instantly
Use our free HTTP Status Codes tool for a searchable, interactive reference. Find any code, understand its meaning, and see examples - all without leaving your browser.
Open HTTP Status Codes Tool4xx: Client Errors
4xx codes indicate the client made an error. The request cannot be fulfilled due to something the client did or did not do correctly.
400 Bad Request
The server cannot process the request due to a client error: malformed request syntax, invalid request parameters, deceptive request routing, or invalid JSON body. Include a descriptive error message in the response body.
POST /api/users
{ "email": "not-an-email" }
→ 400 Bad Request
{ "error": "Invalid email format", "field": "email" }
401 Unauthorized
The request requires authentication. Despite the name "Unauthorized," this code actually means unauthenticated - the client has not provided valid credentials. The response should include a WWW-Authenticate header indicating how to authenticate.
→ 401 Unauthorized
WWW-Authenticate: Bearer realm="api"
{ "error": "Authentication required" }
403 Forbidden
The server understood the request and the client is authenticated, but the client does not have permission to access the resource. Unlike 401, re-authenticating will not help - the user simply lacks the required permissions.
GET /api/admin/users (logged in as a non-admin user)
→ 403 Forbidden
{ "error": "Insufficient permissions" }
401 vs 403: Use 401 when the user is not logged in or their token is invalid. Use 403 when the user is logged in but does not have permission for this action.
404 Not Found
The server cannot find the requested resource. The URL does not exist. Also used to hide the existence of a resource from unauthorized users (instead of returning 403, which reveals the resource exists).
405 Method Not Allowed
The HTTP method used is not supported for the requested resource. The response must include an Allow header listing permitted methods.
DELETE /api/users (DELETE not supported on collection endpoint)
→ 405 Method Not Allowed
Allow: GET, POST
408 Request Timeout
The server timed out waiting for the request. The client can resend the request. Different from a network timeout on the client side - this is the server saying "I gave up waiting for you."
409 Conflict
The request could not be completed due to a conflict with the current state of the resource. Common uses: trying to create a resource that already exists, optimistic concurrency failures, or duplicate unique constraints.
POST /api/users
{ "email": "existing@example.com" }
→ 409 Conflict
{ "error": "Email already registered" }
410 Gone
The resource previously existed but has been permanently deleted and will not be available again. Unlike 404 (which could be temporary), 410 tells search engines to remove the URL from their index.
422 Unprocessable Entity
The request was well-formed (valid JSON, correct content type) but contained semantic errors. Used by many REST APIs for validation failures where the input is syntactically correct but logically invalid.
POST /api/orders
{ "quantity": -5 }
→ 422 Unprocessable Entity
{ "errors": [{ "field": "quantity", "message": "Must be greater than 0" }] }
429 Too Many Requests
The client has sent too many requests in a given time period. Used for rate limiting. The response should include a Retry-After header and ideally X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers.
→ 429 Too Many Requests
Retry-After: 60
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1711468800
5xx: Server Errors
5xx codes indicate the server failed to fulfil a valid request. These errors are the server's fault, not the client's.
500 Internal Server Error
A generic error indicating the server encountered an unexpected condition. This is the catch-all for unhandled exceptions. Never expose stack traces or internal error details to clients in production - log them internally and return a generic message.
→ 500 Internal Server Error
{ "error": "An unexpected error occurred", "requestId": "req_abc123" }
501 Not Implemented
The server does not support the functionality required to fulfil the request. Used when the request method is not supported at all (not for a specific resource, but globally). Rarely used in practice.
502 Bad Gateway
The server, while acting as a gateway or proxy, received an invalid response from an upstream server. Common with Nginx/Apache proxies when the application server (Node.js, Python, PHP-FPM) crashes, returns a non-HTTP response, or times out. Check your application server logs when you see 502.
503 Service Unavailable
The server is temporarily unable to handle the request, typically due to overload or maintenance. Should include a Retry-After header when the duration of unavailability is known.
→ 503 Service Unavailable
Retry-After: 3600
{ "error": "Service in maintenance until 14:00 UTC" }
504 Gateway Timeout
The server, acting as a gateway, did not receive a timely response from an upstream server. Similar to 502 but specifically a timeout rather than an invalid response. Common when application servers or database queries take longer than the proxy's timeout window.
507 Insufficient Storage
The server cannot store the representation needed to complete the request. Used in WebDAV and file storage APIs when disk space is exhausted.
Choosing the Right Status Code for REST APIs
A quick decision guide for common REST API operations:
- GET /resources - 200 (success), 404 if collection does not exist (rare)
- GET /resources/:id - 200 (found), 404 (not found)
- POST /resources - 201 (created), 400 (invalid input), 409 (already exists), 422 (validation error)
- PUT /resources/:id - 200 (updated, returns resource), 204 (updated, no content), 400/422 (validation), 404 (not found)
- PATCH /resources/:id - same as PUT
- DELETE /resources/:id - 204 (deleted), 404 (not found), 409 (conflict, e.g. has dependencies)
- Authentication failures - 401 (not authenticated), 403 (authenticated but no permission)
- Rate limiting - 429 (with Retry-After)
- Unhandled exceptions - 500 (with request ID for log lookup)
Frequently Asked Questions
What is the difference between 401 and 403?
401 Unauthorized means the request lacks valid authentication credentials. The user is not logged in, their token is expired, or their credentials are invalid. The solution is to authenticate (log in again, refresh the token). 403 Forbidden means the user is authenticated (we know who they are) but they do not have permission to perform the requested action. Re-authenticating will not help. The solution is to grant the user the required role or permission. A common mistake is returning 403 when the user is not logged in - that should be 401.
When should I use 404 vs. 410?
Use 404 when you do not know if the resource ever existed, or when a resource is temporarily unavailable. Use 410 when you know the resource previously existed and has been permanently deleted and will not be returning. The practical difference is for SEO: search engines treat 404 as potentially temporary and may keep the URL indexed. A 410 signals permanent deletion and search engines will remove the URL from their index faster.
Should I use 400 or 422 for validation errors?
400 is for malformed requests - the request body is not valid JSON, a required header is missing, or the request structure is fundamentally wrong. 422 is for semantically invalid requests - the JSON is valid, the structure is correct, but the values fail business validation (e.g., a date in the past, a negative quantity, an email that does not match an account). Many modern APIs use 422 exclusively for validation errors because it is more specific. Either is acceptable as long as you include a descriptive error body.
What causes a 502 Bad Gateway?
A 502 means your proxy/load balancer (Nginx, Apache, AWS ALB) received an invalid response from the upstream application server. Common causes: (1) The application server process crashed or is not running. (2) The application server returned a non-HTTP response (e.g., a PHP fatal error with output before headers). (3) The application server's port is not accessible from the proxy. (4) A middleware layer returned an invalid response. Start debugging by checking your application server logs, not the proxy logs.
Is it bad to always return 200 with an error field in the body?
Yes - this anti-pattern (sometimes called "200 OK with errors") breaks HTTP semantics. Clients, proxies, CDNs, and monitoring tools all rely on status codes to understand what happened. A 200 response gets cached by CDNs and proxies. It does not trigger client side error handling in libraries like Axios or fetch (which only reject on 4xx/5xx). And it makes debugging much harder because monitoring tools cannot alert on error rates from HTTP codes. Always use the appropriate 4xx or 5xx code for error conditions.
What HTTP status code should I return for a rate limit exceeded?
Always return 429 Too Many Requests. Include a Retry-After header (seconds until the client can retry, or an HTTP date), and ideally include X-RateLimit-Limit (total allowed requests), X-RateLimit-Remaining (requests left in the window), and X-RateLimit-Reset (Unix timestamp when the window resets). Well-behaved clients will read these headers and back off automatically. Using 503 for rate limiting is incorrect - 503 means the server is down, which may trigger more aggressive retry behavior from clients.
The Bottom Line
HTTP status codes are a contract between your server and its clients. Using the right code for every scenario makes your API self-documenting, enables clients to handle errors gracefully without parsing the body, works correctly with CDN caching rules, and produces meaningful metrics in your monitoring dashboards. The most important codes to get right are 200 vs. 201 (success vs. created), 401 vs. 403 (unauthenticated vs. unauthorized), 400 vs. 422 (malformed vs. semantically invalid), and 500 vs. 503 (crash vs. temporary unavailability).
Use our free interactive tool to look up any status code instantly - open the HTTP Status Codes tool here. For related reading, see our guide on CORS errors and how to fix them.
Usman has 10+ years of experience securing enterprise infrastructure, managing high-traffic servers, and building zero-knowledge security tools. Read more about the author.