HTTP Status Codes: The Complete Developer Reference

Every time your browser loads a page or your app calls an API, the server sends back a three-digit number that tells you exactly what happened. These HTTP status codes are the universal language of the web — and understanding them is essential for building, consuming, and debugging APIs.

This guide covers every status code you'll encounter in practice, explains the subtle differences that trip developers up (like 401 vs 403), and shows you how to choose the right codes for your own APIs.

What Are HTTP Status Codes?

HTTP status codes are three-digit integers included in the response line of every HTTP response. When a client (browser, mobile app, CLI tool) sends a request to a server, the server always replies with a status code that indicates the outcome.

A typical HTTP response starts like this:

HTTP/1.1 200 OK
Content-Type: application/json
Date: Thu, 26 Mar 2026 12:00:00 GMT

{"message": "Hello, world"}

The first digit of the status code defines its class. There are five classes:

Knowing which class a code belongs to immediately tells you where the problem lies — the client side, the server side, or nowhere at all.

1xx Informational

The 1xx codes are interim responses. You rarely see them in application-level code, but they play an important role under the hood.

100 Continue

When a client needs to send a large request body (like a file upload), it can first send the headers with Expect: 100-continue. The server responds with 100 Continue to signal "go ahead and send the body" — or rejects the request early with a 4xx code, saving bandwidth.

# Client sends headers first
POST /upload HTTP/1.1
Content-Length: 52428800
Expect: 100-continue

# Server replies: "go ahead"
HTTP/1.1 100 Continue

# Client then sends the 50MB body

101 Switching Protocols

Used when the client asks to switch from HTTP to a different protocol. The most common case is upgrading to WebSockets:

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

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade

After this handshake, the connection is no longer HTTP — it's a full-duplex WebSocket channel.

103 Early Hints

A newer code that lets the server send preliminary headers (like Link headers for preloading CSS or fonts) while it's still preparing the final response. Browsers can start fetching those resources early, improving page load times.

2xx Success

The codes you want to see. A 2xx response means the request was successfully received, understood, and accepted.

200 OK

The most common status code. The request succeeded and the response body contains the requested resource. Use 200 for successful GET requests that return data, and for PUT/PATCH requests that return the updated resource.

201 Created

The request succeeded and a new resource was created as a result. This is the correct code for successful POST requests that create something. The response should include a Location header pointing to the new resource:

POST /api/users HTTP/1.1
Content-Type: application/json
{"name": "Alice", "email": "alice@example.com"}

HTTP/1.1 201 Created
Location: /api/users/42
Content-Type: application/json
{"id": 42, "name": "Alice", "email": "alice@example.com"}

204 No Content

The request succeeded but there's nothing to send back in the response body. This is the ideal response for successful DELETE requests and PUT/PATCH requests where the client doesn't need the updated resource echoed back.

206 Partial Content

The server is delivering only part of the resource because the client sent a Range header. This is how video streaming, resumable downloads, and PDF viewers work — the client requests specific byte ranges instead of the entire file.

GET /video.mp4 HTTP/1.1
Range: bytes=0-1048575

HTTP/1.1 206 Partial Content
Content-Range: bytes 0-1048575/52428800
Content-Length: 1048576

Tip: When building APIs, use 201 for creation, 204 for deletion, and 200 for everything else that succeeds. This precision makes your API self-documenting.

3xx Redirection

Redirection codes tell the client that the resource has moved and they need to look elsewhere. The differences between them are subtle but important.

301 Moved Permanently

The resource has permanently moved to a new URL. Search engines will transfer link equity to the new URL. Browsers and clients may change the HTTP method to GET when following the redirect — this is an important caveat.

302 Found (Temporary Redirect)

The resource is temporarily at a different URL. Like 301, clients may change the method to GET when following. Despite the specification, most browsers always change POST to GET on a 302 redirect.

307 Temporary Redirect

Like 302, but the client must not change the HTTP method. If the original request was a POST, the redirect must also be a POST. Use this when method preservation matters.

308 Permanent Redirect

Like 301, but the client must not change the HTTP method. This is the permanent equivalent of 307.

CodePermanent?Method Preserved?Use Case
301YesNo (may change to GET)Page moved, SEO redirect
302NoNo (may change to GET)Temporary redirect (legacy)
307NoYesTemporary redirect for APIs
308YesYesPermanent redirect for APIs

304 Not Modified

This isn't really a "redirect" — it's a caching optimisation. When the client sends conditional headers (If-None-Match or If-Modified-Since) and the resource hasn't changed, the server responds with 304 and an empty body. The client uses its cached copy, saving bandwidth and latency.

# First request — server includes ETag
GET /api/config HTTP/1.1
HTTP/1.1 200 OK
ETag: "abc123"

# Second request — client sends the ETag back
GET /api/config HTTP/1.1
If-None-Match: "abc123"

# Resource unchanged — use your cache
HTTP/1.1 304 Not Modified

Warning: Using 301 for API endpoint redirects can silently convert POST requests to GET, losing the request body entirely. Use 307 or 308 for API redirects where the method matters.

4xx Client Errors

The 4xx codes mean the client sent something wrong. These are the codes you'll encounter most often while debugging.

400 Bad Request

The server cannot process the request due to malformed syntax — invalid JSON, missing required fields, wrong data types. This is the catch-all for "your request doesn't make sense."

# Malformed JSON
POST /api/users HTTP/1.1
Content-Type: application/json
{"name": "Alice", email: broken}

