HTTP status codes are the primary vocabulary an API uses to tell clients what happened. The 4xx class signals client errors: the caller did something wrong and must adjust. Within that class, 401 Unauthorized means the request lacks valid credentials and the client should authenticate and retry, while 403 Forbidden means the caller is authenticated but is not permitted to access the resource. The distinction is often summarized as 401 asking "who are you?" and 403 saying "I know who you are, but you cannot have it." 404 Not Found indicates that the resource is not present at the URI and may exist elsewhere or later; 410 Gone goes further, declaring that the resource existed but has been permanently removed.
Two related codes merit careful thought. 400 Bad Request usually signals malformed syntax—invalid JSON, a bad header, or an unreadable payload—whereas 422 Unprocessable Entity indicates that the body is syntactically valid but semantically rejected, typically by business-rule validation. Choosing between them matters: tests should confirm that an API returns 400 for broken payloads and 422 for valid-but-rejected ones, because clients often branch on these codes. 429 Too Many Requests says the client has exceeded a rate limit and should slow down, usually honoring a Retry-After header. 503 Service Unavailable communicates that the server is temporarily unable to handle the request due to overload or maintenance, and is also frequently paired with Retry-After. The 5xx class as a whole signals backend failures the client did not cause, while rate-limit testing in general verifies that the system protects itself from abuse and noisy clients and communicates failures clearly.
Success codes carry their own semantics. 201 Created indicates that a new resource was created and the response should include a Location header pointing to a canonical URI for that resource. 204 No Content signals successful processing with an intentionally empty body—clients must not expect a payload. Two codes tied to caching and concurrency round out the set: 304 Not Modified tells the client to reuse its cached copy, triggered by If-None-Match or If-Modified-Since, and 412 Precondition Failed indicates that a precondition header such as If-Match or If-Unmodified-Since evaluated to false, so the server declines the request. Tests should explicitly assert status codes, because a payload can look reasonable while an incorrect code silently breaks integrations.