Introduction

HTTP status codes are three-digit numbers that indicate the result of an HTTP request. Understanding them is crucial for building and debugging REST APIs. This guide covers all status codes and when to use them.

Status Code Categories

1xx: Informational

Temporary responses indicating the request was received and being processed.

  • 100 Continue: Server received headers, client should send body
  • 101 Switching Protocols: Server agrees to protocol upgrade
  • 102 Processing: Request is being processed (WebDAV)
  • 103 Early Hints: Some headers available (H2/H3)

2xx: Success

Request was successfully received, understood, and accepted.

200 OK

Standard success response:

GET /api/users/1 HTTP/1.1
Host: api.example.com

HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": 1,
  "name": "Alice"
}

Use for:

  • GET requests (retrieve resource)
  • PUT requests (update successful)
  • POST requests (when no specific code fits)

201 Created

Resource successfully created:

POST /api/users HTTP/1.1
Content-Type: application/json

{
  "name": "Bob",
  "email": "bob@example.com"
}

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

{
  "id": 123,
  "name": "Bob",
  "email": "bob@example.com"
}

Use for:

  • POST requests (resource created)
  • Include Location header with new resource URL

204 No Content

Success with no response body:

DELETE /api/users/123 HTTP/1.1

HTTP/1.1 204 No Content

Use for:

  • DELETE requests (resource deleted)
  • PUT requests (update, nothing to return)
  • Headers-only responses

202 Accepted

Request accepted for processing (async):

POST /api/jobs HTTP/1.1

HTTP/1.1 202 Accepted
Location: /api/jobs/456/status

Use for:

  • Asynchronous processing
  • Background jobs
  • Long-running operations

3xx: Redirection

Client must take additional action to complete request.

301 Moved Permanently

Resource permanently moved:

GET /old-page HTTP/1.1

HTTP/1.1 301 Moved Permanently
Location: /new-page

Use for:

  • Permanent URL changes
  • SEO redirects
  • Domain migrations

302 Found (Temporary Redirect)

Resource temporarily moved:

HTTP/1.1 302 Found
Location: /temporary-location

Use for:

  • Temporary redirects
  • Maintenance pages

304 Not Modified

Resource not modified (caching):

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

HTTP/1.1 304 Not Modified
ETag: "abc123"

Use for:

  • Conditional requests
  • Cache validation

4xx: Client Errors

Client made an error (bad request, unauthorized, etc.).

400 Bad Request

Malformed request:

{
  "error": "Invalid request body",
  "details": {
    "email": "Must be valid email address"
  }
}

Use for:

  • Validation errors
  • Malformed JSON
  • Missing required fields

401 Unauthorized

Authentication required:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer

{
  "error": "Authentication required"
}

Use for:

  • Missing or invalid credentials
  • Expired tokens

403 Forbidden

Authenticated but not authorized:

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

Use for:

  • Insufficient permissions
  • Resource access denied

404 Not Found

Resource doesn’t exist:

GET /api/users/999 HTTP/1.1

HTTP/1.1 404 Not Found

{
  "error": "User not found"
}

Use for:

  • Resource doesn’t exist
  • Invalid URL
  • Deleted resource

409 Conflict

Request conflicts with current state:

{
  "error": "Email already exists",
  "conflict": {
    "field": "email",
    "value": "user@example.com"
  }
}

Use for:

  • Duplicate entries
  • Version conflicts
  • Resource state conflicts

422 Unprocessable Entity

Well-formed but semantically invalid:

{
  "error": "Validation failed",
  "errors": [
    {
      "field": "age",
      "message": "Must be positive number"
    }
  ]
}

Use for:

  • Validation errors
  • Business logic violations

5xx: Server Errors

Server failed to fulfill valid request.

500 Internal Server Error

Generic server error:

{
  "error": "Internal server error",
  "requestId": "abc-123-def"
}

Use for:

  • Unexpected server errors
  • Database failures
  • Application crashes

502 Bad Gateway

Invalid response from upstream server:

HTTP/1.1 502 Bad Gateway

Use for:

  • Proxy/gateway issues
  • Upstream server errors

503 Service Unavailable

Service temporarily unavailable:

HTTP/1.1 503 Service Unavailable
Retry-After: 60

Use for:

  • Maintenance mode
  • Overloaded servers
  • Temporary outages

REST API Status Code Usage

GET Requests

// Resource found
GET /api/users/1
200 OK

// Resource not found
GET /api/users/999
404 Not Found

// Not modified (caching)
GET /api/data (with If-None-Match)
304 Not Modified

POST Requests

// Resource created
POST /api/users
201 Created (with Location header)

// Validation error
POST /api/users (invalid data)
400 Bad Request

// Conflict
POST /api/users (duplicate email)
409 Conflict

PUT Requests

// Updated successfully
PUT /api/users/1
200 OK (with updated resource)
204 No Content (no body)

// Resource not found
PUT /api/users/999
404 Not Found

// Validation error
PUT /api/users/1 (invalid data)
400 Bad Request

DELETE Requests

// Deleted successfully
DELETE /api/users/1
204 No Content

// Resource not found
DELETE /api/users/999
404 Not Found

// Conflict (cannot delete)
DELETE /api/users/1 (has dependencies)
409 Conflict

Best Practices

✅ Do This

1. Use appropriate status codes

if (!user) {
  return res.status(404).json({ error: "User not found" });
}

if (user.email === newEmail) {
  return res.status(409).json({ error: "Email already exists" });
}

return res.status(200).json(user);

2. Include error details

{
  "error": "Validation failed",
  "code": "VALIDATION_ERROR",
  "details": [
    {
      "field": "email",
      "message": "Must be valid email"
    }
  ]
}

3. Use consistent error format

interface ApiError {
  error: string;
  code: string;
  details?: any;
  requestId: string;
}

❌ Don’t Do This

1. Don’t use 200 for errors

// ❌ Bad
return res.status(200).json({ error: "Not found" });

// ✅ Good
return res.status(404).json({ error: "Not found" });

2. Don’t expose internal errors

// ❌ Bad - exposes stack trace
return res.status(500).json({
  error: error.message,
  stack: error.stack,
});

// ✅ Good
return res.status(500).json({
  error: "Internal server error",
  requestId: req.id,
});

Status Code Reference

Use our tools:

Conclusion

HTTP status codes are essential for REST APIs:

Key principles:

  • 2xx = Success
  • 3xx = Redirection
  • 4xx = Client error
  • 5xx = Server error

Best practices:

  • Use appropriate codes
  • Include helpful error messages
  • Be consistent
  • Document your API

Next Steps