HTTP Status Codes
Every HTTP response carries a three-digit status code, and it's usually the very first thing a Postman test checks. The code is a promise about what happened on the server — read it correctly and you already know a lot about the response before you even look at the body.
The Five Status Code Families
| Range | Family | Meaning |
|---|---|---|
| 1xx | Informational | Request received, still processing. Rare to see directly — Postman handles these automatically. |
| 2xx | Success | The request was received, understood, and accepted. This is the family you want on a happy-path test. |
| 3xx | Redirection | The resource has moved; the client should follow a new URL. Common on websites, less common on JSON APIs. |
| 4xx | Client Error | Something about the request itself was wrong — bad data, missing auth, a resource that doesn't exist. The client should fix the request, not retry blindly. |
| 5xx | Server Error | The server failed while trying to handle a valid request. This is never the client's fault, and it's exactly the kind of bug API testing is great at catching. |
The Codes You'll Check Constantly
In practice, testers spend most of their time with about a dozen specific codes. Here's what each one promises, and a concrete RecipeBox scenario that would trigger it:
| Code | Meaning | RecipeBox Scenario |
|---|---|---|
| 200 | OK | GET /recipes/42 for a recipe that exists — the standard successful read or update response. |
| 201 | Created | POST /recipes succeeds; the response includes the new recipe with its server-assigned id. |
| 204 | No Content | DELETE /recipes/42 succeeds; there's nothing to return, so the body is empty. |
| 400 | Bad Request | POST /recipes with a body that isn't valid JSON at all (a syntax error in the payload). |
| 401 | Unauthorized | POST /recipes with no auth token, or an expired one — the server doesn't know who you are. |
| 403 | Forbidden | A logged-in user tries DELETE /recipes/42 on a recipe they don't own — the server knows who they are, but denies the action. |
| 404 | Not Found | GET /recipes/99999 where no recipe with id 99999 exists. |
| 409 | Conflict | POST /recipes with a title that must be unique, and a recipe with that exact title already exists. |
| 422 | Unprocessable Entity | POST /recipes with valid JSON syntax, but "prepMinutes": -5 — a negative prep time fails business-rule validation. |
| 500 | Internal Server Error | The server throws an unhandled exception while processing GET /recipes/42 — for example, a bug when a recipe has a null category the server didn't expect. |
| 503 | Service Unavailable | The RecipeBox database is temporarily down for maintenance, so every request fails, but the server itself is still reachable enough to say so. |
400 vs. 422 — A Distinction Worth Testing Precisely
These two get confused constantly, and a good tester should be precise about the difference:
- 400 means the request is malformed at the syntax level — the server literally can't parse what you sent (broken JSON, wrong content type).
- 422 means the request was parsed fine, but the data inside
it violates a business rule — it's syntactically valid JSON, but semantically invalid (a
negative
prepMinutes, an emptyingredientsarray, acategorythat isn't one of the allowed values).
Some APIs collapse both cases into a plain 400 — that's a legitimate design choice, but if the API's own documentation promises a 422 for validation failures and returns 400 instead, that's a contract mismatch worth logging as a bug.
401 vs. 403 — Another Pair to Keep Straight
401 Unauthorized really means "unauthenticated" — the server doesn't know who's asking (no token, or a bad/expired one). 403 Forbidden means the server knows exactly who's asking, but that identity isn't allowed to do this. Testing both correctly means checking two separate cases: a request with no credentials at all, and a request with valid credentials that simply lack permission.