HTTP status codes are one of the fastest signals you get when an API call goes wrong, but they are often used inconsistently or interpreted too loosely. This reference is designed to be a practical page you can return to when debugging requests, designing REST API responses, or deciding which status code best matches a real failure mode. It focuses on what common HTTP status codes mean, how they differ in production debugging, and how to use them in a way that helps both client developers and backend maintainers move faster.
Overview
This guide gives you a working HTTP status codes list for API debugging and error handling, with emphasis on real implementation choices rather than memorizing categories. If you build or consume APIs, the goal is not to know every possible code. The goal is to choose and interpret status codes consistently enough that logs, monitoring, test suites, and client applications all tell the same story.
At a high level, HTTP response codes fall into five groups:
- 1xx informational: the request has started and processing is continuing.
- 2xx success: the request was accepted and handled successfully.
- 3xx redirection: the client must take another step, usually following a different location.
- 4xx client errors: the server could not process the request as sent.
- 5xx server errors: the request may be valid, but the server failed while handling it.
For most API work, the codes you will encounter most often are 200, 201, 204, 400, 401, 403, 404, 409, 422, 429, 500, 502, 503, and 504. Those are the codes worth treating as a core reference because they map directly to day-to-day backend and client behavior.
A status code should answer one narrow question: what happened to this HTTP request from the protocol perspective? It should not try to carry all application detail by itself. In practice, good API responses pair the code with a structured body, often JSON, containing a machine-readable error type, a human-readable message, and relevant fields such as request IDs or validation details. If you need to standardize those payloads, it also helps to validate them consistently; a companion reference like JSON Schema Validator Tools Compared can support that part of the workflow.
Below is a compact reference list for the most useful API status codes.
Common HTTP status codes for APIs
- 200 OK: The request succeeded and a response body is usually returned.
- 201 Created: A new resource was created successfully.
- 202 Accepted: The request was accepted for asynchronous processing, but not completed yet.
- 204 No Content: The request succeeded and there is no response body.
- 301 Moved Permanently: The resource has a new permanent URL.
- 302 Found: The resource is temporarily available at another URL.
- 304 Not Modified: Cached content is still valid.
- 400 Bad Request: The request is malformed or cannot be processed as sent.
- 401 Unauthorized: Authentication is missing, invalid, or expired.
- 403 Forbidden: Authentication may be present, but access is not allowed.
- 404 Not Found: The target resource does not exist or is not exposed.
- 405 Method Not Allowed: The route exists, but the HTTP method is not supported.
- 409 Conflict: The request conflicts with current resource state.
- 410 Gone: The resource used to exist but has been intentionally removed.
- 412 Precondition Failed: A conditional request failed, often due to ETag or version mismatch.
- 415 Unsupported Media Type: The server does not accept the request content type.
- 422 Unprocessable Content: The payload is syntactically valid but semantically invalid.
- 429 Too Many Requests: The client exceeded rate limits.
- 500 Internal Server Error: A generic server-side failure occurred.
- 502 Bad Gateway: An upstream dependency returned an invalid response.
- 503 Service Unavailable: The service is temporarily unable to handle traffic.
- 504 Gateway Timeout: An upstream dependency did not respond in time.
Core concepts
This section explains how to choose among similar API status codes and how to read them during debugging.
2xx: success does not always mean the same thing
200 OK is the default success code for read operations and many updates. Use it when the action completed and you are returning content, such as a fetched record or an updated object.
201 Created is best when a POST or similar action creates a new resource. If your API exposes a canonical URL for that new item, returning it in the response is helpful.
202 Accepted is easy to misuse. It does not mean success in the final business sense. It means the server accepted the request for later processing. Use it for queued jobs, report generation, large imports, or webhook fan-out where completion happens asynchronously.
204 No Content is useful for deletes, idempotent updates, or toggles where the client does not need a body. It avoids ambiguity because an empty body is intentional rather than accidental.
400 vs 422: malformed versus invalid
This is one of the most common design questions in a REST API status codes guide.
400 Bad Request is a good fit when the request itself is broken at a transport or parsing level. Typical examples include invalid JSON, a missing required query parameter format, or a body that the server cannot parse.
422 Unprocessable Content is better when the request is structurally valid but fails business or domain validation. For example:
- The JSON parses correctly, but an email field has an invalid format.
- A start date is later than an end date.
- A username violates application rules.
If your team prefers using 400 for all validation failures, that can still work, but consistency matters more than chasing a perfect taxonomy. Whatever you choose, document it and keep it stable.
401 vs 403: authentication and authorization
401 Unauthorized is historically named in a slightly confusing way. In practice, it usually means the client is not authenticated successfully. The token may be missing, expired, malformed, or invalid.
403 Forbidden means the client is authenticated or recognized, but still does not have permission to perform the action.
A useful rule of thumb:
- If the client should retry with valid credentials, return 401.
- If valid credentials still would not grant access, return 403.
If authentication involves tokens, encoded headers, or signed payloads, adjacent utilities such as a Base64 Encode and Decode Tools Compared guide or a URL encoding reference like URL Encoder and Decoder Guide for Query Strings, Paths, and Unicode can help isolate request construction issues.
404, 405, 409, and 410: state and route clarity
404 Not Found should mean the target resource is not available at that route. That may be because it never existed, was deleted, or is intentionally hidden.
405 Method Not Allowed is more precise when the route exists but does not support the HTTP method used. For example, sending DELETE to a collection endpoint that only supports GET and POST.
409 Conflict is useful when the request collides with current state. Common cases include duplicate unique values, versioning conflicts, or attempts to transition a resource into an impossible state.
410 Gone is less common but useful when you want to make resource removal explicit rather than ambiguous. It can help clients distinguish between a typo and an intentionally retired endpoint or object.
429 and the 5xx family: protection versus failure
429 Too Many Requests tells the client it has hit a rate limit or quota. This is not a server crash. It is a policy or capacity control outcome. Clients can often recover by backing off and retrying later.
500 Internal Server Error is a generic fallback when your application failed unexpectedly.
502 Bad Gateway usually appears when your API depends on an upstream service and receives an invalid or unusable response from it.
503 Service Unavailable is a better choice when the service is intentionally unavailable or temporarily overloaded, such as during maintenance or capacity pressure.
504 Gateway Timeout indicates an upstream dependency did not respond in time. If your architecture includes proxies, gateways, or multiple internal services, distinguishing 502, 503, and 504 makes incident triage much faster.
Why response bodies matter as much as status codes
Status codes are not enough on their own. A helpful error response body should usually include:
- An error code or type that applications can rely on.
- A readable message for developers.
- Field-level validation details where relevant.
- A request or trace ID for log correlation.
- Optional retry guidance for transient failures.
This is where many APIs become much easier to debug. The status code tells you the class of outcome; the body tells you what to do next.
Related terms
If you use an HTTP error codes list regularly, it helps to keep a few adjacent terms clear.
Idempotency
An idempotent operation can be repeated without changing the result after the first successful call. This matters because retries are common in distributed systems. PUT and DELETE are often treated as idempotent in API design, even if implementations vary. Status code choices should support safe retries where possible.
Conditional requests
Conditional headers such as ETag-related checks help prevent lost updates and stale writes. When these conditions fail, codes like 412 Precondition Failed are more meaningful than a generic 400 or 409.
Content negotiation and media type
If the client sends the wrong Content-Type, a server may return 415 Unsupported Media Type. If the client requests a response format the server cannot provide, some implementations return related negotiation errors. These problems often look like application failures until you inspect headers carefully.
CORS errors versus HTTP response errors
Browser-based debugging can be misleading because a frontend app may surface a CORS failure before you ever get a visible API status code in application code. If a request appears to fail without a clean response, review CORS Errors Explained: Fixes, Debug Steps, and Testing Tools alongside your status code debugging.
Gateway, proxy, and upstream failures
In modern deployments, your application server may sit behind a load balancer, API gateway, CDN, or reverse proxy. That means some status codes are generated by infrastructure rather than your application. A 502 or 504 may point to network or upstream health problems rather than a bug in your controller logic. If DNS or routing is involved, a reference like DNS Lookup Tools Compared for Debugging Records, Propagation, and Failures can help narrow the problem.
Practical use cases
This section maps common debugging situations to status code decisions and next steps.
Scenario: creating a resource
If a client sends a valid POST request that creates a new object, return 201 Created. If creation is deferred to a queue, return 202 Accepted and provide a way to check job status. If the payload is broken JSON, return 400. If the payload is valid JSON but fails business validation, return 422.
Scenario: login and token-based access
When credentials are missing, expired, or invalid, return 401. When the token is valid but the user lacks the necessary role or scope, return 403. During debugging, confirm whether the issue is authentication state, token formatting, or authorization policy before changing status codes.
Scenario: duplicate record or version conflict
If a client tries to create a user with an email that must be unique, 409 Conflict is often more helpful than a generic 400. It signals that the request is understood but cannot succeed in the current state. This is especially useful in clients that can surface better recovery options.
Scenario: endpoint exists but method is wrong
If /users/123 supports GET and PATCH but not POST, return 405 Method Not Allowed rather than 404. This distinction helps client developers identify misuse of an otherwise valid route.
Scenario: rate limiting and retries
If a client exceeds allowed request volume, return 429 Too Many Requests. Include clear retry guidance if possible. Client developers should pair this with backoff logic rather than immediate repeated retries, which can amplify the problem.
Scenario: intermittent infrastructure errors
If your app relies on an upstream payment, search, or identity provider and that dependency returns nonsense or fails before completing a valid response, 502 may fit better than 500. If the dependency is unavailable for a known temporary period, 503 can better represent service state. If the dependency is simply too slow and times out, 504 is usually the clearest signal.
Scenario: frontend sees a network error, but backend logs show nothing
This often points to CORS, proxy, DNS, or client construction issues rather than an application-generated status code. Reproduce the request in a dedicated API client. A tool comparison like API Testing Tools Comparison: Postman vs Insomnia vs Hoppscotch and More can help you choose a cleaner environment for isolating request headers, payloads, and auth behavior.
A practical checklist for choosing status codes
- Did the request succeed completely? Use a 2xx code that matches the outcome.
- Was the route wrong or missing? Consider 404.
- Was the method unsupported? Consider 405.
- Was the request malformed? Consider 400.
- Was the request valid but semantically wrong? Consider 422.
- Was authentication missing or invalid? Consider 401.
- Was access denied despite valid identity? Consider 403.
- Did current state block the operation? Consider 409 or 412.
- Did policy or quota block the request? Consider 429.
- Did your system or an upstream dependency fail? Consider 5xx, with 502, 503, and 504 used intentionally.
Document these choices in your API style guide and test them. Once client teams depend on a response contract, changing code semantics casually creates avoidable friction.
When to revisit
Use this page as a stable status code reference, but revisit your own API conventions when any of the following happens:
- You add new gateways, proxies, queues, or third-party dependencies that change where failures originate.
- You move synchronous operations to asynchronous jobs and should switch some responses from 200 or 201 to 202.
- You introduce stronger validation and need to separate malformed requests from domain validation failures more clearly.
- You notice dashboards full of generic 500s that would be more actionable as 409, 422, 429, 502, 503, or 504.
- Client teams repeatedly ask what a response means, which is often a sign that the code-body combination is underspecified.
- Your API documentation has drifted from actual implementation behavior.
A good maintenance habit is to review your most common failed requests every few months. Look at access logs, application logs, and API test collections. Ask simple questions: are the status codes precise, are error bodies consistent, and do retry behaviors make sense? Tightening those three areas usually improves both developer experience and incident response.
If you maintain internal tooling, it can also help to keep related debugging references close at hand: use a schema validator for response contracts, URL tools for encoded parameters, and API clients for reproducible request testing. Small utilities reduce guesswork, and that is often what separates fast debugging from long sessions of trial and error.
The practical takeaway is straightforward: do not treat HTTP status codes as decoration. Treat them as part of the API contract. Pick the narrowest code that matches the outcome, pair it with a structured body, and keep the rules consistent across endpoints. That makes your APIs easier to consume, easier to monitor, and much easier to debug when something breaks.