6.9 KiB
HTTP Status Codes for REST APIs
Quick reference for selecting the correct HTTP status code in REST API responses.
2xx Success
| Code | Name | When to Use |
|---|---|---|
200 |
OK | General success. GET returns data, PUT/PATCH returns updated resource. |
201 |
Created | POST successfully created a resource. Include Location header. |
202 |
Accepted | Request accepted for async processing. Return a job/task ID. |
204 |
No Content | DELETE success or PUT/PATCH with no response body needed. |
Guidelines:
200is the default success response for GET, PUT, PATCH201must be used when a new resource is created (POST)204is preferred for DELETE (no body to return)202signals "we got it, processing later" -- return a status URL
// 201 Created response
{
"id": "usr_abc123",
"name": "Jane Doe",
"createdAt": "2026-01-15T10:30:00Z"
}
// Header: Location: /v1/users/usr_abc123
3xx Redirection
| Code | Name | When to Use |
|---|---|---|
301 |
Moved Permanently | Resource URL changed permanently. Clients should update bookmarks. |
302 |
Found | Temporary redirect. Original URL still valid. |
304 |
Not Modified | Conditional GET -- resource unchanged since If-None-Match/If-Modified-Since. |
307 |
Temporary Redirect | Like 302 but preserves HTTP method. Use for API redirects. |
308 |
Permanent Redirect | Like 301 but preserves HTTP method. |
Guidelines:
- Prefer
307/308over302/301in APIs (method preservation) 304reduces bandwidth when clients cache responses- Always include
Locationheader with redirect responses
4xx Client Errors
| Code | Name | When to Use |
|---|---|---|
400 |
Bad Request | Malformed syntax, invalid JSON, failed validation. |
401 |
Unauthorized | Missing or invalid authentication credentials. |
403 |
Forbidden | Authenticated but lacks permission for this resource. |
404 |
Not Found | Resource does not exist at this URL. |
405 |
Method Not Allowed | HTTP method not supported on this endpoint. |
409 |
Conflict | Request conflicts with current state (duplicate, version mismatch). |
410 |
Gone | Resource existed but has been permanently deleted. |
415 |
Unsupported Media Type | Content-Type header not supported. |
422 |
Unprocessable Entity | Valid JSON but semantically invalid (business rule violation). |
429 |
Too Many Requests | Rate limit exceeded. Include Retry-After header. |
Guidelines:
400for structural issues (bad JSON, missing required field, wrong type) — caught by the parser/validator.422for semantic failures (email already taken, invalid state transition, quota exceeded) — caught by application logic.401means "who are you?" —403means "I know who you are, but no".409for optimistic-locking failures and unique-constraint violations.412forIf-Match/If-Unmodified-Sinceprecondition failures (ETag concurrency).429must includeRetry-Afterwith seconds until retry.
400 vs 422 decision rule: If the request body failed to parse or a required field is missing, return 400. If the body parsed fine and every field has the right type but the combination violates a business rule, return 422.
All error bodies use application/problem+json per RFC 9457.
// 422 Unprocessable Entity
// Content-Type: application/problem+json
{
"type": "https://api.example.com/problems/validation-error",
"title": "Validation failed",
"status": 422,
"detail": "Request validation failed.",
"errors": [
{ "field": "email", "message": "Email already registered", "code": "conflict" },
{ "field": "age", "message": "Must be 18 or older", "code": "outOfRange" }
]
}
// 429 Too Many Requests
// Headers: Retry-After: 60
// Content-Type: application/problem+json
{
"type": "https://api.example.com/problems/rate-limited",
"title": "Too many requests",
"status": 429,
"detail": "Rate limit exceeded. Retry after 60s."
}
5xx Server Errors
| Code | Name | When to Use |
|---|---|---|
500 |
Internal Server Error | Unhandled exception. Generic server failure. |
501 |
Not Implemented | Endpoint exists but functionality not built yet. |
502 |
Bad Gateway | Upstream service returned invalid response. |
503 |
Service Unavailable | Server overloaded or in maintenance. Include Retry-After. |
504 |
Gateway Timeout | Upstream service did not respond in time. |
Guidelines:
500should never expose stack traces in production503should includeRetry-Afterheader and a maintenance message- Log all 5xx errors with request context for debugging
- Return a consistent error body format for all 5xx responses
// 500 Internal Server Error (production)
// Content-Type: application/problem+json
{
"type": "https://api.example.com/problems/internal-error",
"title": "Internal server error",
"status": 500,
"detail": "An unexpected error occurred. Please try again.",
"instance": "/v1/users/usr_abc123",
"requestId": "req_7f3a9b2c"
}
Extension members (requestId, traceId, etc.) are encouraged by RFC 9457 — include anything that helps the caller report the bug.
Decision Flowchart
Request received
|
+-- Is it valid syntax? -- NO --> 400 Bad Request
|
+-- Is caller authenticated? -- NO --> 401 Unauthorized
|
+-- Is caller authorized? -- NO --> 403 Forbidden
|
+-- Does resource exist? -- NO --> 404 Not Found
|
+-- Is it rate-limited? -- YES --> 429 Too Many Requests
|
+-- If-Match / If-Unmodified-Since fails? -- YES --> 412 Precondition Failed
|
+-- Does it pass business rules? -- NO --> 422 Unprocessable Entity
|
+-- Any conflicts? -- YES --> 409 Conflict
|
+-- Server error? -- YES --> 500 Internal Server Error
|
+-- Success!
GET --> 200 OK
POST --> 201 Created
PUT --> 200 OK
PATCH --> 200 OK
DELETE --> 204 No Content
Standard Error Response Format — RFC 9457 Problem Details
Every error response uses the application/problem+json media type with this shape:
{
"type": "https://api.example.com/problems/<problem-slug>",
"title": "Short human-readable summary",
"status": 422,
"detail": "Human-readable explanation for this occurrence.",
"instance": "/v1/users/usr_abc123",
"errors": [ /* optional: field-level validation breakdown */ ],
"requestId": "req_..."
}
Required fields: type, title, status. Everything else is optional but strongly recommended. The type URI should resolve to a real documentation page — that is the core benefit of RFC 9457 over ad-hoc envelopes.
Reference: RFC 9110 — HTTP Semantics, RFC 9457 — Problem Details for HTTP APIs