HTTP Status Codes Explained

Complete reference — every status code explained with examples and REST API best practices

HTTP & APIsJune 26, 202622 min readBy Keyur Patel

Every single HTTP response includes a status code — a 3-digit number that tells the client exactly what happened with their request. Did it succeed? Was the resource moved? Was there an authentication problem? Did the server crash? Status codes answer all of these questions instantly, without the client needing to parse the response body.

This guide covers every important HTTP status code with real-world explanations, REST API best practices, common mistakes, and a decision guide for choosing the right code. Whether you're building APIs, debugging network issues, or preparing for interviews — this is your complete reference.

What Are HTTP Status Codes?

An HTTP status code is a standardized number that the server includes in the first line of every response. It immediately tells the client the outcome of the request before they even look at the body. The status line looks like this:

HTTP/1.1 200 OK
         ^^^  ^^
         |    └── Reason phrase (human-readable, optional)
         └─────── Status code (machine-readable, always 3 digits)

The first digit defines the category. You can immediately tell the general outcome by looking at just the first digit: 2 = success, 3 = redirect, 4 = client error, 5 = server error.

Status Code Categories

RangeCategoryMeaningExamples
1xxInformationalRequest received, processing continues100 Continue, 101 Switching Protocols
2xxSuccessRequest was successful200 OK, 201 Created, 204 No Content
3xxRedirectionFurther action needed (different URL)301 Moved, 302 Found, 304 Not Modified
4xxClient ErrorProblem with the request from client400 Bad Request, 401, 403, 404, 422
5xxServer ErrorServer failed to fulfill valid request500 Internal Error, 502, 503, 504

2xx Success Codes

These codes indicate the request was received, understood, and processed successfully.

200 OK

The request succeeded. The most common status code — used for successful GET, PUT, and PATCH requests. The response body contains the requested data or confirmation of the action.

Use when: GET returns data, PUT/PATCH updates succeed, any successful operation with a response body.

201 Created

A new resource was successfully created. Should always be returned for successful POST requests that create something. The response should include the created resource (or at minimum its ID and location).

Use when: POST creates a new user, order, post, file, or any new entity. Include a Location header pointing to the new resource.

204 No Content

The request succeeded but there is nothing to return. The response has no body. Used for DELETE operations and updates where the client doesn't need confirmation data.

Use when: DELETE removes a resource successfully, PUT updates but client doesn't need the updated object back.

206 Partial Content

Only part of the resource is returned, based on the Range header in the request. Used for video streaming, file downloads that can be resumed, and pagination of binary content.

Use when: Client requests a byte range (video seeking, resumable downloads).

3xx Redirection Codes

These codes tell the client to look elsewhere — the resource has moved or can be found at a different URL.

301 Moved Permanently

The resource has permanently moved to a new URL. Browsers and search engines update their records. All future requests should use the new URL. SEO value transfers to the new URL.

Use when: Domain change, URL restructuring, www to non-www redirect. Search engines transfer ranking to the new URL.

302 Found (Temporary Redirect)

The resource is temporarily at a different URL. The original URL is still the canonical version. Search engines keep indexing the original URL.

Use when: Temporary maintenance page, A/B testing, geolocation-based redirect. The original URL should still be bookmarked.

304 Not Modified

The resource hasn't changed since the client's last request. The browser should use its cached version. No body is sent — saves bandwidth significantly. Works with ETag/If-None-Match and Last-Modified/If-Modified-Since headers.

Use when: Client sends conditional request (If-None-Match with ETag) and the content is unchanged.

307 Temporary Redirect (preserves method)

Like 302, but guarantees the HTTP method is preserved. A POST to the original URL will remain a POST to the new URL. 302 historically could change POST to GET in some browsers.

Use when: Temporary redirect of API endpoints where you need to preserve the HTTP method (POST stays POST).

4xx Client Error Codes

These indicate something is wrong with the request — the client needs to fix it before retrying.

400 Bad Request

The server cannot understand the request due to malformed syntax. The JSON is invalid, required parameters are missing, or the request structure is wrong. The client should not retry without modifications.

Use when: Invalid JSON body, missing required query parameters, malformed URL, wrong data types.

