The error envelope
Every error response from /api/v1/ is a JSON object with a single top-level error key whose value is
a human-readable string:
This is consistent across authentication failures, permission checks, throttling, not-found, and
method-not-allowed responses — you can always read body.error for a displayable message.
Status codes
Validation errors
Field-level validation errors (400 Bad Request) are the one intentional exception to the single-error
envelope. They follow Django REST Framework’s field-keyed convention — a map of field name to a list of
messages, so you can surface errors next to the right input:
Non-field errors appear under non_field_errors:
When parsing a 400, check for the error key first; if it’s absent, treat the body as a
field → messages map.
Server errors
A 500 never leaks internal detail. The full exception (including stack trace) is captured server-side;
the client always receives a fixed, parsable body:
If you hit a reproducible 500, contact support with the timestamp and endpoint — we can correlate it to
the captured exception.
A request to a completely unrouted /api/v1/... path (a typo’d or non-existent endpoint) returns
Django’s HTML 404 page rather than the JSON envelope above. Always confirm your path matches an endpoint
in the API Reference — every routed endpoint returns JSON, but an unknown path does
not.