Documentation

Authentication

API keys, scopes, and what a key can be limited to.

Every request carries a bearer token: Authorization: Bearer sk_live_…. Keys are created in the dashboard under API keys, or with POST /v1/api-keys, shown once, and stored only as a hash. If you lose one, revoke it and make another.

The API also accepts an OAuth access token (srv_oat_…), which is what an MCP client holds after signing in through the consent screen. It carries the scopes that were granted and none of a key's limits: no daily limit, no recipient allowlist and no approval hold, which belong to a key someone configured. Because nothing limits it, it also cannot decide an approval: POST /v1/approvals/{id} answers 403 forbidden for an OAuth token, and approvals are decided by a person in the dashboard or by an API key without guardrails. See API keys and the MCP server.

Scopes

A key carries only the scopes you grant it. A key that only sends transactional mail has no business reading your contact list, and scoping it accordingly limits what a leak costs you. A route called without its scope answers 403 forbidden, naming the scope.

ScopeAllows
emails:sendSend one message or a batch, cancel a scheduled send, decide an approval (API keys only, and not a key with guardrails), mark a thread handled, add and remove suppressions, enrol someone in an automation, and record an event
emails:readRead sent emails, their event timelines and metrics, the suppression list, the approvals queue and usage
threads:readRead conversations and inbound replies, and download inbound attachments
domains:readList sending domains and read one
domains:writeAdd, verify and delete sending domains, and list, create, edit and revoke API keys
contacts:readRead audiences, contacts, tags, contact properties, segments, topics and a person's topic preferences
contacts:writeCreate and delete audiences, add, edit, tag and remove contacts, manage contact properties, segments and topics, and set or import topic preferences
broadcasts:readRead campaigns, their preview, recipients and clicked links, and read automations
broadcasts:writeCreate, edit, send, resume, decide and delete campaigns, and create, edit, switch on or off and delete automations
templates:readList and read templates, and render one
templates:writeCreate, update, duplicate and delete templates
webhooks:readList webhook endpoints and their recent deliveries
webhooks:writeCreate, edit and delete webhook endpoints

domains:write is the closest thing to an administrative scope, because it is the one that manages keys. Grant it only to a key that should be able to mint others. A key it mints can hold only scopes the minting credential holds, and a key that carries a daily limit, a recipient allowlist or an approval hold can only mint keys at least as restricted. No key can edit or revoke itself: either answers 403 forbidden. See API keys.

A key's limits also apply to campaigns. A key with an approval hold or a recipient allowlist cannot send, schedule, reschedule or resume a campaign, or decide an A/B test's winner (403 forbidden), and a key with a daily limit can start one only when its recipients fit what is left of that limit today (429 daily_limit). See Guardrails.

Idempotency

POST requests accept an Idempotency-Key header. Replaying the same key on the same path in the same workspace within 24 hours returns the stored response rather than acting again, and the response carries Idempotent-Replay: true so you can tell. Only a successful response is stored: after a 4xx or 5xx, a retry with the same key runs the request again. A retry that arrives while the first request is still running waits up to 8 seconds for it and returns its answer, and answers 409 idempotency_in_progress only if it is still running after that. A key must be reused only with the identical request: the same key with a different body answers 422 idempotency_key_reused, once the endpoint's scope has been checked (a credential without the scope gets 403). Responses that carry a secret shown once (a new API key, a new webhook endpoint) are never stored, so retrying those creates another. See Idempotency.

On this page