401 Unauthorized (Unauthenticated)

The request requires authentication but none was provided, or the credentials are invalid. Despite the name "Unauthorized," it actually means "unauthenticated" — the server doesn't know who you are.

Use when: No token provided, expired token, invalid credentials. Client should login or refresh their token.

403 Forbidden

The server knows who you are (authenticated) but you do not have permission to access this resource. Unlike 401, re-authenticating won't help — you simply don't have the required role or permission.

Use when: Authenticated user tries to access admin-only resource, user tries to edit another user's data, insufficient role/permission.

404 Not Found

The server cannot find the requested resource. The URL may be wrong, the resource may have been deleted, or it never existed. The most recognized error code on the internet.

Use when: GET /users/99999 where user doesn't exist, wrong URL path, deleted resource. Some APIs use 404 instead of 403 to hide the existence of resources (security through obscurity).

409 Conflict

The request conflicts with the current state of the server. Most commonly: trying to create a resource that already exists (duplicate email, username taken) or concurrent edit conflicts.

Use when: Duplicate unique field (email already registered), optimistic locking conflict, resource state prevents the action.

422 Unprocessable Content

The server understands the content type and syntax (valid JSON), but cannot process the data due to semantic/validation errors. The most appropriate code for form validation failures in APIs.

Use when: Email format invalid, password too short, age is negative, required business rules not met. Include error details in the response body.

429 Too Many Requests

The client has sent too many requests in a given time period (rate limited). The server should include a Retry-After header indicating when the client can try again.

Use when: Rate limit exceeded, API quota reached. Include Retry-After header. Client should implement exponential backoff.

5xx Server Error Codes

These indicate the server failed to fulfill a valid request. The problem is on the server side — the client did nothing wrong.

500 Internal Server Error

A generic "something crashed" error. The server encountered an unexpected condition that prevented it from fulfilling the request. Usually caused by unhandled exceptions, null pointer errors, or database connection failures.

When you see it: Bug in server code, uncaught exception, database down. Never expose error details to the client in production — log them server-side.

502 Bad Gateway

The server (acting as a gateway/proxy) received an invalid response from the upstream server. Your Nginx/load balancer is running, but the application server behind it is down or returning garbage.

When you see it: Backend app crashed but reverse proxy (Nginx) is still running, upstream timeout, Docker container restarting.

503 Service Unavailable

The server is temporarily unable to handle requests. Usually due to maintenance, overload, or the server starting up. Should include a Retry-After header indicating when to try again.

When you see it: Planned maintenance, server overloaded, auto-scaling hasn't caught up with traffic spike, health check failing.

504 Gateway Timeout

The server (acting as a gateway) did not receive a timely response from the upstream server. The backend is taking too long — perhaps a slow database query, infinite loop, or network issue between services.

When you see it: Slow database query exceeds proxy timeout, upstream service hanging, network partition between services.

Status Code Decision Guide for REST APIs

Use this as a quick reference when building API endpoints:

ScenarioStatus CodeExample
GET succeeds, returning data200 OKGET /users → list of users
POST creates a new resource201 CreatedPOST /users → new user created
DELETE succeeds, nothing to return204 No ContentDELETE /users/123 → user removed
PUT/PATCH update succeeds200 OKPUT /users/123 → updated user returned
Resource permanently moved301 MovedOld URL → new URL (SEO transfer)
Resource not changed (cached)304 Not ModifiedBrowser uses cached version
Invalid request body (bad JSON)400 Bad RequestMalformed JSON, wrong types
No authentication provided401 UnauthorizedMissing or expired token
Authenticated but no permission403 ForbiddenUser can't access admin route
Resource doesn't exist404 Not FoundGET /users/99999 (no such user)
Duplicate resource conflict409 ConflictEmail already registered
Validation fails (business rules)422 UnprocessableInvalid email format, password too short
Too many requests (rate limit)429 Too Many RequestsClient exceeded 100 req/min
Server bug or crash500 Internal ErrorUnhandled exception in code
Upstream server down502 Bad GatewayApp server crashed behind Nginx
Server temporarily unavailable503 Service UnavailableMaintenance mode, overloaded

