Technical

HTTP Status Codes Cheat Sheet: Quick Reference + Real Examples

The complete guide to when to use 200 vs 201, 401 vs 403, and every other status code

By Chandler Supple7 min read

Using the wrong HTTP status code is the #1 REST API mistake. This cheat sheet covers all 50+ status codes with when to use each one, plus code examples you can copy.

Quick Reference Table: Most Common Status Codes

CodeNameWhen to Use
200OKSuccessful GET, PUT, PATCH, DELETE with response body
201CreatedSuccessful POST that created a new resource
204No ContentSuccessful request with no response body (DELETE)
301Moved PermanentlyResource permanently moved to new URL
304Not ModifiedCached resource unchanged (conditional GET)
400Bad RequestInvalid request syntax, malformed JSON
401UnauthorizedMissing or invalid authentication
403ForbiddenAuthenticated but insufficient permissions
404Not FoundResource doesn't exist at this URL
409ConflictRequest conflicts with current state (duplicate)
422Unprocessable EntityValid syntax but semantic errors (validation)
429Too Many RequestsRate limit exceeded
500Internal Server ErrorUnexpected server error (bug, crash)
502Bad GatewayInvalid response from upstream server
503Service UnavailableServer temporarily unavailable (maintenance)
504Gateway TimeoutUpstream server didn't respond in time

2xx Success Codes (Detailed)

200 OK

Use for: Successful GET, PUT, PATCH, or DELETE when returning response body.

// GET /users/123
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": 123,
  "name": "John Doe",
  "email": "john@example.com"
}

201 Created

Use for: Successful POST that creates a new resource. Include Location header.

// POST /users
HTTP/1.1 201 Created
Content-Type: application/json
Location: /users/456

{
  "id": 456,
  "name": "Jane Doe",
  "email": "jane@example.com"
}

204 No Content

Use for: Successful operation with no response body. Common for DELETE.

// DELETE /users/123
HTTP/1.1 204 No Content

202 Accepted

Use for: Async operations where processing continues in background.

// POST /reports (starts long-running job)
HTTP/1.1 202 Accepted
Content-Type: application/json

{
  "job_id": "abc123",
  "status": "processing",
  "check_url": "/jobs/abc123"
}

3xx Redirection Codes

301 Moved Permanently

Use for: Resource permanently moved. Browsers/crawlers update bookmarks.

// GET /api/v1/users (deprecated)
HTTP/1.1 301 Moved Permanently
Location: /api/v2/users

302 Found (Temporary Redirect)

Use for: Temporary redirect. Client should continue using original URL.

304 Not Modified

Use for: Conditional GET where resource hasn't changed. Saves bandwidth.

// GET /users/123 with If-None-Match header
HTTP/1.1 304 Not Modified
ETag: "abc123"

4xx Client Error Codes (The Tricky Ones)

400 Bad Request

Use for: Malformed syntax, invalid JSON, type errors.

// POST /users with invalid JSON
HTTP/1.1 400 Bad Request
Content-Type: application/json

{
  "error": {
    "code": "invalid_json",
    "message": "Request body is not valid JSON",
    "details": "Unexpected token at position 42"
  }
}

401 Unauthorized vs 403 Forbidden

This is the most commonly confused pair.

ScenarioUse CodeWhy
No token provided401Not authenticated
Invalid/expired token401Not authenticated
Valid token, wrong role403Authenticated but not authorized
Valid token, resource forbidden403Authenticated but not authorized

401 Unauthorized (actually means "Unauthenticated"):

// GET /account without Authorization header
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer

{
  "error": {
    "code": "authentication_required",
    "message": "Please provide a valid access token"
  }
}

403 Forbidden:

// GET /admin/users with valid user token (not admin)
HTTP/1.1 403 Forbidden

{
  "error": {
    "code": "insufficient_permissions",
    "message": "Admin role required to access this resource"
  }
}

404 Not Found

Use for: Resource doesn't exist at this URL.

// GET /users/99999
HTTP/1.1 404 Not Found

{
  "error": {
    "code": "not_found",
    "message": "User with ID 99999 not found"
  }
}

409 Conflict

Use for: Request conflicts with current resource state (duplicates, versioning).

// POST /users with existing email
HTTP/1.1 409 Conflict

{
  "error": {
    "code": "duplicate_email",
    "message": "A user with this email already exists"
  }
}

422 Unprocessable Entity vs 400 Bad Request

