← Back to Blog

HTTP Status Codes Explained: A Complete Reference for API Developers

A systematic guide to HTTP status codes covering all major categories, proper usage patterns, common mistakes, and REST API conventions. Everything you need to design consistent, predictable APIs.

Alex Kowalski
Alex KowalskiBackend Developer & API Architect

HTTP status codes form the foundation of communication between clients and servers. They are the first piece of information a client receives about the outcome of their request. Yet in my years of reviewing API designs, I consistently encounter misused status codes that create confusion, break client implementations, and make debugging unnecessarily difficult.

This guide provides a systematic overview of HTTP status codes, organized by category. For each code, I will explain what it means, when to use it, and common mistakes to avoid.

The Five Categories

HTTP status codes are divided into five categories based on their first digit:

  • 1xx (Informational): Request received, continuing process
  • 2xx (Success): Request successfully received, understood, and accepted
  • 3xx (Redirection): Further action needed to complete the request
  • 4xx (Client Error): Request contains bad syntax or cannot be fulfilled
  • 5xx (Server Error): Server failed to fulfill a valid request

This categorization is fundamental. Clients can make initial handling decisions based solely on the first digit, even for codes they do not specifically recognize.

1xx Informational Responses

Informational responses indicate that the server has received the request and is continuing to process it. These are rarely used in typical web applications but have specific purposes.

100 Continue

The server has received the request headers and the client should proceed to send the request body. This is useful for large uploads where the client wants to verify the server will accept the request before transmitting a potentially large body.

Client Request: POST /api/upload HTTP/1.1 Host: api.example.com Content-Length: 50000000 Expect: 100-continue Server Response: HTTP/1.1 100 Continue

101 Switching Protocols

The server is switching protocols as requested by the client. Most commonly seen during WebSocket handshakes.

Client Request: GET /chat HTTP/1.1 Host: example.com Upgrade: websocket Connection: Upgrade Server Response: HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade

102 Processing (WebDAV)

Used in WebDAV to indicate that the server has received and is processing the request, but no response is available yet. Prevents client timeouts during long operations.

2xx Success Codes

Success codes indicate that the client's request was received, understood, and accepted. The specific code provides additional context about the nature of the success.

200 OK

The standard success response. The actual meaning depends on the HTTP method:

  • GET: The resource has been fetched and transmitted in the message body
  • POST: The resource describing the result of the action is transmitted in the body
  • PUT/PATCH: The resource has been updated successfully
  • DELETE: The resource has been deleted (though 204 is often preferred)
HTTP/1.1 200 OK Content-Type: application/json { "id": "user_123", "name": "Alice", "email": "[email protected]" }

201 Created

A new resource has been created as a result of the request. This should be the response for successful POST requests that create resources. Include a Location header pointing to the new resource.

HTTP/1.1 201 Created Location: /api/users/user_456 Content-Type: application/json { "id": "user_456", "name": "Bob", "email": "[email protected]" }

Common Mistake: Using 200 for resource creation. While technically valid, 201 provides clearer semantics and sets client expectations correctly.

202 Accepted

The request has been accepted for processing, but processing has not completed. This is appropriate for asynchronous operations.

HTTP/1.1 202 Accepted Content-Type: application/json { "jobId": "job_789", "status": "pending", "statusUrl": "/api/jobs/job_789" }

Use 202 when the operation will complete asynchronously. Provide a way for clients to check the operation status.

204 No Content

The request succeeded, but there is no content to send back. Common for DELETE operations or PUT operations that do not need to return the updated resource.

HTTP/1.1 204 No Content

Important: 204 responses must not include a body. Including a body is a protocol violation.

206 Partial Content

The server is delivering only part of the resource due to a range header sent by the client. Used for resumable downloads and video streaming.

HTTP/1.1 206 Partial Content Content-Range: bytes 0-1023/10240 Content-Length: 1024

3xx Redirection Codes

Redirection codes indicate that further action is needed to complete the request, typically involving a different URI.

301 Moved Permanently

The requested resource has been permanently moved to a new URI. Clients should update bookmarks and use the new URI for future requests.

HTTP/1.1 301 Moved Permanently Location: https://api.example.com/v2/users

Use 301 for permanent URL changes, such as moving from HTTP to HTTPS or restructuring your API paths.

302 Found

