HTTP Status Codes Explained: When to Use Each One
Choosing the right HTTP status code for your API responses matters more than you might think. The correct status code helps clients handle responses appropriately, makes debugging easier, and follows web standards. Here's a practical guide for API developers.
The Status Codes You'll Use Most
200 OK — The Default Success
Use for successful GET requests that return data, and successful PUT/PATCH updates. This is your bread and butter.
GET /api/users/123 → 200 with user data
PUT /api/users/123 → 200 with updated user data
201 Created — Something New Was Made
Use when a POST request successfully creates a new resource. Include a Location header pointing to the new resource.
POST /api/users → 201
Location: /api/users/456
204 No Content — Success, Nothing to Return
Use for successful DELETE requests or updates where you don't need to return the resource body.
DELETE /api/users/123 → 204 (no response body)
400 Bad Request — Client Sent Garbage
Use when the request is malformed — invalid JSON, wrong data types, missing required fields that prevent the server from even understanding what the client wants.
POST /api/users with body: {invalid json}
→ 400 "Request body is not valid JSON"
401 Unauthorized — Who Are You?
Use when the request lacks valid authentication credentials. The client needs to log in or provide a valid token.
GET /api/me (no Authorization header)
→ 401 "Authentication required"
403 Forbidden — Not Allowed
Use when the client is authenticated but doesn't have permission. Re-authenticating won't help — this user simply doesn't have access.
DELETE /api/admin/settings (as regular user)
→ 403 "Admin access required"
404 Not Found — Doesn't Exist
Use when the requested resource doesn't exist. Also commonly used to hide the existence of resources from unauthorized users.
GET /api/users/999999
→ 404 "User not found"
409 Conflict — Can't Do That Right Now
Use when the request conflicts with the current state. Common for duplicate entries or edit conflicts.
POST /api/users with duplicate email
→ 409 "A user with this email already exists"
422 Unprocessable Entity — Understood But Invalid
Use when the request is syntactically correct but fails validation rules. The server understood it but won't process it.
POST /api/users { "email": "not-an-email", "age": -5 }
→ 422 { "errors": { "email": "Invalid format", "age": "Must be positive" } }
429 Too Many Requests — Slow Down
Use for rate limiting. Include a Retry-After header to tell the client when they can try again.
500 Internal Server Error — We Broke
Use when something unexpected went wrong on the server. Log the details server-side but don't expose them to the client.
Common Mistakes
- Using 200 for everything — even errors. This makes client-side error handling impossible.
- Confusing 401 and 403 — 401 means "not authenticated", 403 means "not authorized".
- Using 404 when you mean 400 — a bad parameter value is a 400, not a 404.
- Using 500 for validation errors — user input errors should be 4xx, not 5xx.
Decision Tree
When choosing a status code, ask yourself:
- Did the request succeed? → 2xx
- Should the client go somewhere else? → 3xx
- Did the client do something wrong? → 4xx
- Did the server have an internal problem? → 5xx
For the full list of status codes with detailed descriptions, check out our HTTP Status Codes cheat sheet.