REST API Status Code Chooser
Choose an API outcome to see the status code, reason, and example response. Each scenario has a link you can share.
Browse all 20 API outcomes
Choosing between 409 and 422? See the duplicate-email worked case.
Request succeeded and returns a representation
The request succeeded and the response body contains the requested representation or operation result.
Example response
HTTP/1.1 200 OK
Content-Type: application/json
{"id":"user_123","name":"Ada"}
Request created a new resource
The request created a new resource. Include a Location header when the new resource has its own URL.
Example response
HTTP/1.1 201 Created
Location: /users/user_123
Content-Type: application/json
{"id":"user_123"}
Request was accepted for async processing
The request was accepted, but processing has not completed yet.
Example response
HTTP/1.1 202 Accepted
Content-Type: application/json
{"jobId":"job_123","status":"queued"}
Request succeeded and intentionally returns no body
The request succeeded and an empty response body is intentional.
Example response
HTTP/1.1 204 No Content
Request syntax, JSON, query, or shape is invalid
The request syntax, JSON, query string, headers, or required shape is invalid.
Example response
HTTP/1.1 400 Bad Request
Content-Type: application/json
{"error":"Invalid JSON body"}
Authentication is missing, expired, or invalid
Authentication is missing, invalid, or expired. The client may retry with valid credentials.
Example response
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer
Content-Type: application/json
{"error":"Authentication required"}
Caller is authenticated and access is denied
The request was understood, but the authenticated caller is not allowed to perform the action.
Example response
HTTP/1.1 403 Forbidden
Content-Type: application/json
{"error":"Permission denied"}
Resource does not exist or should not be revealed
The resource does not exist, or the API should not reveal whether it exists.
Example response
HTTP/1.1 404 Not Found
Content-Type: application/json
{"error":"Resource not found"}
Request conflicts with current resource state
The request conflicts with current resource state, such as a duplicate key, version mismatch, or edit conflict.
Example response
HTTP/1.1 409 Conflict
Content-Type: application/json
{"error":"Version conflict"}
Resource was intentionally removed permanently
The resource was intentionally removed and should be treated as permanently unavailable.
Example response
HTTP/1.1 410 Gone
Content-Type: application/json
{"error":"Resource permanently removed"}
Request body or upload is too large
The request body, upload, or submitted payload exceeds the server limit.
Example response
HTTP/1.1 413 Content Too Large
Content-Type: application/json
{"error":"Upload exceeds 10 MB"}
Content-Type is unsupported
The request Content-Type is not supported by this endpoint.
Example response
HTTP/1.1 415 Unsupported Media Type
Content-Type: application/json
{"error":"Use application/json"}
Request is syntactically valid but semantically invalid
The request is syntactically valid, but the submitted data fails semantic or domain validation.
Example response
HTTP/1.1 422 Unprocessable Content
Content-Type: application/json
{"error":"End date must follow start date"}
Client, user, or API key exceeded a rate limit
The client, user, IP address, or API key exceeded a rate limit.
Example response
HTTP/1.1 429 Too Many Requests
Retry-After: 60
Content-Type: application/json
{"error":"Rate limit exceeded"}
Resource moved permanently
The resource moved permanently and the client should preserve the original request method and body. Use 301 for browser-oriented GET redirects.
Example response
HTTP/1.1 308 Permanent Redirect
Location: https://api.example.com/v2/users
Resource moved temporarily
The resource moved temporarily and the client should preserve the original request method and body. Use 302 only when method preservation is not required.
Example response
HTTP/1.1 307 Temporary Redirect
Location: https://api-backup.example.com/users
Unexpected application failure
The server hit an unexpected application failure without a more specific status code.
Example response
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{"error":"Unexpected server error"}
Gateway received a bad upstream response
A proxy or gateway received an invalid response from an upstream service.
Example response
HTTP/1.1 502 Bad Gateway
Content-Type: application/json
{"error":"Bad upstream response"}
Gateway did not receive an upstream response in time
A server acting as a gateway or proxy did not receive a timely response from an upstream server needed to complete the request.
Example response
HTTP/1.1 504 Gateway Timeout
Content-Type: application/json
{"error":"Upstream timeout"}
409 or 422 for a duplicate email?
Use 409 Conflict when an existing account prevents creation under the endpoint's resource-state rules. 422 Unprocessable Content can fit an API that treats uniqueness as field validation. Document the choice and what the client should change; retrying the same request will not remove the duplicate.
RFC 9110's 409 definition concerns a conflict with current resource state; its 422 definition concerns understood, syntactically correct content whose instructions cannot be processed. Neither assigns a mandatory status to duplicate email addresses.
Authenticated administrative creation
Consider POST /admin/teams/team_123/users with {"email":"ada@example.com"}. The administrator is authenticated and authorized to create users and learn account membership within this team. Email addresses must be unique within that scope. These are two alternative API contracts for the same duplicate; choose one consistently.
409: creation conflicts with the team's user collection
The address is valid, but a user in this team already has it. Return a conflict the administrator can resolve by choosing another address or using the existing user.
HTTP/1.1 409 Conflict
Content-Type: application/problem+json
Cache-Control: no-store
{
"type": "https://api.example.com/problems/email-conflict",
"title": "Email already in use",
"status": 409,
"detail": "This email belongs to a user in this team. Choose another email or use the existing user."
}
422: the documented contract treats uniqueness as field validation
If the API reports uniqueness failures through its validation contract, identify the email field so the form can show a correction. The client must change the input or use the authorized existing-account workflow.
HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json
Cache-Control: no-store
{
"type": "https://api.example.com/problems/validation-error",
"title": "Request validation failed",
"status": 422,
"errors": [
{ "detail": "Email is already in use in this team", "pointer": "/email" }
]
}
Both examples use RFC 9457 Problem Details, with the body status matching the HTTP status. The example type URIs and errors extension belong to this API's contract; define your own stable types. Clients should use those identifiers and structured fields, rather than parsing human-readable messages.
Public signup needs a separate privacy decision
A public caller may not be allowed to learn whether an email is registered. OWASP's authentication guidance covers generic registration messages and warns about response-code and timing differences. Changing only the body still leaks membership if new and existing addresses receive different statuses or noticeably different processing times.
When membership must stay private, design a common accepted signup workflow, such as sending next steps by email, with the same outward status and generic body for new and existing addresses. Keep processing paths and timing comparable instead of quickly exiting only for duplicates. Use 202 only when the request is accepted for later processing; a generic response must describe what the workflow does.
REST API status code rules
- Use precise 2xx responses instead of returning 200 for every successful request.
- Use the real HTTP status code. A failure returned as 200 OK with a JSON status field looks successful to generic HTTP tooling.
- Use 401 for authentication problems and 403 for authorization problems.
- Send the headers the status code requires, such as
WWW-Authenticatewith 401 andAllowwith 405. The response obligations table lists each rule with its RFC section. - Use 404 when the resource is missing or you do not want to reveal whether it exists.
- Use 409 for state conflicts, 422 for valid requests with invalid domain data, and 429 for rate limits.
- Use 500 only when no more specific 5xx response describes the server-side failure.
HTTP status codes and JSON error bodies
Use the HTTP status code for the generic result that clients, proxies, logs, caches, and monitoring tools can understand. Use the response body for your application-specific details.
For a rejected operation, choose the matching error status and explain what the client can change. The duplicate-email case shows how the endpoint contract and disclosure permissions affect that choice. Returning 200 OK with {"status":"error"} makes generic HTTP tooling treat the request as a success.
When the API needs a standard error format, follow the RFC 9457 Problem Details guide and return application/problem+json.
Common questions
Should validation errors use 400 or 422?
Use 400 when the request is malformed. Use 422 when the request shape is valid but the submitted domain data cannot be processed.
Should missing authentication use 401 or 403?
Use 401 when the caller needs valid authentication. Use 403 when the caller is authenticated and lacks permission.
Should an API return 200 with a status field for errors?
No. Return the most accurate HTTP status code first. Then include a response body with the error code, field details, or problem information your client needs.