HTTP Status Codes — The Complete Developer Reference Guide
Every status code explained clearly, with causes, practical handling guidance, and a complete quick-reference table. Bookmark this page and never wonder what a status code means again.
HTTP status codes are the first thing an API response tells you. Before the response body, before the headers, before the data, the status code tells you whether the request worked, failed, or needs something. Understanding every code makes debugging faster, API integration more reliable, and production issues easier to diagnose.
How Status Codes Are Structured
Status codes are three-digit numbers grouped into five categories by their first digit. The first digit tells you the category immediately, before you even read the specific code:
2xx — Success Codes
Every 2xx response means the request was received, understood, and accepted. Different codes in this range communicate different kinds of success:
The most common success response. The request worked and the response body contains the requested data. For GET requests the body contains the resource. For POST requests that do not create a new resource, the body contains the result of the operation.
- Successful GET request
- Successful POST that returns data
- Successful PUT returning updated resource
- Validate the response structure
- Check for nullable fields
- Never assume 200 = correct data shape
A POST request succeeded and a new resource was created. The response typically includes the newly created resource in the body and a Location header pointing to the URL of the new resource.
- Successful POST creating a new resource
- Store the new resource ID from the response
- Check the Location header for the resource URL
The request has been received but processing has not completed yet. Used for asynchronous operations: the server accepted the task and will process it in the background. You typically receive a job ID or polling URL to check the result later.
- Long-running background jobs
- Email or report generation requests
- Batch processing operations
- Poll the provided URL to check status
- Implement a status-checking loop with delays
Success, but there is nothing to return. The most common response for DELETE requests: the operation succeeded but there is no body to send back because the resource no longer exists.
- Successful DELETE request
- Successful PUT with no return body
- Do not attempt to parse a response body
- Treat as confirmed success and update your UI
The server is returning only part of the resource as requested. Used for large file downloads that support resumable transfers or range requests. The Content-Range header indicates which part of the resource is being returned.
- Resumable file downloads
- Video streaming with range requests
- Check Content-Range header for byte range
- Append to existing downloaded data
3xx — Redirection Codes
Redirection codes tell the client that further action is needed. The resource has moved or the client should look elsewhere. Browsers handle most of these automatically, but API integrations need to handle them explicitly:
The resource has permanently moved to a new URL specified in the Location header. Browsers and search engines update to the new URL. SEO link equity transfers to the new location. Used for permanent URL changes.
- Permanent URL restructuring
- HTTP to HTTPS migration
- Domain changes
- Update all references to use the new URL
- Update bookmarks and internal links
The resource is temporarily at a different URL. The original URL should continue to be used for future requests. Does not transfer SEO equity permanently. Browsers may change POST to GET when following this redirect.
- Temporary maintenance pages
- Login redirects
- Follow the redirect for this request
- Keep using the original URL for future requests
The cached version of the resource is still valid. The server is saying "nothing has changed since you last fetched this, use your cached copy." Saves bandwidth and improves performance. No response body is sent.
- Conditional GET with If-None-Match header
- ETag or Last-Modified caching in use
- Use the existing cached response
- No body parsing needed
Same as 302 but explicitly preserves the HTTP method. A POST request redirected with 307 will redirect as POST, not GET. Use 307 instead of 302 when the HTTP method must not change on redirect.
Same as 301 but explicitly preserves the HTTP method. The modern replacement for 301 in REST APIs where method preservation is important. A POST to a 308 URL will redirect as POST, not GET.
4xx — Client Error Codes
These codes mean the problem is with the request you sent. The server understood the request but cannot or will not process it. Fix the request before retrying: retrying the same broken request will always produce the same error.
The request is malformed or missing required information. The server cannot process it as sent. Always read the error response body: well-built APIs tell you exactly which field is wrong and why.
- Missing required field
- Invalid JSON syntax (trailing comma, missing quotes)
- Wrong data type (string instead of number)
- Value out of acceptable range
- Log the full response body
- Validate JSON with the JSON Formatter
- Surface field-specific errors to the user
- Never retry without fixing the request
Authentication is required but was not provided, or the provided credentials are invalid. Despite the name, this is about authentication (who you are), not authorisation (what you can do). That distinction belongs to 403.
- Missing Authorization header
- Expired access token
- Revoked or invalid API key
- Token sent in wrong format
- Attempt token refresh automatically
- If refresh fails, redirect to re-authentication
- Check the Authorization header format
Authentication succeeded but the authenticated user does not have permission to access this resource. The server knows who you are. It will not let you do what you are asking. The same credentials will always produce the same result, so do not retry.
- Accessing another user's private resource
- Missing required permission or role
- Plan or tier restriction
- IP allowlist restriction
- Show a permission error to the user
- Do not retry the same request
- Check the user's role and plan level
The resource does not exist at this URL. This could mean the ID does not exist, the resource was deleted, or the URL is simply wrong. Do not retry in a loop: the resource is not there. Handle it gracefully in your UI as "not found."
- ID does not exist in the database
- Resource was deleted
- Typo in the URL path
- Stale reference to a deleted item
- Show "not found" state in UI
- Remove stale references from local state
- Do not crash or retry
You used an HTTP method that this endpoint does not support. The response includes an Allow header listing the permitted methods. Check the documentation and use the correct method for this endpoint.
- Sending DELETE to a read-only endpoint
- Sending POST to a GET-only endpoint
- Check the Allow response header
- Use the correct HTTP method per documentation
The request conflicts with the current state of the resource. Most commonly seen when trying to create a resource that already exists or when concurrent updates conflict with each other.
- Duplicate creation (email already in use)
- Optimistic locking conflict
- Concurrent write conflict
- Show a duplicate error to the user
- Let the user decide how to resolve
- For locking conflicts: re-fetch and retry
The resource existed but has been permanently deleted and will not be available again. Unlike 404, which is ambiguous, 410 definitively confirms the resource existed. Update any links, bookmarks, or references pointing to this URL.
- Permanently deleted resource
- Expired content that will not return
- Remove all stored references to this URL
- Show "permanently removed" message
The request body is valid JSON but fails validation rules. The key distinction from 400: the syntax is correct, but the content is semantically wrong. APIs that follow this convention will return detailed field-level error information.
- Value fails business rules (age under 18)
- Invalid email or phone format
- Date in the past when future is required
- Map field errors to form fields
- Show inline validation messages to user
- Do not retry without user correction
Rate limit exceeded. You have sent too many requests in a given time window. Always implement exponential backoff on 429 responses. Check the response headers for precise timing information before retrying.
- Too many requests in the rate limit window
- Burst of concurrent requests
- Loop without rate limit awareness
- Read Retry-After header for wait time
- Implement exponential backoff: 1s, 2s, 4s, 8s
- Add proactive rate limiting to your client
- Never retry immediately on 429
5xx — Server Error Codes
Server error codes mean the server failed to process a valid request. These are not caused by your request content. The appropriate response is to retry with backoff and alert if the error persists.
The server encountered an unexpected condition that prevented it from fulfilling the request. This is the generic server error: something went wrong that the server did not handle gracefully. The request itself may be fine. The server has a bug.
- Unhandled exception in server code
- Database connection failure
- Unexpected null reference on the server
- Misconfiguration in a recent deployment
- Log the full error with request details
- Retry with exponential backoff
- Alert if errors persist over time
- Check the API's status page
The server acting as a gateway or proxy received an invalid response from an upstream server. Often indicates the API's backend service is down or overloaded. Typically transient.
- Backend service is down
- Upstream service returning errors
- Load balancer misconfiguration
- Retry with backoff (usually transient)
- Check API status page
The server is temporarily unable to handle requests, usually due to overload or planned maintenance. The Retry-After header may indicate exactly when to retry. Queue requests rather than dropping them.
- Planned maintenance window
- Traffic spike overloading the server
- Deployment in progress
- Check the Retry-After header for timing
- Queue requests for retry, do not drop them
- Show a maintenance message to users
The server acted as a gateway and the upstream server did not respond within the timeout period. Critical distinction: the request may or may not have been processed by the upstream server before it timed out. Treat as potentially processed and verify before retrying.
- Upstream service too slow to respond
- Long-running database query
- Network issues between servers
- Check if the operation was actually completed
- Retry with caution (may cause duplicates)
- Implement idempotency keys for safe retry
A 5xx error that is caught and hidden from logs is a production bug that nobody knows about. Always log 5xx errors with the full request context: method, URL, headers (without auth), request body, and response body. Set up alerts for sustained 5xx error rates. A 1% error rate that nobody sees is a 1% failure rate your users are experiencing.
Complete Quick Reference Table
Bookmark this table. Every code you will encounter, with the cause and the correct response at a glance:
| Code | Name | Common Cause | How to Handle |
|---|---|---|---|
| 200 | OK | Normal success | Validate structure, then process |
| 201 | Created | POST succeeded, resource created | Store returned ID, check Location header |
| 202 | Accepted | Async operation queued | Poll the status URL provided |
| 204 | No Content | DELETE succeeded | No body to parse, update UI |
| 206 | Partial Content | Range request fulfilled | Check Content-Range, append data |
| 301 | Moved Permanently | URL changed permanently | Update all references to new URL |
| 302 | Found | Temporary redirect | Follow redirect, keep using original URL |
| 304 | Not Modified | Cache still valid | Use cached response, no parsing needed |
| 307 | Temporary Redirect | Temp redirect, method preserved | Follow with same HTTP method |
| 308 | Permanent Redirect | Perm redirect, method preserved | Update URL, use same HTTP method |
| 400 | Bad Request | Malformed request or missing field | Log body, fix request, validate JSON |
| 401 | Unauthorized | Auth token missing or expired | Refresh token or re-authenticate |
| 403 | Forbidden | Valid auth, no permission | Show permission error, do not retry |
| 404 | Not Found | Resource does not exist | Show not found UI, do not retry |
| 405 | Method Not Allowed | Wrong HTTP method used | Check Allow header, use correct method |
| 409 | Conflict | Duplicate or concurrent conflict | Show duplicate error, let user resolve |
| 410 | Gone | Resource permanently deleted | Remove all references to this URL |
| 422 | Unprocessable Entity | Validation rules failed | Show field-level errors to user |
| 429 | Too Many Requests | Rate limit exceeded | Read Retry-After, exponential backoff |
| 500 | Server Error | Unhandled server exception | Log, retry with backoff, alert if persistent |
| 502 | Bad Gateway | Upstream service down | Retry, check API status page |
| 503 | Service Unavailable | Server overloaded or maintenance | Queue requests, use Retry-After header |
| 504 | Gateway Timeout | Upstream timed out | Verify then retry, use idempotency keys |
Debugging Status Codes — The Right Workflow
When an API returns an unexpected status code, follow this sequence. It prevents the most common debugging mistakes (retrying 4xx errors, ignoring 5xx bodies, logging nothing useful):
- Check the status code category first. A 4xx means your request has a problem. A 5xx means the server has a problem. This tells you immediately where to look and whether fixing anything on your end will help.
- Read the response body in full. Most APIs include a detailed error message explaining what went wrong. Always log the complete response body for 4xx errors. Never discard it.
- For 401 errors: Check your authentication token. Is it expired? Was it revoked? Are you sending it in the correct header format (Authorization: Bearer YOUR_TOKEN)? Has the token been regenerated since you last used it?
- For 400 and 422 errors: Paste the request body into the JSON Formatter and validate it. Missing commas, wrong types, and trailing commas are the most common causes and are invisible until formatted.
- For 429 errors: Implement exponential backoff immediately. Check the Retry-After and X-RateLimit-Reset headers for exact timing. Never retry a 429 without waiting.
- For 5xx errors: Check the API's status page first. If the API is reported healthy, log the error with full context and retry with exponential backoff. Set up an alert if the error rate exceeds a threshold. Never swallow 5xx errors silently.
- For production-only errors: Compare the request and response against a working environment using the Text Diff Checker. Environment divergence, a different API key scope, a missing header, or a different data format, is the most common cause of errors that only appear in production.
Before spending time stepping through code to find a 400 or 422 error, paste the request body into the JSON Formatter. Invalid JSON syntax, trailing commas, wrong quote types, and mismatched brackets are invisible in plain text and immediately obvious when formatted. This single step resolves the majority of Bad Request errors in seconds.
Frequently Asked Questions
401 Unauthorized means authentication failed or was not provided: the server does not know who you are. 403 Forbidden means authentication succeeded but you do not have permission: the server knows who you are and is refusing the request. The names are confusingly reversed historically: "Unauthorized" really means "unauthenticated." In practice: 401 means re-authenticate; 403 means check permissions.
400 Bad Request means the request is syntactically malformed: invalid JSON, missing required fields, or wrong data type. 422 Unprocessable Entity means the request is syntactically valid JSON but fails business validation rules: the age field is present and is a number, but the value is below the minimum. Not all APIs make this distinction, and some use 400 for both cases. When an API does use both, 422 typically comes with detailed field-level error messages.
404 Not Found is ambiguous: the resource might not exist, it might have been deleted, or the URL might be wrong. 410 Gone is definitive: the resource existed and has been permanently removed and will not return. In practice, most APIs return 404 for both cases because tracking and returning 410 requires storing a record of deleted resources. When a 410 is returned, update or remove any stored references to that URL.
Retry 500, 502, and 503 with exponential backoff: these are typically transient and the operation has not been processed. Be careful with 504 Gateway Timeout: the operation may have been processed before the timeout occurred. For operations that are not idempotent (creating a record, charging a payment), verify whether the operation completed before retrying to avoid duplicates. Use idempotency keys when the API supports them.
On the first 429 response, wait 1 second. On the second consecutive 429, wait 2 seconds. Then 4 seconds, then 8 seconds. Add a small random jitter (100 to 500 ms) to each wait to prevent multiple clients from retrying in sync. Always check the Retry-After response header first: if it is present, use its value as the minimum wait time rather than calculating your own. Stop retrying after a configurable maximum (typically 5 attempts) and surface an error to the user.
Debug API responses faster
Validate JSON request and response bodies, compare across environments, and convert between formats. All free, all in your browser, no login required.
Know the Code, Diagnose Faster
HTTP status codes are a complete, standardised communication protocol between servers and clients. Every 4xx tells you exactly where your request went wrong. Every 5xx tells you the server needs time or attention. Every 2xx tells you something specific about how the operation succeeded. That information is available immediately, before you read a single line of the response body, if you know what to look for.
The most important habits are: always log the full response body for 4xx errors, always implement backoff for 429 and 5xx, never retry 4xx errors without fixing the request first, and never swallow any status code silently. The quick reference table and debugging workflow above give you a repeatable process that works for any API you encounter.
Bookmark this page alongside the JSON Formatter. The two resources together cover the majority of API debugging situations: the formatter to understand the response structure, and this reference to understand what the status code is telling you.