Common Developer Mistakes

⚠️ Returning 200 for everything (even errors)

Some APIs return 200 with {error: 'Not found'} in the body. This breaks client error handling — fetch() won't throw, Axios won't catch it. Clients rely on status codes for error detection. Always use proper codes.

✅ Fix: Use 4xx for client errors, 5xx for server errors. Reserve 200 for actual success.

⚠️ Using 500 for validation errors

Validation failures are not server crashes — they are client errors (the client sent bad data). Returning 500 makes it impossible to distinguish between 'your input is wrong' and 'our server is broken'.

✅ Fix: Use 400 for malformed requests, 422 for validation failures. Reserve 500 for unexpected server errors.

⚠️ Returning 404 when you mean 403

If a user requests a resource they can't access, returning 404 ('not found') instead of 403 ('forbidden') confuses the client — they'll think the URL is wrong instead of realizing they need different permissions.

✅ Fix: Use 403 when the user is authenticated but lacks permission. Use 404 only when the resource genuinely doesn't exist. (Exception: use 404 to hide resource existence for security-sensitive APIs.)

⚠️ Using 302 instead of 301 for permanent moves

After a domain change or URL restructuring, using 302 (temporary) instead of 301 (permanent) means search engines don't transfer SEO ranking to the new URL. Your old URLs keep ranking while new ones get no credit.

✅ Fix: Use 301 for permanent URL changes. Use 302 only for genuinely temporary redirects (maintenance, A/B tests).

⚠️ Not returning 201 for POST creation

Returning 200 after creating a new resource loses valuable semantic information. Clients can't reliably distinguish 'updated' from 'created' if both return 200.

✅ Fix: Always return 201 Created for successful POST requests that create a new resource. Include a Location header with the new resource's URL.

⚠️ Returning 200 with empty body instead of 204

A 200 with an empty body is ambiguous — did the operation succeed with no data, or did something go wrong? 204 explicitly says 'success, and I intentionally have nothing to send you'.

✅ Fix: Use 204 No Content for DELETE operations and updates where no response body is needed.

Interview Questions

Q: What is the difference between 401 and 403?

