HTTP Status Codes Explained: The Complete Developer Reference
HTTP status codes are three-digit numbers that servers send back with every response. Knowing what they mean is fundamental to building and debugging web applications. This guide covers every status code you're likely to encounter, with practical context about when to use each one.
The Five Categories
| Range | Category | Meaning |
|---|---|---|
1xx | Informational | Request received, continuing process |
2xx | Success | Request successfully received and processed |
3xx | Redirection | Further action needed to complete request |
4xx | Client Error | The request contains an error on the client side |
5xx | Server Error | The server failed to process a valid request |
2xx Success Codes
200 OK
The request succeeded. The meaning depends on the HTTP method:
GET: Resource fetched and sent in the response bodyPOST: Action completed, result in response bodyPUT/PATCH: Resource updated successfully
201 Created
A new resource was successfully created. Always use this instead of 200 for POST requests that create resources. Include a Location header pointing to the new resource:
HTTP/1.1 201 Created
Location: /api/users/12345
Content-Type: application/json
{"id": 12345, "name": "Alice"} 204 No Content
The request succeeded but there's no response body. Common for DELETE operations and PUT updates where the client doesn't need the updated resource back:
DELETE /api/users/12345
→ 204 No Content 206 Partial Content
The server is delivering only part of the resource due to a Range header. Used for resumable downloads and video streaming.
3xx Redirection Codes
301 Moved Permanently
The resource has permanently moved to a new URL. Search engines transfer ranking to the new URL. Browsers cache this redirect aggressively:
# Old URL permanently redirects to new URL
/old-page → 301 → /new-page 302 Found (Temporary Redirect)
The resource is temporarily at a different URL. Search engines keep the original URL indexed. Use for maintenance pages or A/B testing.
304 Not Modified
The resource hasn't changed since the last request. The server sends no body — the client uses its cached version. This is triggered by If-Modified-Since or If-None-Match headers:
# Client sends:
GET /api/data
If-None-Match: "abc123"
# Server responds (data unchanged):
304 Not Modified 307 Temporary Redirect
Like 302, but guarantees the HTTP method won't change. A POST request redirected with 307 remains a POST. Use 307 instead of 302 for non-GET requests.
308 Permanent Redirect
Like 301, but guarantees the HTTP method won't change. Use 308 instead of 301 when redirecting POST/PUT/DELETE requests permanently.
4xx Client Error Codes
400 Bad Request
The server can't process the request due to a client error — malformed syntax, invalid parameters, or bad JSON formatting. Always include a descriptive error message:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": "validation_error",
"message": "Email address is required",
"field": "email"
} 401 Unauthorized
Authentication is required but was not provided or is invalid. Despite the name, this is about authentication (who you are), not authorization (what you're allowed to do). The server should include a WWW-Authenticate header indicating the auth scheme. Common when a JWT token is missing or expired.
403 Forbidden
The server understood the request but refuses to authorize it. The client is authenticated but doesn't have permission. Unlike 401, re-authenticating won't help:
- 401: "I don't know who you are. Please log in."
- 403: "I know who you are. You're not allowed to do this."
404 Not Found
The requested resource doesn't exist. The most well-known status code. Can also be used intentionally to hide the existence of a resource from unauthorized users (instead of 403).
405 Method Not Allowed
The HTTP method isn't supported for this resource. For example, trying to DELETE a read-only resource. Include an Allow header listing valid methods:
HTTP/1.1 405 Method Not Allowed
Allow: GET, HEAD, OPTIONS 409 Conflict
The request conflicts with the current state of the resource. Common for duplicate creation attempts or version conflicts:
# Trying to create a user with an existing email
POST /api/users
→ 409 Conflict
{"error": "A user with this email already exists"} 422 Unprocessable Entity
The request syntax is valid (unlike 400) but the content is semantically incorrect. Common in form validation when the JSON structure is correct but the values are invalid:
# Valid JSON, but age can't be negative
{"name": "Alice", "age": -5}
→ 422 Unprocessable Entity 429 Too Many Requests
The client has sent too many requests (rate limiting). Include a Retry-After header telling the client when to retry:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
{"error": "Rate limit exceeded. Try again in 60 seconds."} 5xx Server Error Codes
500 Internal Server Error
The generic server error. Something went wrong on the server side. In production, never expose stack traces or internal details to clients — log them server-side and return a generic message:
// BAD — exposes internals
{"error": "NullPointerException at UserService.java:42"}
// GOOD — safe for clients
{"error": "internal_error", "message": "Something went wrong. Please try again."} 502 Bad Gateway
The server (acting as a proxy or gateway) received an invalid response from an upstream server. Common with reverse proxies (Nginx, Cloudflare) when the backend application crashes or is unreachable.
503 Service Unavailable
The server is temporarily unable to handle the request — usually due to maintenance or overload. Include a Retry-After header:
HTTP/1.1 503 Service Unavailable
Retry-After: 300
{"error": "Server is under maintenance. Back in ~5 minutes."} 504 Gateway Timeout
The proxy/gateway server didn't receive a timely response from the upstream server. Common when backend processing takes too long (slow database queries, external API timeouts).
Choosing the Right Status Code for APIs
| Operation | Success Code | Common Error Codes |
|---|---|---|
GET /resource | 200 | 404, 401, 403 |
POST /resource (create) | 201 | 400, 409, 422 |
PUT /resource/:id (update) | 200 or 204 | 400, 404, 409, 422 |
PATCH /resource/:id | 200 | 400, 404, 422 |
DELETE /resource/:id | 204 | 404, 403 |
| List with no results | 200 (empty array) | — |
| Authentication failure | — | 401 |
| Insufficient permissions | — | 403 |
| Rate limited | — | 429 |
Handling Status Codes in JavaScript
async function fetchUser(id) {
const response = await fetch(`/api/users/${id}`);
switch (response.status) {
case 200:
return await response.json();
case 404:
throw new Error('User not found');
case 401:
// Redirect to login
window.location.href = '/login';
return;
case 429:
const retryAfter = response.headers.get('Retry-After');
throw new Error(`Rate limited. Retry after ${retryAfter}s`);
default:
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
}
} When testing API responses, use our Curl Converter to translate curl commands into JavaScript fetch calls, or format the JSON response bodies with our JSON Formatter.
Less Common But Useful Codes
| Code | Name | Use Case |
|---|---|---|
| 202 | Accepted | Request accepted for async processing (not completed yet) |
| 301 | Moved Permanently | SEO-safe permanent URL redirect |
| 410 | Gone | Resource permanently deleted (unlike 404, confirms it existed) |
| 413 | Payload Too Large | Request body exceeds server limits |
| 415 | Unsupported Media Type | Server doesn't support the Content-Type |
| 418 | I'm a Teapot | April Fools' joke from 1998 — still in the spec |
| 451 | Unavailable for Legal Reasons | Censorship or legal takedown |
Need a quick reference while debugging? Our HTTP Status Code Explorer lets you search any status code and instantly see its meaning, common causes, and how to handle it in your code.