Status codes are part of the contract
Status codes tell clients how to interpret the response. They are part of your API contract, not a decorative detail.
When codes are inconsistent, clients must guess. That leads to fragile integrations and noisy monitoring.
2xx: success with meaning
Use 200 for success with a response body. Use 201 for creation and include a Location header. Use 204 when the action succeeds but there is no body.
These differences help clients decide whether to update local state or fetch fresh data.
3xx: rare for APIs
Redirects are uncommon in APIs. They can be useful for moved resources or version upgrades, but they add complexity.
If you use 3xx, document the behavior and avoid redirect chains.
4xx: errors the client can fix
Use 400 for malformed payloads, 401 for missing/invalid auth, 403 for forbidden access, 404 for missing resources, 409 for conflicts, and 422 for validation errors if you choose that route.
What matters most is consistency. Pick a scheme and apply it everywhere.
5xx: server failures
5xx codes indicate server-side problems. 500 covers unexpected errors. 502/503 are useful for dependency failures or temporary outages.
Do not use 500 for errors the client can fix. Reserve 5xx for genuine server failures.
Always return structured errors
A status code alone is not enough. Provide a structured error body with a code, message, and optionally field errors.
This reduces support overhead and makes automated handling possible.
Patterns to standardize
Create: POST returns 201 + Location. Read: GET returns 200 or 404. Update: PATCH returns 200 with body or 204 without. Delete: DELETE returns 204 or 404.
These patterns are widely understood and make onboarding easy.
Observability depends on codes
Monitoring and alerting often rely on status codes. If you return 200 for failures, your alerts will miss real issues.
Correct status codes improve reliability, not just documentation.
