# Choosing Status Codes — API Design and Versioning

Source: https://www.geekswithgeeks.com/en/api-design/rr-status-codes

> Use the standard classes and a handful of precise codes consistently.

## The class tells who is at fault

Status codes group by first digit: **2xx** success, **3xx** redirect or "not modified", **4xx** the **client** made a mistake, **5xx** the **server** failed. Use precise codes: `200 OK`, `201 Created` (with a `Location` header) after creating, `202 Accepted` when work continues in the background, `204 No Content` for success with no body, `400 Bad Request` for malformed input, `401 Unauthorized` (not authenticated), `403 Forbidden` (authenticated but not allowed), `404 Not Found`, `409 Conflict` (state clash, such as a duplicate), `412 Precondition Failed` (failed conditional request), `422 Unprocessable Content` (well-formed but invalid data), `429 Too Many Requests` (with `Retry-After`) and `503 Service Unavailable`. Never return `200` with an error hidden inside the body: clients, caches and monitors rely on the code.

## Say what happened, clearly

Status codes, error bodies and pagination are where an API either feels trustworthy or confusing.

![Four tools: status, error, page, filter.](assets/figures/api-design/section-2-map.svg) — Figure 2.1 — Status, error, page and filter.

## Event to status code, run

I ran this plain-Python example. A tiny lookup that you could use as a team reference: created 201, accepted-for-async 202, deleted 204, validation 422, conflict 409, rate limited 429.

```python
import hmac, hashlib, json, time, bisect

def status_for(event):
    return {"created": 201, "accepted_async": 202, "deleted": 204, "validation": 422, "conflict": 409, "not_found": 404, "unauth": 401, "forbidden": 403, "rate": 429}[event]
print([status_for(e) for e in ("created", "accepted_async", "deleted", "validation", "conflict", "rate")])

```

Output:

```
[201, 202, 204, 422, 409, 429]
```

## 401 vs 403

401 means "I do not know who you are" (missing or bad credentials); 403 means "I know who you are and you may not do this". Mixing them confuses clients and hides bugs.

**Quiz:** A user is logged in but lacks permission for an action. Which code fits?

- [ ] 401 Unauthorized
- [x] 403 Forbidden
- [ ] 200 OK
- [ ] 500 Internal Server Error

*Answer:* 403 Forbidden. The identity is known but not allowed, which is 403.
