Back to Blog
Technicalhttpapiweb

HTTP Status Codes: A Complete Reference Guide

Every HTTP status code explained with examples. Learn when to use each code in your APIs, handle errors properly, and follow REST best practices.

Loopaloo TeamJuly 28, 202516 min read

Every time your browser loads a page or your app calls an API, the server responds with an HTTP status code. Understanding these codes is essential for debugging, building APIs, and handling errors gracefully.

What Are HTTP Status Codes?

HTTP status codes are three-digit numbers returned by servers to indicate the result of a request. They're grouped into five classes based on their first digit:

RangeCategoryMeaning
1xxInformationalRequest received, processing continues
2xxSuccessRequest successfully received and accepted
3xxRedirectionFurther action needed to complete request
4xxClient ErrorRequest contains bad syntax or cannot be fulfilled
5xxServer ErrorServer failed to fulfill a valid request

1xx Informational

These codes indicate the server received the request and is continuing to process it. You rarely see these in practice.

100 Continue

The server received the request headers and the client should proceed to send the body.

When it's used: Large file uploads. The client sends headers first, and if the server approves (correct auth, enough space), it sends 100 to signal "go ahead."

101 Switching Protocols

The server is switching protocols as requested by the client.

When it's used: WebSocket connections. The client requests an upgrade from HTTP to WebSocket:

GET /chat HTTP/1.1
Upgrade: websocket
Connection: Upgrade

Server responds with 101, then the WebSocket connection begins.

102 Processing

The server is still processing a long request.

When it's used: WebDAV operations that take a long time.

2xx Success

The request was successfully received, understood, and accepted.

200 OK

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

Method200 Means
GETResource returned in response body
POSTAction completed, result in body
PUTResource updated, result in body
DELETEDeletion completed (some APIs)
HTTP/1.1 200 OK
Content-Type: application/json

{"id": 123, "name": "John"}

201 Created

A new resource was successfully created. Should include a Location header with the new resource's URL.

Use for: POST requests that create resources.

HTTP/1.1 201 Created
Location: /api/users/123
Content-Type: application/json

{"id": 123, "name": "John"}

202 Accepted

The request was accepted but hasn't been processed yet. Used for asynchronous operations.

Use for: Background jobs, batch processing, long-running tasks.

HTTP/1.1 202 Accepted
Content-Type: application/json

{"jobId": "abc123", "status": "pending", "checkUrl": "/jobs/abc123"}

204 No Content

Success, but there's no content to return.

Use for: DELETE requests, PUT requests when you don't need to return the updated resource.

HTTP/1.1 204 No Content

Note: 204 responses must not have a body.

206 Partial Content

Returning part of a resource (used with range requests).

Use for: Video streaming, resumable downloads.

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

3xx Redirection

The client must take additional action to complete the request.

301 Moved Permanently

The resource has permanently moved to a new URL. Clients should update bookmarks and search engines should update their index.

HTTP/1.1 301 Moved Permanently
Location: https://new-site.com/page

Use for: Domain changes, URL restructuring, HTTP to HTTPS redirects.

302 Found (Temporary Redirect)

The resource is temporarily at a different URL. The client should continue using the original URL for future requests.

HTTP/1.1 302 Found
Location: /temporary-page

Historical note: Browsers incorrectly changed POST to GET on 302. Use 307 if you need to preserve the method.

303 See Other

The response can be found at another URL using GET. Typically used after a POST to redirect to a result page.

Use for: POST/Redirect/GET pattern to prevent form resubmission.

304 Not Modified

The resource hasn't changed since the version in the client's cache. No body is returned.

Use for: Caching. Client sends If-Modified-Since or If-None-Match, server responds with 304 if unchanged.

GET /api/data HTTP/1.1
If-None-Match: "abc123"

HTTP/1.1 304 Not Modified

307 Temporary Redirect

Like 302, but guarantees the request method won't change.

Use for: Temporary redirects where you need to preserve POST, PUT, etc.

308 Permanent Redirect

Like 301, but guarantees the request method won't change.

Use for: Permanent redirects for non-GET requests.

4xx Client Errors

The request was invalid or cannot be fulfilled. This is the client's fault.

400 Bad Request

The request is malformed and cannot be understood.

Use for:

  • Malformed JSON
  • Invalid syntax
  • Missing required fields
  • Invalid query parameters
HTTP/1.1 400 Bad Request
Content-Type: application/json

{"error": "Invalid JSON: unexpected token at position 42"}

401 Unauthorized

Authentication is required but missing or invalid.

Use for: Missing auth token, expired token, invalid credentials.

Should include a WWW-Authenticate header:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="api"

{"error": "Invalid or expired token"}

403 Forbidden

The server understood the request but refuses to authorize it. Unlike 401, authenticating won't help.

Use for: User is authenticated but lacks permission.

HTTP/1.1 403 Forbidden

{"error": "You don't have permission to delete this resource"}

401 vs 403:

  • 401: "Who are you?" (authentication)
  • 403: "I know who you are, but you can't do this" (authorization)

404 Not Found

The requested resource doesn't exist.

HTTP/1.1 404 Not Found

{"error": "User not found"}

Security tip: Sometimes you should use 404 even when the issue is permission-based, to avoid revealing that a resource exists.