ScenarioUse CodeWhy
Invalid JSON syntax400Malformed request
Missing required field422Valid syntax, validation failed
Invalid email format422Valid syntax, semantic error
Type mismatch (string instead of int)400Schema violation
// POST /users with invalid email (valid JSON, semantic error)
HTTP/1.1 422 Unprocessable Entity

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

429 Too Many Requests

Use for: Rate limit exceeded. Include Retry-After header.

HTTP/1.1 429 Too Many Requests
Retry-After: 60
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1704067200

{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded. Please retry after 60 seconds."
  }
}

5xx Server Error Codes

500 Internal Server Error

Use for: Unexpected server errors (bugs, uncaught exceptions).

HTTP/1.1 500 Internal Server Error

{
  "error": {
    "code": "internal_error",
    "message": "An unexpected error occurred. Please try again.",
    "request_id": "req_abc123"  // For debugging
  }
}

502 Bad Gateway

Use for: Your server received invalid response from upstream service.

503 Service Unavailable

Use for: Server temporarily unavailable (maintenance, overload).

HTTP/1.1 503 Service Unavailable
Retry-After: 3600

{
  "error": {
    "code": "service_unavailable",
    "message": "Service is under maintenance. Please try again in 1 hour."
  }
}

504 Gateway Timeout

Use for: Upstream service didn't respond in time.

Complete Status Code Reference

1xx Informational

CodeNameUse Case
100ContinueServer received headers, client should send body
101Switching ProtocolsUpgrading to WebSocket
102ProcessingRequest received, still processing (WebDAV)

2xx Success

CodeNameUse Case
200OKStandard successful response
201CreatedResource created successfully
202AcceptedRequest accepted, processing async
204No ContentSuccess with no response body
206Partial ContentRange request fulfilled

3xx Redirection

CodeNameUse Case
301Moved PermanentlyResource permanently moved
302FoundTemporary redirect
304Not ModifiedCached resource unchanged
307Temporary RedirectRedirect preserving method
308Permanent RedirectPermanent redirect preserving method

4xx Client Errors

CodeNameUse Case
400Bad RequestMalformed syntax
401UnauthorizedNot authenticated
403ForbiddenAuthenticated but not authorized
404Not FoundResource doesn't exist
405Method Not AllowedHTTP method not supported
409ConflictConflicts with current state
410GoneResource permanently deleted
413Payload Too LargeRequest body too large
415Unsupported Media TypeContent-Type not supported
422Unprocessable EntityValidation errors
429Too Many RequestsRate limited

5xx Server Errors

CodeNameUse Case
500Internal Server ErrorUnexpected server error
501Not ImplementedServer doesn't support functionality
502Bad GatewayInvalid upstream response
503Service UnavailableTemporarily unavailable
504Gateway TimeoutUpstream timeout

Frequently Asked Questions

What's the difference between 401 and 403?

401 = "Who are you?" (not authenticated). 403 = "I know who you are, but you can't do this" (not authorized). Use 401 when no valid credentials provided. Use 403 when credentials are valid but the user lacks permission for this specific action.

When should I use 400 vs 422?

400 = malformed request (can't parse). 422 = valid syntax but semantic errors (validation failed). Invalid JSON → 400. Valid JSON with invalid email format → 422. Some APIs use 400 for both, which is acceptable but less precise.

Should DELETE return 200 or 204?

204 if no response body, 200 if returning deleted resource data. 204 is more common and saves bandwidth. 200 with the deleted object is useful if clients need confirmation of what was deleted.

What should I return for a missing optional resource?

Return 200 with null or empty array, not 404. GET /users/123/avatar when user has no avatar → 200 with {"avatar": null}. 404 means "this URL doesn't exist." A user without an avatar is different from a nonexistent user.

Can I create custom status codes?

No. Use standard codes only. HTTP status codes are standardized. Custom codes (e.g., 499) break standard tooling and confuse developers. Put custom error information in the response body with standard status codes.

What status code for partial success in batch operations?

207 Multi-Status (WebDAV) or 200 with detailed response body. When a batch operation succeeds for some items and fails for others, return 200/207 with per-item status in the response body. Don't return 500 for partial failures.

Use this cheat sheet as your HTTP status code reference. For faster API documentation, try River's API documentation tools.

Chandler Supple

Co-Founder & CTO at River

Chandler spent years building machine learning systems before realizing the tools he wanted as a writer didn't exist. He founded River to close that gap. In his free time, Chandler loves to read American literature, including Steinbeck and Faulkner.

Ready to write better, faster?

Try River's AI-powered document editor for free.

Get Started Free →