Files
claudekit/skills/openapi/references/http-status-codes.md
T
2026-04-19 14:10:38 +07:00

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:

  • 200 is the default success response for GET, PUT, PATCH
  • 201 must be used when a new resource is created (POST)
  • 204 is preferred for DELETE (no body to return)
  • 202 signals "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/308 over 302/301 in APIs (method preservation)
  • 304 reduces bandwidth when clients cache responses
  • Always include Location header 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:

  • 400 for structural issues (bad JSON, missing required field, wrong type) — caught by the parser/validator.
  • 422 for semantic failures (email already taken, invalid state transition, quota exceeded) — caught by application logic.
  • 401 means "who are you?" — 403 means "I know who you are, but no".
  • 409 for optimistic-locking failures and unique-constraint violations.
  • 412 for If-Match / If-Unmodified-Since precondition failures (ETag concurrency).
  • 429 must include Retry-After with 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:

  • 500 should never expose stack traces in production
  • 503 should include Retry-After header 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