405 Method Not Allowed

The HTTP method is not supported for this endpoint.

HTTP/1.1 405 Method Not Allowed
Allow: GET, POST

406 Not Acceptable

The server can't produce a response matching the client's Accept headers.

408 Request Timeout

The client took too long to send the request.

409 Conflict

The request conflicts with the current state of the resource.

Use for:

  • Duplicate entries (email already exists)
  • Version conflicts (optimistic locking)
  • State conflicts (can't delete active subscription)
HTTP/1.1 409 Conflict

{"error": "A user with this email already exists"}

410 Gone

The resource existed but has been permanently deleted. Unlike 404, this is definitive - it won't come back.

Use for: Deleted content where you want clients to stop retrying.

413 Payload Too Large

The request body exceeds the server's limits.

HTTP/1.1 413 Payload Too Large

{"error": "File size exceeds 10MB limit"}

415 Unsupported Media Type

The request's Content-Type is not supported.

HTTP/1.1 415 Unsupported Media Type

{"error": "Content-Type must be application/json"}

422 Unprocessable Entity

The request is syntactically correct but semantically invalid.

Use for: Validation errors, business logic violations.

HTTP/1.1 422 Unprocessable Entity

{
  "error": "Validation failed",
  "details": {
    "email": "Invalid email format",
    "age": "Must be at least 18"
  }
}

400 vs 422:

  • 400: "I can't parse this" (syntax error)
  • 422: "I understand it, but it's invalid" (semantic error)

429 Too Many Requests

The client has sent too many requests (rate limiting).

HTTP/1.1 429 Too Many Requests
Retry-After: 60

{"error": "Rate limit exceeded. Try again in 60 seconds."}

Include Retry-After header to tell clients when to retry.

5xx Server Errors

The server failed to fulfill a valid request. This is the server's fault.

500 Internal Server Error

A generic server error when something unexpected happened.

HTTP/1.1 500 Internal Server Error

{"error": "An unexpected error occurred"}

Never expose internal details (stack traces, database errors) in production.

501 Not Implemented

The server doesn't support the functionality required.

Use for: Features that are planned but not yet implemented.

502 Bad Gateway

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

Common causes: Upstream server crashed, misconfigured proxy, network issues.

503 Service Unavailable

The server is temporarily unavailable (overloaded, maintenance).

HTTP/1.1 503 Service Unavailable
Retry-After: 3600

{"error": "Server is under maintenance. Back in 1 hour."}

504 Gateway Timeout

The server, acting as a gateway, didn't receive a timely response from upstream.

Common causes: Slow database queries, upstream service timeout, network latency.

API Design Best Practices

Choosing the Right Status Code

Request successful?
├─ Yes: 2xx
│   ├─ Created something? → 201
│   ├─ No content to return? → 204
│   ├─ Async processing? → 202
│   └─ Default → 200
├─ Client's fault?
│   ├─ Not authenticated? → 401
│   ├─ Not authorized? → 403
│   ├─ Resource not found? → 404
│   ├─ Validation failed? → 422
│   ├─ Rate limited? → 429
│   ├─ Malformed request? → 400
│   └─ Conflict? → 409
└─ Server's fault? → 500

Consistent Error Response Format

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": [
      {"field": "email", "message": "Invalid email format"},
      {"field": "age", "message": "Must be a positive number"}
    ]
  }
}

Common Patterns

OperationSuccessError
GET resource200404
GET collection200 (empty array is fine)-
POST create201 + Location header400/422
PUT update200 or 204404
DELETE204404
Invalid auth-401
No permission-403
Validation-422

Security Considerations

  1. Don't leak information: Return 404 instead of 403 when you don't want to confirm a resource exists.
  2. Generic 500 errors: Never expose stack traces or internal errors to clients.
  3. Consistent timing: Avoid timing attacks by taking the same time for "user not found" and "wrong password."

Handling Status Codes in Code

JavaScript/Fetch

const response = await fetch('/api/users');

if (response.ok) {  // 200-299
  const data = await response.json();
} else if (response.status === 401) {
  // Redirect to login
} else if (response.status === 404) {
  // Show "not found" message
} else if (response.status >= 500) {
  // Show "server error" message
}

Axios

try {
  const { data } = await axios.get('/api/users');
} catch (error) {
  if (error.response) {
    // Server responded with error
    const { status, data } = error.response;
    if (status === 401) {
      // Handle auth error
    }
  } else if (error.request) {
    // No response received
  } else {
    // Request setup error
  }
}

Quick Reference

CodeNameWhen to Use
200OKStandard success
201CreatedResource created (POST)
204No ContentSuccess, no body (DELETE)
301Moved PermanentlyURL changed forever
304Not ModifiedUse cache
400Bad RequestMalformed request
401UnauthorizedAuth required
403ForbiddenPermission denied
404Not FoundResource doesn't exist
409ConflictState conflict
422UnprocessableValidation failed
429Too Many RequestsRate limited
500Internal Server ErrorServer error
502Bad GatewayUpstream error
503Service UnavailableMaintenance/overload

Use our HTTP Status Codes reference tool for quick lookups and examples.

Related Tools

Related Articles

Try Our Free Tools

200+ browser-based tools for developers and creators. No uploads, complete privacy.

Explore All Tools