Errors
The shape
Every error returns the same JSON, with no stack traces, SQL, or file paths:
{ "error": { "code": "authenticate_user.invalid_credentials", "message": "authenticate_user.invalid_credentials" } }
The code is a stable translation key, not localized text. Your client maps it to a message in the user's language at render time, so error copy lives on your side and never changes under you.
Status codes
- 400 Bad Request: malformed input (invalid email, bad UUID, unknown query value).
- 401 Unauthorized: missing or invalid key or token.
- 402 Payment Required: the wallet has no balance to reserve the job. Distinct from
403so you can prompt a top-up rather than a permission fix. - 403 Forbidden: the key is missing the required scope or check.
- 404 Not Found: no such resource for your account (a UUID owned by someone else looks identical to a missing one).
- 408 Request Timeout: the request exceeded the server's processing budget (
request.timeout); safe to retry. - 409 Conflict: for example an idempotency key reused with a different body.
- 429 Too Many Requests: rate limit exceeded. The response carries
Retry-After.
No enumeration
Authentication failures return the same error for an unknown email and a wrong password, so responses never reveal whether an account exists.