HTTP/1.1 400 Bad Request
{"error": "Invalid JSON in request body"}

401 Unauthorized vs 403 Forbidden

This is one of the most commonly confused pairs in HTTP. Despite the name, 401 is about authentication, not authorisation:

Tip: Think of 401 as "please log in" and 403 as "you don't have access." A missing or expired JWT token is 401. A valid token for a user who isn't an admin trying to access the admin panel is 403.

404 Not Found

The server cannot find the requested resource. This could mean the URL is wrong, the resource was deleted, or the endpoint doesn't exist. Some APIs also return 404 instead of 403 to avoid leaking information about the existence of resources.

405 Method Not Allowed

The HTTP method is not supported for this URL. For example, sending a DELETE request to an endpoint that only accepts GET. The response should include an Allow header listing the valid methods:

DELETE /api/reports HTTP/1.1

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

409 Conflict

The request conflicts with the current state of the resource. Common examples include trying to create a user with an email that already exists, or updating a resource with a stale version (optimistic concurrency control).

422 Unprocessable Entity

The server understands the request syntax (it's valid JSON), but the content is semantically invalid. For example, the JSON is well-formed but an email field contains "not-an-email". Some APIs prefer 422 over 400 to distinguish between syntactically broken requests and semantically invalid ones.

429 Too Many Requests

The client has sent too many requests in a given time window (rate limiting). The response should include a Retry-After header telling the client when they can try again:

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

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

5xx Server Errors

The 5xx codes mean the server knows the request was valid but something went wrong on its end. These are the codes that wake you up at 3 a.m.

500 Internal Server Error

The generic "something broke" response. An unhandled exception, a null pointer, a failed database query — anything that the server didn't anticipate. If you're building an API, never expose raw stack traces in a 500 response. Log the details internally and return a safe error message to the client.

502 Bad Gateway

The server, acting as a gateway or proxy (like Nginx or a load balancer), received an invalid response from the upstream server. This usually means your application server crashed or returned something malformed. If you see 502 errors, check the upstream application, not the proxy itself.

503 Service Unavailable

The server is temporarily unable to handle the request, usually due to maintenance or overload. This is the right code for planned downtime. Include a Retry-After header so clients know when to come back:

HTTP/1.1 503 Service Unavailable
Retry-After: 3600
Content-Type: application/json

{"error": "Scheduled maintenance. Back in approximately 1 hour."}

504 Gateway Timeout

The gateway or proxy timed out waiting for a response from the upstream server. This often means a slow database query, an overloaded application server, or a network issue between services. Check your upstream server's response times and consider increasing timeout thresholds or optimising slow operations.

Warning: Never return a 200 OK with an error message in the body. This is a common anti-pattern that breaks error handling, caching, and monitoring. Use the correct 4xx or 5xx code so clients, proxies, and observability tools can do their jobs.

Status Codes in REST API Design

Choosing the right status code makes your API predictable and self-documenting. Here's a practical mapping for standard CRUD operations:

OperationMethodSuccess CodeCommon Error Codes
List resourcesGET200401, 403
Get single resourceGET200401, 403, 404
Create resourcePOST201400, 409, 422
Full updatePUT200400, 404, 409
Partial updatePATCH200400, 404, 422
Delete resourceDELETE204401, 403, 404

Common Mistakes

Debugging with Status Codes

When something goes wrong, status codes are your first diagnostic clue. Here's how to inspect them efficiently.

Using curl

The -I flag sends a HEAD request and shows only response headers, including the status code:

# Show just headers
curl -I https://api.example.com/users

# Show headers + body with verbose output
curl -v https://api.example.com/users

# Follow redirects and show each hop
curl -v -L https://example.com/old-page

# POST with response headers
curl -i -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -d '{"name": "Alice"}'

Browser DevTools

Open the Network tab in your browser's developer tools (Cmd+Option+I on macOS, Ctrl+Shift+I on Windows/Linux). Every request shows its status code, response headers, and timing breakdown. You can filter by status code to quickly find errors:

Reading Response Headers

Status codes tell you what happened; response headers often tell you why:

Tip: When debugging 502 or 504 errors, the problem is almost never the proxy. Check the upstream application server's logs and response times first.

Quick Reference Table

CodeNameMeaning
100ContinueSend the request body
101Switching ProtocolsUpgrading to WebSocket or HTTP/2
200OKRequest succeeded
201CreatedResource created successfully
204No ContentSuccess, no body returned
206Partial ContentRange request fulfilled
301Moved PermanentlyResource permanently moved (may change method)
302FoundTemporary redirect (may change method)
304Not ModifiedUse cached version
307Temporary RedirectTemporary redirect (preserves method)
308Permanent RedirectPermanent redirect (preserves method)
400Bad RequestMalformed request syntax
401UnauthorizedAuthentication required
403ForbiddenAuthenticated but not authorised
404Not FoundResource does not exist
405Method Not AllowedHTTP method not supported
409ConflictConflicts with current resource state
422Unprocessable EntityValid syntax but semantic errors
429Too Many RequestsRate limit exceeded
500Internal Server ErrorUnhandled server-side failure
502Bad GatewayInvalid upstream response
503Service UnavailableServer temporarily down
504Gateway TimeoutUpstream server timed out

All HTTP Codes at Your Fingertips

BoltKit's HTTPCodes tool gives you a searchable, categorised reference for every HTTP status code — right on your iPhone or iPad. Instant lookup, no Googling required.

Get BoltKit Free