Skip to main content

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 gets 400 with a list of the failing parts instead, one entry per part, each with the Zod issues that explain what is wrong:
Show 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

429, 502, 503, 504 and network errors. Back off exponentially (for example 1s, 2s, 4s, with jitter) and give up after a few tries.
400, 401, 403 and 404. The same request will fail the same way. Fix the input, the key or its scopes first.
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.