401 is not authorisation
The specification names 401 Unauthorized and means unauthenticated: we do not know who you are, so send credentials - which is why it must carry a WWW-Authenticate header. 403 Forbidden means the opposite situation: we know exactly who you are and you still may not do this, so re-authenticating will not help and sending the user to a login page is the wrong response.
Getting this backwards produces a specific, common bug: a client that redirects to login on a 403 puts a legitimately-authenticated user into an endless loop, because signing in again changes nothing. There is one deliberate exception worth knowing - where confirming that a resource exists would itself leak information, returning 404 to an unauthorised caller is the right answer rather than 403.
400 or 422
400 Bad Request means the request could not be read: unparseable JSON, a missing required field, a value of the wrong type. 422 Unprocessable Content means it was read perfectly and is still wrong - a well-formed email address that is already taken, an end date before its start date, a quantity larger than the stock.
The distinction is worth maintaining because it tells the client whether to fix its serialisation or to show the user a field error, and those are entirely different code paths.
The three redirects that are really six
302 is historically ambiguous: the specification says preserve the request method, every browser changes POST to GET. That ambiguity is why 303 and 307 exist - 303 See Other explicitly means redirect with GET, and 307 explicitly means keep the method. 308 is the permanent, method-preserving counterpart to 301.
For new work, prefer the explicit pair: 303 after a successful form POST so a refresh does not resubmit, and 307 or 308 whenever a POST must stay a POST. 301 remains the one that reliably passes search authority, and browsers cache it hard enough that a mistaken 301 is close to irreversible for returning visitors.
- Search by number - typing 40 lists the whole 40x range
- Or by symptom, including phrases like rate limit and forbidden vs unauthorized
- Codes cacheable by default under RFC 9111 are marked
- Codes registered with IANA but absent from a core RFC are labelled as such
What it will not do
It will not tell you which code your framework is actually returning, and that gap matters: a proxy, a CDN or an error handler in the middle can and does rewrite a status on the way out. Check the response over the wire rather than the code your handler thinks it set.
It is also not exhaustive. Roughly sixty registered codes are covered - the ones you will actually meet - and the WebDAV and unofficial extensions are included only where they are widely deployed or widely looked up. Inventing a status code for your own API is a non-goal for the same reason: clients and proxies only understand the registered ones.