API reference
Errors
The error envelope, and the codes worth branching on.
Every error has the same shape, including unexpected ones:
{ "error": { "code": "invalid_request", "message": "Country must be a two-letter ISO code." } }
Branch on code. message is written for a person to read and may be
reworded; code is part of the contract.
Codes
| Status | Code | Means |
|---|---|---|
| 400 | invalid_request | The request was malformed or a value was rejected. |
| 401 | unauthorized | No credential, or one that does not verify. |
| 403 | forbidden | Authenticated, but not allowed to do this. |
| 404 | not_found | No such thing, or nothing you may see. |
| 409 | conflict | Something already exists: a taken username, a duplicate. |
| 429 | rate_limited | Too many requests. Back off and retry. |
| 500 | internal_error | Ours. Quote the reference if you contact support. |
What errors deliberately do not tell you
Sign-in and passwordless endpoints answer identically whether or not an address belongs to anybody. A wrong password and an unknown account produce the same error, and requesting a magic link for an unknown address succeeds.
That is not vagueness for its own sake: a distinguishable response turns any of those endpoints into a way to test whether a given person has an account with you.
Internal errors say nothing about the cause
A 500 carries a generic message and a reference:
{
"error": {
"code": "internal_error",
"message": "Something went wrong on our side. Quote reference 4f2a9c11 if you get in touch."
}
}
Updated at, Friday, August 28, 2026