The resource temporarily resides at a different URI. Clients should continue to use the original URI for future requests. Historically, browsers incorrectly changed POST to GET on redirect. Use 307 if method preservation is critical.

303 See Other

The response to the request can be found at another URI using GET. Commonly used after POST requests to redirect to a confirmation page.

HTTP/1.1 303 See Other Location: /api/orders/order_123

304 Not Modified

Used for caching. Indicates that the resource has not been modified since the version specified by the request headers (If-Modified-Since or If-None-Match).

Client Request: GET /api/users/123 HTTP/1.1 If-None-Match: "abc123" Server Response: HTTP/1.1 304 Not Modified ETag: "abc123"

Proper use of 304 significantly reduces bandwidth and improves performance.

307 Temporary Redirect

Like 302, but guarantees that the method and body will not be changed during the redirect. Use this for POST redirects where you need to preserve the request method.

308 Permanent Redirect

Like 301, but guarantees that the method and body will not be changed. The permanent equivalent of 307.

4xx Client Error Codes

Client error codes indicate that the request contains errors or cannot be fulfilled due to client-side issues. The server should include an explanation of the error in the response body.

400 Bad Request

The server cannot process the request due to client error. This includes malformed syntax, invalid request framing, or deceptive request routing.

HTTP/1.1 400 Bad Request Content-Type: application/json { "error": { "code": "INVALID_REQUEST", "message": "Request body must be valid JSON", "details": { "parseError": "Unexpected token at position 45" } } }

Use 400 for:

  • Malformed JSON or XML
  • Missing required fields
  • Invalid field formats
  • General validation errors

Common Mistake: Using 400 for authentication failures. Use 401 instead.

401 Unauthorized

Authentication is required and has failed or not been provided. Despite the name "Unauthorized," this code indicates an authentication problem, not authorization.

HTTP/1.1 401 Unauthorized WWW-Authenticate: Bearer realm="api" Content-Type: application/json { "error": { "code": "AUTHENTICATION_REQUIRED", "message": "Valid authentication credentials are required" } }

Always include the WWW-Authenticate header indicating the authentication scheme.

403 Forbidden

The server understood the request but refuses to authorize it. Unlike 401, authentication will not help. The client does not have permission for this action.

HTTP/1.1 403 Forbidden Content-Type: application/json { "error": { "code": "INSUFFICIENT_PERMISSIONS", "message": "Admin role required to access this resource" } }

Use 403 when:

  • The user is authenticated but lacks permissions
  • Access is forbidden regardless of authentication
  • The resource exists but the user cannot access it

Decision Guide: 401 means "I don't know who you are." 403 means "I know who you are, but you can't do this."

404 Not Found

The requested resource could not be found. This can mean the resource does not exist or that the server is unwilling to disclose its existence.

HTTP/1.1 404 Not Found Content-Type: application/json { "error": { "code": "RESOURCE_NOT_FOUND", "message": "User with id 'user_999' not found" } }

Security Consideration: Sometimes 403 should be returned as 404 to avoid leaking information about resource existence. If knowing that a resource exists is sensitive, return 404 even for authorization failures.

405 Method Not Allowed

The method specified in the request is not allowed for the resource. Include an Allow header listing valid methods.

HTTP/1.1 405 Method Not Allowed Allow: GET, POST Content-Type: application/json { "error": { "code": "METHOD_NOT_ALLOWED", "message": "DELETE is not supported for this resource" } }

409 Conflict

The request conflicts with the current state of the resource. Common for concurrent modification issues or duplicate resource creation.

HTTP/1.1 409 Conflict Content-Type: application/json { "error": { "code": "DUPLICATE_RESOURCE", "message": "A user with this email already exists", "conflictingField": "email" } }

Use 409 for:

  • Duplicate unique field violations
  • Concurrent edit conflicts
  • State transition violations

410 Gone

The resource is no longer available and will not be available again. Unlike 404, this is a permanent condition.

HTTP/1.1 410 Gone Content-Type: application/json { "error": { "code": "RESOURCE_DELETED", "message": "This account was permanently deleted on 2025-01-15" } }

Use 410 when you want clients to stop requesting a resource and remove any cached references.

415 Unsupported Media Type

The media format of the request is not supported. Common when clients send the wrong Content-Type.

HTTP/1.1 415 Unsupported Media Type Content-Type: application/json { "error": { "code": "UNSUPPORTED_MEDIA_TYPE", "message": "Content-Type must be application/json", "supportedTypes": ["application/json"] } }

