Skip to main content
New here? Start with the Quick start. This section is the exhaustive reference.

Base URL

Resource-oriented URLs, JSON in and out, standard verbs and status codes.

The envelope

Every response is wrapped:
Unknown fields are omitted — we do not send nulls. Branch on error.code, never on error.message. See Errors.

Objects

Authentication

Bearer token on every request.
The credential’s form selects the Loom mode: a JWT is direct, anything else is relay. See Authentication.

Headers

Versioning

Public endpoints live under /v1. Breaking changes get a new prefix; additive fields may appear on existing objects without one. Agent ids pin one exact version, so a published agent’s behaviour does not change under you.

Pagination

Every collection is paginated the same way. Pass limit and cursor; read pagination beside data.
Walk a collection by following next_cursor until has_more is false, at which point next_cursor is null. Cursors are stable under writes: new rows arriving mid-walk will not shift a page and cause you to skip or repeat a row, which is why there is no page or offset, and no total count. Messages are ordered oldest-to-newest within the page, while the pages themselves walk backwards from the most recent — so opening a thread costs one request, and following the cursor loads older history.

Idempotency

Send an Idempotency-Key on any POST and the call becomes safe to retry. The key is yours to choose; a UUID per logical operation is the usual shape. Our SDKs generate one for every POST automatically. The first request with a given key does the work and its response is stored. A retry with the same key returns that stored response, carrying Idempotency-Replayed: true — it does not run again, and it does not charge again. A replay is still a request, so it appears in your activity log with Idempotency-Replayed. It is left out of the Identify dashboard’s counts, which report lookups performed and therefore match what you were charged. Keys are scoped to your workspace and expire after 24 hours. Without a key, a POST behaves as it always has: repeating it repeats the work, so POST /v1/identify re-resolves and charges again, and a second POST …/messages starts a second turn.

Rate limits and credits

Requests are metered per workspace — all API keys share one allowance. Every response carries RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset; a rejection is 429 with Retry-After. Credits are prepaid and spent per run. An empty balance returns 402. See Rate limits and credits.