Documentation menu

Errors

One shape, always.

{
  "error": {
    "code": "invalid",
    "message": "no value for guest_name",
    "hint": "A contract that ships with a placeholder still in it is worse than one that failed to send."
  }
}

The message is frequently the database's own sentence, passed through rather than replaced. It is more specific than anything this layer could write, and the layer that knows why something was refused is the layer that refused it.

StatusCodeMeans
400bad_requestThe request could not be read at all.
401unauthorizedNo key, or a key that is not live. Unknown, revoked and expired all answer the same way — a caller who could tell them apart could enumerate.
403forbiddenThe key is live and its scopes do not carry this.
404not_foundNo such thing, in this account. A thing in another account answers the same way, and deliberately: confirming it exists would be the leak.
405method_not_allowedThat path exists under another method. Said separately from 404 because it saves an hour.
409conflictAn idempotency key reused for a different body, or the first attempt still running.
413too_largeLarger than a signing request ever is.
422invalidThe body did not validate, or the engine refused it. The message is the engine's own sentence.
429rate_limitedToo many attempts. The message names the budget and the hint says when to try again.
500internalOurs. Quote the x-request-id.

Retrying

Retry 429 and 500, with backoff. Do not retry 422 — the request will be refused the same way every time, and the message says why. Retrying anything that creates something means sending an idempotency key; our own SDK mints one for you.

Ready to build? An API key takes a minute in the portal, and the free plan covers the first 25 agreements a month.

Get an API key