A: 401 = not authenticated (provide credentials). 403 = authenticated but not authorized (you don't have permission). 401 means 'who are you?', 403 means 'I know who you are, but you can't do this'.

Q: What is the difference between 301 and 302?

A: 301 = permanent redirect (SEO transfers, browsers cache it forever). 302 = temporary redirect (SEO stays with original, browser re-checks next time).

Q: When should you use 201 instead of 200?

A: Use 201 when a POST request successfully creates a new resource. 200 is for general success (GET, PUT). 201 specifically signals 'a new entity now exists that didn't before'.

Q: What is 422 and when do you use it?

A: 422 Unprocessable Content — the request is syntactically valid (good JSON) but semantically invalid (fails business validation like invalid email format). Use it for form/input validation errors.

Q: 500 vs 502 vs 503 — what's the difference?

A: 500 = your application code crashed. 502 = your reverse proxy/gateway is fine but the app behind it is down. 503 = server is temporarily unavailable (maintenance/overload). 504 = gateway timeout (upstream too slow).

Q: What does 304 Not Modified mean?

A: The resource hasn't changed. The browser sent a conditional request (with If-None-Match/ETag), and the server confirmed the cached version is still current. No body is returned — browser uses its cache.

Q: What is 429 and how should clients handle it?

A: 429 = rate limited (too many requests). Clients should read the Retry-After header, wait the specified time, then retry. Implement exponential backoff for repeated 429s.

Q: Why should APIs never return 200 for errors?

A: HTTP clients use status codes for error detection. fetch() only rejects on network errors, but response.ok checks the status. Axios throws on 4xx/5xx. If you return 200 with an error body, client error handling breaks.

Complete HTTP Status Code Cheat Sheet

Quick reference for all important codes by category:

CodeNameWhen to use
100ContinueLarge request body — server says 'go ahead'
101Switching ProtocolsWebSocket upgrade
200OKSuccessful GET, PUT, PATCH
201CreatedSuccessful POST that creates resource
202AcceptedRequest queued for async processing
204No ContentSuccessful DELETE, nothing to return
206Partial ContentRange request (video streaming)
301Moved PermanentlyPermanent URL change (SEO transfers)
302FoundTemporary redirect
304Not ModifiedCached version is still valid
307Temporary RedirectLike 302 but preserves HTTP method
308Permanent RedirectLike 301 but preserves HTTP method
400Bad RequestMalformed request syntax
401UnauthorizedNot authenticated
403ForbiddenAuthenticated but no permission
404Not FoundResource doesn't exist
405Method Not AllowedWrong HTTP method for endpoint
409ConflictDuplicate resource, state conflict
410GoneResource permanently deleted (vs 404 which might return)
413Payload Too LargeRequest body exceeds server limit
415Unsupported Media TypeWrong Content-Type
418I'm a TeapotEaster egg (RFC 2324, for fun)
422Unprocessable ContentValidation failed
429Too Many RequestsRate limit exceeded
451Unavailable for Legal ReasonsCensored/blocked content
500Internal Server ErrorServer bug/crash
501Not ImplementedFeature not supported yet
502Bad GatewayUpstream server returned bad response
503Service UnavailableServer temporarily down
504Gateway TimeoutUpstream server too slow

Frequently Asked Questions

What is an HTTP status code?
An HTTP status code is a 3-digit number returned by the server with every HTTP response. It tells the client whether the request succeeded (2xx), needs redirection (3xx), had a client error (4xx), or encountered a server error (5xx).
What is the most common HTTP status code?
200 OK is the most common — it means the request was successful and the server is returning the requested data. You see it on virtually every successful page load, API call, and resource request.
What does 404 Not Found mean?
404 means the server cannot find the requested resource at the given URL. Either the URL is wrong, the resource was deleted, or it never existed. It's the most well-known error code among both developers and regular internet users.
What is the difference between 401 and 403?
401 Unauthorized means 'you are not authenticated — please log in or provide credentials.' 403 Forbidden means 'you are authenticated but do not have permission to access this resource.' 401 = who are you? 403 = I know who you are, but you can't access this.
What does 500 Internal Server Error mean?
500 means something went wrong on the server that prevented it from fulfilling the request. It's a generic 'something crashed' error — usually caused by unhandled exceptions, bugs in server code, database failures, or misconfiguration.
What is 301 vs 302 redirect?
301 is a permanent redirect — search engines transfer SEO value to the new URL. 302 is a temporary redirect — the original URL is still considered the canonical version. Use 301 for domain moves and URL changes. Use 302 for temporary situations like maintenance or A/B testing.
What is 429 Too Many Requests?
429 means the client has sent too many requests in a given time period (rate limited). The server typically includes a Retry-After header indicating when the client can try again. APIs use this to protect against abuse and ensure fair usage.
Why is 304 Not Modified important?
304 means the resource hasn't changed since the last request — the browser can use its cached version. This saves bandwidth because the server doesn't need to send the response body again. It's part of HTTP caching using ETag and If-None-Match headers.
When should a REST API return 201 vs 200?
Return 201 Created when a new resource is created (POST endpoint creates a user, order, etc.). Return 200 OK for successful requests that don't create new resources (GET, PUT updates, successful operations). 201 specifically signals 'a new thing now exists'.
What is 422 Unprocessable Content?
422 means the server understands the request format (valid JSON) but cannot process the content due to validation errors — invalid email format, password too short, required fields missing. Use 422 for business logic validation failures.

Related Articles & Tools

Conclusion

HTTP status codes are the language of the web — they instantly communicate the outcome of every request without requiring the client to parse response bodies. Using the correct status code is not optional — it is how clients, browsers, proxies, and monitoring tools understand what happened.

The essential codes every developer must know: 200 (success), 201 (created), 204 (no content), 301 (permanent redirect), 304 (not modified), 400 (bad request), 401 (unauthenticated), 403 (forbidden), 404 (not found), 422 (validation failed), 429 (rate limited), 500 (server error), and 503 (service unavailable). Master these 13 codes and you can handle 99% of real-world situations.

Build APIs that use proper status codes from day one — your frontend developers, mobile developers, and future self will thank you when debugging at 2 AM.