422 Unprocessable Entity

The request is syntactically correct but semantically invalid. Often used for validation errors where the JSON is valid but the business rules are violated.

HTTP/1.1 422 Unprocessable Entity Content-Type: application/json { "error": { "code": "VALIDATION_ERROR", "message": "Validation failed", "fields": { "email": "Must be a valid email address", "age": "Must be between 18 and 120" } } }

400 vs 422: Use 400 for syntactically invalid requests (malformed JSON). Use 422 for syntactically valid but semantically invalid requests (valid JSON but invalid data).

429 Too Many Requests

Rate limiting response. The user has sent too many requests in a given time period.

HTTP/1.1 429 Too Many Requests Retry-After: 60 X-RateLimit-Limit: 100 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 1699977600 Content-Type: application/json { "error": { "code": "RATE_LIMITED", "message": "Rate limit exceeded. Please retry after 60 seconds" } }

Always include Retry-After header. Consider including rate limit headers to help clients manage their request rate.

5xx Server Error Codes

Server error codes indicate that the server failed to fulfill a valid request. These represent bugs, configuration issues, or downstream service failures.

500 Internal Server Error

A generic server error when no more specific error is applicable. This indicates an unexpected condition on the server.

HTTP/1.1 500 Internal Server Error Content-Type: application/json { "error": { "code": "INTERNAL_ERROR", "message": "An unexpected error occurred", "requestId": "req_abc123" } }

Important: Never expose stack traces or internal details in production 500 responses. Include a request ID for correlation with server logs.

502 Bad Gateway

The server, acting as a gateway or proxy, received an invalid response from an upstream server.

HTTP/1.1 502 Bad Gateway Content-Type: application/json { "error": { "code": "UPSTREAM_ERROR", "message": "Failed to connect to payment service" } }

Use 502 when your service depends on another service that is returning errors.

503 Service Unavailable

The server is currently unable to handle the request due to maintenance or overload. This should be temporary.

HTTP/1.1 503 Service Unavailable Retry-After: 300 Content-Type: application/json { "error": { "code": "SERVICE_UNAVAILABLE", "message": "System under maintenance. Please try again in 5 minutes" } }

Include Retry-After header when possible. Use 503 for planned maintenance windows.

504 Gateway Timeout

The server, acting as a gateway, did not receive a timely response from an upstream server.

HTTP/1.1 504 Gateway Timeout Content-Type: application/json { "error": { "code": "UPSTREAM_TIMEOUT", "message": "Request timed out while waiting for response" } }

REST API Conventions

Beyond individual status codes, consistent patterns make APIs predictable and easier to use.

Response Structure

Maintain consistent response structures across all endpoints:

// Success response { "data": { ... }, "meta": { "pagination": { ... } } } // Error response { "error": { "code": "ERROR_CODE", "message": "Human readable message", "details": { ... } } }

Status Code Summary by Method

MethodSuccessCreatedNo ContentCommon Errors
GET200--404, 403
POST200201-400, 409, 422
PUT200201204400, 404, 409
PATCH200-204400, 404, 422
DELETE200-204404, 403

Common Mistakes to Avoid

  1. Using 200 for everything: Clients cannot distinguish between success types
  2. Returning 200 with error in body: Breaks HTTP semantics and caching
  3. Using 500 for client errors: Makes debugging difficult and triggers unnecessary alerts
  4. Inconsistent error formats: Forces clients to handle multiple response shapes
  5. Missing Location header on 201: Clients cannot find the created resource
  6. Using 404 when 403 is appropriate: Leaks information about resource existence
  7. Not including Retry-After on 429/503: Clients cannot implement intelligent backoff

Conclusion

HTTP status codes are a standardized vocabulary for server-client communication. Using them correctly makes your APIs predictable, debuggable, and easier to integrate with.

The key principles are:

  1. Use the most specific applicable status code
  2. Keep response formats consistent across all codes
  3. Include actionable information in error responses
  4. Use headers like Location, Retry-After, and Allow appropriately
  5. Consider security implications of your status code choices

A well-designed API communicates clearly through its status codes alone. Before a client parses a single byte of your response body, the status code should tell them what happened and what to do next.

Alex Kowalski
Written byAlex KowalskiBackend Developer & API Architect
Read more articles