This shape covers everything
Including the responses that usually escape an API’s error format:404for a path that is not mounted405for a method the route does not accept401from the authentication layer, before any handler runs429from the rate limiter, before authentication runs500when something failed on our side
/api/v1 that answers a refusal in HTML, in plain text, or in a
different JSON shape. You never need a fallback parser for a body you could not decode.
Statuses
Every response carries a correlation id
401 and 429 that
are answered before any handler runs. It is the same value that appears in our logs for
that request.
Log the
x-request-id alongside your own errors. When you report a problem, quoting
it is the difference between support finding the exact request in seconds and asking
you a series of narrowing questions.Handling errors
Client mistakes are never 5xx
A malformed body, a bad cursor, an unknown field or an invalid value answers4xx. It
does not answer 500.
This matters for your retry logic. A 5xx from this API means something failed on our
side and retrying is reasonable. If client faults could also surface as 500, you could
not distinguish “retry this” from “this will fail identically forever”, and a retry loop
on a permanently malformed request is just load with no chance of success.
Unknown codes
New error codes can be added as the API grows. Handle the codes you care about explicitly and fall through to a default that logscode, message and x-request-id.
Do not treat an unrecognised code as success.