Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.kayle.id/llms.txt

Use this file to discover all available pages before exploring further.

Errors use the same envelope as successful responses, with data: null and an error object describing what went wrong:
{
  "data": null,
  "error": {
    "code": "UNKNOWN_CLAIM_KEY",
    "message": "Unknown claim key.",
    "hint": "Use a supported claim key from the share contract allowlist.",
    "docs": "https://kayle.id/docs/api/sessions#create"
  }
}
code is stable and safe to match on. message and hint are human-readable and may evolve. docs points to the relevant guide. For list endpoints, the envelope also includes pagination with limit, has_more: false, and next_cursor: null so the response shape stays consistent on error.

HTTP status codes

StatusWhen it’s used
200Success.
201Resource created.
202Accepted; processing continues asynchronously (event replay).
204Success, no body (cancel, delete).
400Validation failure. The body explains which field.
401Missing or invalid Authorization header.
403Authenticated but lacking the scope or role.
404Resource not found, or scoped to a different organization.
409State conflict (e.g. cancel token already consumed).
410The owning organization is pending deletion. API keys are disabled until deletion is cancelled.
426The endpoint requires a WebSocket upgrade and got a plain HTTP request.
500Internal error. Safe to retry idempotent operations after backoff.

Common error codes

CodeHTTPMeaning
UNAUTHORIZED401The Authorization header is missing, malformed, or refers to a deleted/disabled key.
FORBIDDEN403The key or session is authenticated but lacks the required scope.
NOT_FOUND404The resource does not exist or belongs to another organization.
BAD_REQUEST400The request shape failed validation. The message indicates the field.
INVALID_REQUEST400A semantic precondition failed (e.g. starting_after cursor doesn’t exist).
CONFLICT409The operation can’t proceed in the current state.
INTERNAL_SERVER_ERROR500Something blew up server-side. Retry idempotent calls after backoff.
ORGANIZATION_FROZEN410The owning organization has requested deletion. API keys are disabled until the deletion is cancelled.

Resource-specific codes

Sessions

CodeHTTPMeaning
UNKNOWN_CLAIM_KEY400A share_fields key isn’t in the allowlist. See Share fields.
SESSION_NOT_FOUND404The session ID doesn’t exist or belongs to another organization.
INVALID_SESSION_ID400The session ID is malformed.
SESSION_EXPIRED409Operation rejected because the session is past its 60-minute window.
SESSION_IN_PROGRESS409Operation conflicts with an in-flight attempt (e.g. cancelling a verifying session).

Verify (public endpoints)

These appear when the verify web app or a mobile client talks to /v1/verify/*. You’ll usually only see them in user-facing error states, not in your own server code.
CodeHTTPMeaning
CANCEL_TOKEN_INVALID401The cancel token in the body doesn’t match the session.
CANCEL_TOKEN_USED409The cancel token was already consumed.
WEBSOCKET_REQUIRED426The verify socket endpoint was called without a WebSocket upgrade.
HANDOFF_TOKEN_INVALID / HANDOFF_TOKEN_EXPIRED / HANDOFF_TOKEN_CONSUMED401 / 401 / 409Mobile handoff token rejected.
HANDOFF_DEVICE_MISMATCH403Different device than the one that first claimed the attempt.

Webhooks

CodeHTTPMeaning
WEBHOOK_URL_REJECTED400The URL fails Kayle’s safety checks (must be https://, not a private IP).

What to retry

5xx and transient network failures are safe to retry on idempotent operations (GET, DELETE, POST /cancel). Every POST /v1/sessions produces a brand-new session — retrying after a 5xx may create a duplicate. Use a request-side idempotency check (last response captured before the timeout) before re-issuing creates. 4xx responses other than 429 (which the API does not currently emit) are permanent — fix the request shape rather than retrying.