Every HTTP response starts with a status code: a three-digit number that tells the client what happened. Browsers, search engines and API clients all rely on it.
The five groups
| Range | Meaning |
|---|---|
| 1xx | Information (rarely used directly) |
| 2xx | Success |
| 3xx | Redirection |
| 4xx | The client made a mistake |
| 5xx | The server failed |
The codes you will use
| Code | Name | Use it when |
|---|---|---|
200 | OK | The request worked (the default) |
201 | Created | A resource was created (after POST) |
204 | No Content | Success with nothing to send back (after DELETE) |
301 | Moved Permanently | A page has a new permanent address |
302 / 303 | Found / See Other | A temporary redirect (after a form post) |
304 | Not Modified | The cached copy is still good |
400 | Bad Request | The request is malformed or invalid |
401 | Unauthorized | The user is not logged in (authentication needed) |
403 | Forbidden | Logged in, but not allowed |
404 | Not Found | The resource does not exist |
405 | Method Not Allowed | Wrong HTTP method for this URL |
409 | Conflict | The request clashes with the current state (duplicate) |
415 | Unsupported Media Type | Wrong Content-Type |
422 | Unprocessable Content | Valid syntax, but the data fails validation |
429 | Too Many Requests | Rate limit reached |
500 | Internal Server Error | Something broke on the server |
503 | Service Unavailable | Maintenance or overload |
Sending a status code in PHP
<?php
http_response_code(404);
echo "Page not found";
Call it before output, and remember that the code is part of the headers.
<?php
http_response_code(201);
header("Location: /products/42"); // where the new resource is
For redirects, header("Location: ...") sets 302 automatically. To choose, pass the code as the third argument: header("Location: /new", true, 301).
Why correct codes matter
- Search engines. A missing page that returns
200(a “soft 404”) confuses search engines. A moved page should return301. - Clients. A JavaScript
fetch()treats404and500differently from200, and can react. - Monitoring. Tools count
5xxresponses to find outages.
Choose between 401, 403 and 404
<?php
function statusFor(bool $loggedIn, bool $allowed, bool $exists): int
{
if (!$loggedIn) {
return 401;
}
if (!$exists) {
return 404;
}
return $allowed ? 200 : 403;
}
echo statusFor(false, false, true) . " ";
echo statusFor(true, false, true) . " ";
echo statusFor(true, true, false) . " ";
echo statusFor(true, true, true);
401 403 404 200
Sometimes you return 404 instead of 403 on purpose, so that people cannot find out which private resources exist.
400 vs 422
400: the request itself is broken (invalid JSON, missing required header).422: the JSON is fine, but a value is not acceptable (an invalid email). Many APIs simply use400for both. Be consistent.
Names for codes
<?php
$names = [200 => "OK", 201 => "Created", 404 => "Not Found", 500 => "Internal Server Error"];
foreach ([201, 404] as $code) {
echo "$code {$names[$code]}\n";
}
201 Created
404 Not Found
Read a status code
When you call another API, check the status before you trust the body. API Error Handling shows how.
A rule of thumb
2xx means “it worked”, 4xx means “you sent something wrong, do not retry unchanged”, 5xx means “we failed, you can retry later”.