HTTP status codes tell generic software, including client libraries, caches and proxies, the broad category of what happened, but they cannot carry the specifics. RFC 9457 was written to close that gap: a problem type URI identifies the specific problem, and the response body carries details the client can act on (RFC 9457). The earlier RFC 7807 was the original version of the same idea and is now obsolete in favor of RFC 9457 (RFC 7807).
The practical rule: pick the most specific status code that applies, then use the body to say exactly which condition fired. Returning 400 for every client mistake or 500 for every server mistake throws away information the client could have used (Zuplo). Postman's checklist states the same goal from the consumer side: clients should understand outcomes without parsing response bodies (Postman).
A status-code map that holds up in practice:
| Situation | Status | Body code example | Retryable |
|---|---|---|---|
| Malformed JSON, unreadable body | 400 | request.malformed_json | no |
| Missing or invalid credentials | 401 | auth.invalid_token | no (refresh first) |
| Authenticated but not permitted | 403 | auth.insufficient_scope | no |
| Resource does not exist | 404 | resource.not_found | no |
| Duplicate create or lost update | 409 | order.already_exists | no |
| Syntactically valid, business rule failed | 422 | validation.field_invalid | no |
| Rate limit exceeded | 429 | rate_limit.exceeded | yes, with Retry-After |
| Unhandled server failure | 500 | internal.unexpected | maybe |
| Upstream dependency down | 503 | upstream.unavailable | yes, with Retry-After |
These categories match the commonly used conventions: 400 for invalid format, 401 for missing authentication, 403 for lacking permission, 409 for a conflict with current state, 422 for semantic errors, and 429 for rate limits with a Retry-After header (Postman). The split between 400 and 422 is the one teams argue about most. Decide once and write it down: 400 means "I could not read this request," 422 means "I read it and a business rule rejected it." Clients can then treat a 400 as a bug in their serializer and a 422 as something to show the user.



