Error body
Every error from the public API has the same JSON shape:string
required
A human-readable message. Log it; don’t branch on it, the wording may change.
string
A stable machine-readable code, when there is one. Branch on this.
Validation errors
A request whose path, query or body fails validation gets400 with a list of the failing parts instead, one entry per part, each with the Zod issues that explain what is wrong:
path and message to whoever wrote the input; don’t parse message.
Status codes
An id that belongs to another organization answers
404, exactly like one that doesn’t exist. Lancer never tells you whether another organization’s record exists.Rate limits
Responses carry the standard
RateLimit and RateLimit-Policy headers (IETF draft 8), so you can see how much of the window is left. Over the limit you get 429 with { "error": "Too many requests" }.
Retrying
Safe to retry
Safe to retry
429, 502, 503, 504 and network errors. Back off exponentially (for example 1s, 2s, 4s, with jitter) and give up after a few tries.Don't retry as-is
Don't retry as-is
400, 401, 403 and 404. The same request will fail the same way. Fix the input, the key or its scopes first.Creates are not idempotent
Creates are not idempotent
POST /v1/leads, /v1/clients and /v1/payment-requests create a new record on every call. If a create timed out, list recent records (for example GET /v1/clients?q=…) before trying again, so you don’t make a duplicate.