Real-world workflow
Use CasePick the Right HTTP Status for an API Response
Choose between 400, 401, 403, 404, 409, 422, and the 5xx family when designing REST endpoints — with a decision path and lookup tool.
Decision path
- Did the server fail? → 5xx. Unexpected exception = 500; dependency down or maintenance = 503; upstream timeout at a proxy = 504.
- Is the caller unauthenticated? → 401 (send
WWW-Authenticate). - Authenticated but not allowed? → 403.
- Resource missing? → 404 (or 410 if permanently deleted and you want crawlers to drop it).
- Request malformed? Unparseable body/params = 400; parseable but semantically invalid = 422.
- Clashes with current state? Duplicate create, stale version, edit conflict = 409.
- Success: created = 201, async accepted = 202, no body = 204, everything else = 200.
Check any code’s exact meaning in the HTTP Status Lookup — it covers 100–599 with guidance per code.
Steps
- Map each endpoint failure mode to the path above before writing handlers; put the table in your API docs.
- Keep error bodies consistent (
code,message,details) regardless of status. - Verify what your API actually returns — inspect live responses with the HTTP Header Inspector and validate error bodies with the JSON Validator.
Watch out
- Returning 200 with
{"error": ...}breaks client retry logic and monitoring — status codes are the contract. - Do not leak existence through status: if unauthorized users must not know a resource exists, return 404 rather than 403.
Related
Frequently Asked Questions
409 or 422 for a duplicate record?
409 Conflict — the request clashes with existing state (the record already exists). Use 422 when the body is syntactically valid JSON but semantically wrong (a negative quantity, a missing required field).
401 or 403?
401 when the caller is not authenticated (missing/expired token — they should log in). 403 when they are authenticated but not allowed (valid token, wrong role).