Branch on code, never on message
code is the contract. It comes from a fixed set, and its meaning never
changes.
message is written for a human reading a log. We may reword it at any time.
Anything that matches on the text of a message is a bug waiting for a copy
edit.
field appears on validation failures. It is a dotted path into the body you
sent.
The codes
Two that surprise people
404 for another workspace’s data
Asking for a ticket that belongs to someone else returnsnot_found, exactly
as if it did not exist. It never returns 403.
That is by design. A 403 would tell you the id is real, and being able to
probe for which ids exist in other workspaces is itself the leak.
402 rather than 403 when you run out
quota_exhausted is a billing state, not a permissions one. Your credentials
are fine, and you are allowed to do this; the account is not paid up.
The distinction matters for clients. Something treating 403 as “log in
again” would send an integration round an auth loop over an unpaid invoice.
Validation changes nothing
A400 means the request was rejected before anything acted on it. There is
no partial write to undo. Fix the field named in field, then send it again.