The HTTP status codes that actually matter

The status codes that actually come up when you are debugging an API, what each one is really telling you, and which are routinely misused.

Updated

Status codes are the fastest diagnostic an API gives you, and most of the confusion around them comes from a handful that are routinely used to mean something they do not.

The ones you will actually see

200 OK — the request succeeded. Note what this does not promise: nothing about the body being correct or complete.

201 Created — a resource now exists. Should come with a Location header.

204 No Content — success, and there is deliberately no body. Common after a DELETE. If your client tries to parse JSON from a 204 it will throw, which is a surprisingly common bug.

301 vs 302 — permanent versus temporary. This one has consequences beyond your app: a 301 is cached aggressively by browsers and treated by search engines as a permanent move. Sending a 301 you later want to undo is genuinely painful.

400 Bad Request — malformed input. Often really means "I could not parse your JSON."

401 Unauthorized — badly named; it means unauthenticated. Who are you?

403 Forbidden — authenticated, but not permitted. Retrying with a new token will not help.

404 Not Found — no such resource. Also used, legitimately, to hide the existence of resources from users who are not allowed to know about them.

409 Conflict — the request collided with current state. Duplicate unique key, or an edit against a stale version.

422 Unprocessable Entity — the JSON parsed fine but the values are invalid. The useful distinction from 400 is syntax versus semantics.

429 Too Many Requests — rate limited. Should include Retry-After; honour it.

500 Internal Server Error — the server broke. Your request may be perfectly valid.

502 / 503 / 504 — an upstream is down, overloaded, or slow. These are the codes worth retrying with backoff; a 400 never is.

The rule that saves the most time

The leading digit tells you where to look before you read anything else. 4xx means change your request. 5xx means change the server. Developers lose hours debugging their own payload against what turns out to be a 502.

Where status codes mislead you

Plenty of APIs return 200 OK with {"error": "not found"} in the body. Some return 200 with an empty body where the resource should be. Both pass any test that only asserts on the status line.

That is the case for checking the response body too, rather than trusting the code — see validating API responses against a schema, or start with how to test a REST API.

Frequently asked questions

Should a REST API return 200 or 201 after creating a resource?

201 Created, with a Location header pointing at the new resource. Returning 200 is not fatal, but 201 tells the client a resource now exists at a URL it can follow, which 200 does not.

What is the difference between 401 and 403?

401 Unauthorized means the server does not know who you are — credentials are missing, malformed or expired. 403 Forbidden means it knows exactly who you are and you are not allowed. If retrying with a fresh token could help, it is a 401.