HTTP Status Codes and REST API Cheat Sheet (401 vs 403 Finally Explained)
β‘ Quick Answer
An HTTP status codes cheat sheet for REST APIs β every code class, 401 vs 403, 400 vs 422, redirect codes, method idempotency, URL naming, pagination and CORS.
Get more content like this on Telegram!
Daily AI tips, notes & resources β free
Advertisement
HTTP Status Codes and REST API Cheat Sheet
An HTTP status code is a three-digit answer to one question: what happened to your request? The first digit is the category, and the other two are the detail.
Most APIs use about twelve of them correctly. This sheet covers all five classes, the four distinctions that get argued about in code review, and the REST conventions that go with them.
Updated for 2026. Covers HTTP/1.1 through HTTP/3 semantics as defined in RFC 9110.
The Five Classes
| Range | Class | Means |
|---|---|---|
1xx | Informational | Request received, still processing |
2xx | Success | It worked |
3xx | Redirection | Look somewhere else |
4xx | Client error | You sent something wrong |
5xx | Server error | We broke |
The 4xx / 5xx split is the one that matters operationally. 4xx is the client's fault and should not page anyone. 5xx is yours and should. An API that returns 500 for a validation failure will train your team to ignore its own alerts.
2xx β Success
| Code | Name | Use for |
|---|---|---|
200 | OK | Successful GET, PUT, PATCH, or POST that returns data |
201 | Created | POST that created a resource β include a Location header |
202 | Accepted | Queued for async processing, not done yet |
204 | No Content | Success with an intentionally empty body β typical DELETE |
206 | Partial Content | Range request, video seeking, resumable download |
What people get wrong: returning 200 for every successful create. 201 plus a Location: /api/users/42 header tells the client where the new thing lives without a second round trip.
204 must have a genuinely empty body. Sending {"success": true} with a 204 is a protocol violation, and some clients will error on it.
3xx β Redirection
| Code | Name | Permanent? | Method preserved? |
|---|---|---|---|
301 | Moved Permanently | Yes | Not guaranteed |
302 | Found | No | Not guaranteed |
303 | See Other | No | Forced to GET |
304 | Not Modified | β | Cache is still valid |
307 | Temporary Redirect | No | Yes |
308 | Permanent Redirect | Yes | Yes |
301 and 302 predate the method-preservation rules, and browsers historically converted a redirected POST into a GET. 307 and 308 exist precisely to remove that ambiguity β they guarantee the method and body survive.
Practical rules:
- Moving a public page:
301. Search engines transfer ranking signals. - Moving an API endpoint:
308. ThePOSTbody must not be dropped. - Post/Redirect/Get after a form submission:
303. - Temporary maintenance page:
302or307β never301, which browsers cache aggressively and hard.
304 Not Modified is not really a redirect. It answers a conditional request carrying If-None-Match or If-Modified-Since, and it saves bandwidth by sending headers only.
4xx β Client Errors
| Code | Name | Meaning |
|---|---|---|
400 | Bad Request | Malformed β the server could not parse it |
401 | Unauthorized | Not authenticated β who are you? |
403 | Forbidden | Authenticated but not permitted |
404 | Not Found | No such resource |
405 | Method Not Allowed | Wrong verb for this URL |
409 | Conflict | State clash β duplicate, or a version mismatch |
410 | Gone | Existed, deliberately removed, will not return |
413 | Content Too Large | Body exceeds the limit |
415 | Unsupported Media Type | Wrong Content-Type |
422 | Unprocessable Content | Valid syntax, failed business validation |
429 | Too Many Requests | Rate limited β send Retry-After |
401 vs 403
This is the distinction interviewers ask about, and it is genuinely useful.
401 means the server does not know who you are. Missing token, expired token, invalid signature. The name is a historical mistake β it is an authentication failure. The spec requires a WWW-Authenticate header on the response.
403 means the server knows exactly who you are and is refusing anyway. You are logged in; your role does not include this action.
401 β "Who are you?" β client should log in / refresh the token
403 β "I know. Still no." β retrying with the same token never helpsThat difference drives client behaviour. On 401 your frontend should attempt a token refresh and retry once. On 403 it should show a permission message β a retry loop on 403 is an infinite loop.
Security note: some APIs deliberately return 404 instead of 403 for resources the user may not even know exist, so that response codes do not leak the existence of records. That is a legitimate choice, but be consistent about it.
400 vs 422
| Situation | Code |
|---|---|
| Broken JSON syntax | 400 |
| Missing required field | 400 |
Wrong data type ("abc" for an integer) | 400 |
| Email is valid but already registered | 422 |
| End date is before start date | 422 |
| Quantity exceeds available stock | 422 |
The line is parser failure versus validator failure. 400 means the server could not understand the request. 422 means it understood perfectly and disagrees with the content.
Using 400 for both is defensible and common. Using 422 for malformed JSON is not.
409 vs 422
409 Conflict is about state, not content: an optimistic-locking version mismatch, or a resource that already exists at that identifier. 422 is about the payload's own semantics.
5xx β Server Errors
| Code | Name | Meaning |
|---|---|---|
500 | Internal Server Error | Unhandled exception β your bug |
501 | Not Implemented | The server does not support this method at all |
502 | Bad Gateway | Upstream returned garbage |
503 | Service Unavailable | Down or overloaded β send Retry-After |
504 | Gateway Timeout | Upstream did not answer in time |
502, 503 and 504 almost always come from a proxy or load balancer rather than your application. In a Kubernetes or NGINX setup, a 502 usually means the pod crashed or the port mapping is wrong; a 504 means it is alive but slow.
What people get wrong: returning 500 with a stack trace in the body. That leaks file paths, library versions, and sometimes credentials. Log the detail, return a trace ID.
Methods: Safety and Idempotency
| Method | Safe | Idempotent | Body | Typical use |
|---|---|---|---|---|
GET | Yes | Yes | No | Read a resource |
HEAD | Yes | Yes | No | Headers only, no body |
OPTIONS | Yes | Yes | No | Capability / CORS preflight |
POST | No | No | Yes | Create, or non-idempotent action |
PUT | No | Yes | Yes | Full replace |
PATCH | No | Usually no | Yes | Partial update |
DELETE | No | Yes | Optional | Remove |
Safe = does not change server state. Idempotent = doing it five times leaves the same state as doing it once.
PUT is idempotent because it replaces the whole resource with what you sent. DELETE is idempotent in effect β the second call returns 404, but the resource is equally gone.
POST being non-idempotent is the entire reason payment APIs need idempotency keys. The client sends a unique key with the request; if the network drops the response and the client retries, the server recognises the key and returns the original result instead of charging twice.
REST URL Conventions
GET /api/v1/articles list
POST /api/v1/articles create
GET /api/v1/articles/42 read one
PUT /api/v1/articles/42 replace
PATCH /api/v1/articles/42 partial update
DELETE /api/v1/articles/42 remove
GET /api/v1/articles/42/comments nested collectionThe rules that produce consistent APIs:
- Plural nouns for collections.
/articles, not/articleor/getArticles. - No verbs in the path. The HTTP method is the verb.
POST /articlesbeatsPOST /createArticle. - Lowercase, hyphenated.
/blog-posts, not/blogPostsor/blog_posts. - Nest at most one level.
/articles/42/commentsis fine;/users/1/articles/42/comments/7/repliesis a maintenance problem. Once you have the comment ID, fetch it at/comments/7. - Version in the path.
/api/v1/is uglier than a header and far easier to debug, cache, and route.
Genuine actions that are not CRUD β POST /orders/42/refund β are the accepted exception. Do not contort them into a resource for purity's sake.
Pagination and Filtering
GET /api/v1/articles?page=2&limit=20
GET /api/v1/articles?cursor=eyJpZCI6NDJ9&limit=20
GET /api/v1/articles?status=published&author=42
GET /api/v1/articles?sort=-published_at,title
GET /api/v1/articles?fields=id,title,excerpt| Style | Best for | Weakness |
|---|---|---|
Offset (page / limit) | Small datasets, jump-to-page UIs | Slow at high offsets; rows shift between pages |
Cursor (cursor / limit) | Feeds, large tables, infinite scroll | Cannot jump to page 50 |
Offset pagination degrades badly: OFFSET 100000 makes the database count and discard 100,000 rows on every request. Cursor pagination stays constant-time because it becomes an indexed WHERE id > ?. See the SQL cheat sheet for the query patterns behind both.
The - prefix on a sort field for descending order (sort=-published_at) is a widely used convention worth adopting rather than inventing your own.
Error Response Shape
{
"error": {
"code": "VALIDATION_FAILED",
"message": "The request could not be processed.",
"details": [
{ "field": "email", "issue": "already_registered" },
{ "field": "age", "issue": "must_be_at_least_18" }
],
"request_id": "req_01HZX9K2M4"
}
}code is stable and machine-readable β clients branch on it, so it must never change wording. message is human-readable and safe to display. details carries per-field problems so a form can highlight the right inputs in one round trip.
request_id is the highest-value field here. A user pastes one string into a support ticket and you find the exact log line.
RFC 9457 (Problem Details) standardises this with type, title, status, detail and instance under the application/problem+json content type. Adopting it means existing tooling parses your errors without custom code.
The non-negotiable rule: the shape is identical on every endpoint. An API with three different error formats forces every client to write three parsers.
CORS Basics
CORS errors are enforced by the browser, not the server. That is why the identical request succeeds from curl and fails in your page.
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 86400A request is simple β no preflight β if it uses GET, HEAD or POST with a basic content type and no custom headers. Anything else triggers a preflight OPTIONS request that your server must answer before the real request is sent.
Two rules people trip over:
- With
Allow-Credentials: true, theAllow-Originheader cannot be*. It must name an exact origin. Browsers reject the wildcard combination outright. Authorizationis a custom header. Adding a bearer token converts a simple request into a preflighted one, which is why an endpoint that worked publicly breaks the moment you add auth.
What Interviewers Ask
| Question | Short answer |
|---|---|
| 401 vs 403 | Not authenticated vs not permitted |
| Is PUT idempotent? | Yes. POST is not. |
| 301 vs 302 for SEO | 301 transfers ranking signals; 302 does not |
| Why does DELETE return 204? | Success, and there is nothing meaningful to return |
| What makes an API RESTful? | Resources as nouns, HTTP methods as verbs, stateless requests |
| When is 429 correct? | Rate limiting β pair it with a Retry-After header |
| Why not 200 with an error inside? | It defeats caching, retries, and every HTTP-aware proxy |
That last one is the deep question. Returning 200 {"error": "not found"} means every proxy, CDN, monitoring tool and HTTP client in the chain believes the request succeeded. The status code is infrastructure, not decoration. The system design cheat sheet covers where that matters at scale.
The Five Mistakes
1. 200 with an error in the body. Breaks caching, retries, and every piece of HTTP-aware tooling between you and the client.
2. 500 for validation failures. Client mistakes are 4xx. Mixing them destroys the signal value of your error-rate alerts.
3. 403 where 401 belongs. The client cannot tell whether to refresh the token or give up, so it does neither correctly.
4. Verbs in URLs. POST /api/deleteUser abandons every cache, proxy, and convention HTTP gives you for free.
5. Inconsistent error shapes. Three formats across one API means every consumer writes three parsers and handles two of them badly.
Print This Section
2xx 200 OK 201 Created (+Location) 202 Queued 204 No body
3xx 301 permanent (SEO) 308 permanent, method kept
302 temporary 307 temporary, method kept
303 POSTβGET 304 cache still valid
4xx 400 malformed / unparseable
401 NOT AUTHENTICATED β refresh token, retry
403 AUTHENTICATED, DENIED β do not retry
404 no such resource 405 wrong method
409 state conflict 422 valid syntax, failed validation
429 rate limited (+Retry-After)
5xx 500 your bug 502 bad upstream 503 down 504 upstream timeout
METHODS safe: GET HEAD OPTIONS
idempotent: GET HEAD OPTIONS PUT DELETE
NOT idempotent: POST, PATCH
URLS /api/v1/articles/42/comments
plural nouns Β· no verbs Β· lowercase-hyphens Β· nest once
CORS Allow-Credentials: true β Allow-Origin CANNOT be *
Authorization header β preflight OPTIONS requiredPick the status code that describes what happened, not the one that keeps your client code simple. Every proxy, cache, retry policy and dashboard between your server and your user is reading it.
π Next in this collection: Networking Cheat Sheet, or return to The Complete Developer Cheat Sheet Collection.
Advertisement
π¬ DiscussionPowered by GitHub Discussions
Frequently Asked Questions

AI & Software Engineering Editorial Team
The AiTechWorlds editorial team writes and reviews in-depth guides on artificial intelligence, machine learning, prompt engineering, programming, and developer tools. Every article is fact-checked against primary sources and kept up to date for working developers and CS students.
Not sure yet? Ask AI about this article
Get an instant, unbiased AI summary of βHTTP Status Codes and REST API Cheat Sheet (401 vs 403 Finally Explained)β.
Advertisement
Related Articles
Bash Scripting Cheat Sheet (The First Line Every Script Needs)
A practical Bash scripting cheat sheet β variables, conditionals, loops, functions, and the set -euo pipefail line that turns silent failure into loud failure.
15 Coding Interview Patterns That Solve Most Problems
The 15 coding interview patterns that cover most problems β the signal that identifies each one, a minimal code skeleton, and a two-minute recognition table.
CSS and Tailwind Cheat Sheet: Flexbox, Grid and Centering Solved
A practical CSS and Tailwind cheat sheet β Flexbox vs Grid decision rules, every centering method, responsive breakpoints, and the specificity traps.
Data Structures and Big-O Cheat Sheet for Coding Interviews
A practical big O cheat sheet β the complexity ladder with real examples, data structure operation tables, and how to state your complexity in an interview.