Status codes carry the outcome class
Status codes tell clients what happened without parsing the body. Load balancers, APM tools, and client libraries classify success and failure from the first line of the response. Interviews expect you to map client mistakes (4xx), success (2xx), and server failures (5xx), and to describe a consistent error envelope — often application/problem+json per RFC 7807.
Do not return 200 OK with { "error": true } for failures. That breaks HTTP caches, retries, and monitoring that trust status codes.
Common status codes
| Code | When to use |
|---|---|
| 200 OK | Success; body contains the representation |
| 201 Created | Resource created; include Location header pointing to the new URI |
| 204 No Content | Success with no body (common for DELETE or updates that return nothing) |
| 400 Bad Request | Malformed JSON, unknown fields if strict, failed basic validation |
| 401 Unauthorized | Unauthenticated — missing or invalid credentials (name is historical; means “not authenticated”) |
| 403 Forbidden | Authenticated but not permitted for this action or resource |
| 404 Not Found | Resource does not exist (or hide existence with 403 in sensitive cases) |
| 409 Conflict | Conflict with current state — duplicate unique key, version mismatch, illegal transition |
| 412 Precondition Failed | Conditional header failed (If-Match ETag mismatch) |
| 422 Unprocessable Entity | Semantic validation error (popular in APIs; some teams use 400 instead) |
| 429 Too Many Requests | Rate limited — include Retry-After when possible |
| 500 Internal Server Error | Unexpected server failure |
| 502 Bad Gateway | Upstream invalid response |
| 503 Service Unavailable | Overload or maintenance — Retry-After helps clients backoff |
| 504 Gateway Timeout | Upstream did not respond in time |
4xx vs 5xx
4xx — the client can fix the request: fix auth, fix validation, use a different id, wait and respect rate limits. Retrying the same payload without change should not succeed (except 429 after waiting).
5xx — the server or gateway failed. Clients may retry with exponential backoff unless the operation is known non-idempotent without an idempotency key.
Map precisely: a duplicate email signup is 409, not 500. A missing Authorization header is 401, not 403.
401 vs 403
This pair is swapped constantly in production APIs.
- 401 — “Who are you?” Missing token, expired token, invalid signature. Client should authenticate or refresh.
- 403 — “I know who you are; you cannot do this.” Valid credentials, insufficient scope or role.
Example: GET /admin/users without a token → 401. Authenticated user without admin role → 403.
Error response body
Minimum useful fields for a consistent JSON error:
type— URI identifying the error class (stable, links to documentation)title— short human-readable summarystatus— numeric code (duplicates the status line but useful in parsed body)detail— specific explanation for this occurrence (no stack traces or secrets in production)instance— unique id for this occurrence (support correlation)
For validation failures, add errors[] with field-level messages:
{
"type": "https://api.example.com/problems/validation-error",
"title": "Validation failed",
"status": 422,
"detail": "One or more fields are invalid",
"instance": "urn:uuid:8d0f8760-4b9e-4d3a-9c1e-2f0b8a7d6c5b",
"errors": [
{ "field": "amount", "message": "must be positive" },
{ "field": "currency", "message": "must be ISO 4217 code" }
]
}
Avoid generic 400 for every failure when 409, 422, or 404 carries meaning clients and operators can act on. Never ship stack traces in production bodies.
Problem Details (RFC 7807)
RFC 7807 defines application/problem+json (and XML variant) so errors are machine-readable and uniform across services.
HTTP/1.1 400 Bad Request
Content-Type: application/problem+json
{
"type": "https://api.example.com/problems/invalid-amount",
"title": "Invalid amount",
"status": 400,
"detail": "amount must be positive",
"instance": "urn:uuid:8d0f8760-4b9e-4d3a-9c1e-2f0b8a7d6c5b"
}
Benefits:
- API gateways and clients handle errors one way across teams
typeURIs document error classes without reading prose docsinstanceties to distributed trace ids for support tickets
Many APIs use Problem Details shape without the exact MIME type; adopting the standard fully helps generic HTTP clients.
Success headers worth mentioning
- Location on 201 Created — canonical URI of the new resource
- ETag on 200 — enables conditional GET and optimistic concurrency
- Retry-After on 503 and 429 — seconds or HTTP-date for client backoff
Interview framing
“401 vs 403?” — 401 unauthenticated; 403 authenticated but not allowed.
“When use 409?” — Conflict with current state: duplicate unique constraint, stale version, illegal state machine transition.
“What is Problem Details?” — RFC 7807 standard type application/problem+json with type, title, status, detail, instance for structured errors.
“Why not always 400?” — Specific codes let clients branch (retry vs fix input vs escalate) without parsing free-text messages.
Next: Versioning, Pagination & Idempotency — evolving APIs and safe retries at scale.