RefreshDocsConsole →

API reference

Rate limits & idempotency

Per-key request caps, daily send caps, daily event quotas, and how Idempotency-Key makes retries safe.

Rate limit

The API caps each key at 10 requests per second. An admin can give a key its own cap (1–1000) when the admin creates the key. Ops can change the platform default with API_RATE_LIMIT_PER_SEC. Unset, blank, or 0 uses 10. Over the cap you get 429 rate_limited with the header Retry-After: 1.

POST /emails/batch costs one request per message. The route reserves 100 tokens before it reads the body, then refunds unused tokens. A batch that starts in an empty second always goes through. Concurrent batches in that second: the limiter admits only the first reserved batch. The rest of that second answers 429 until the window turns. At the default cap that is 100 messages per second per key.

Daily send caps

The worker charges three daily allowances (UTC day) before handing a message to the transport. Each recipient counts as one email, so a message to 10 addresses uses 10. Mail over a cap waits in the queue and goes out when the day turns. The API still answers 200, and the message stays queued.

Allowance Default Where to change it
Domain warm-up stage 200 to 20,000 per day, by stage Automatic. See Domains.
Organization plan ceiling (Free: 100) or 20,000 per day Settings → Organization → Daily send cap. On a plan with a ceiling, blank or 0 is the ceiling and a value can only lower it. On other plans, blank = default and 0 = no cap, or ORG_DAILY_SEND_CAP.
Platform account 45,000 per day Platform-wide ceiling across all organizations.

The worker also caps sends at 12 per second across the platform.

Daily quotas (POST /events)

A SEND key can post events. Two per-organization daily counters (UTC) therefore bound what a leaked key could do:

Quota Default Error
New contacts created through events 1,000 / day 429 contact_quota_exceeded
Automation runs started by events 5,000 / day 429 run_quota_exceeded

Contacts that already exist and events that match no automation do not consume quota.

Idempotency

POST /emails accepts an idempotency key in two ways: the Idempotency-Key request header (preferred) or idempotency_key in the body. The header wins when both are present.

  • Keys are unique per organization, and the platform keeps them with the message.
  • A repeat with the same key returns the original message id and the header Idempotent-Replayed: true. The platform sends nothing again, even if the status of the first message is now delivered, bounced or canceled.
  • If the first attempt stored the message but crashed before it queued the message, the replay queues it. A retry is always safe.
  • Select keys that name the intent: invoice:1234:sent, availability:<employeeId>:<date>.

Batch items use idempotency_key in each item body. The API ignores the request header for batches.

Messages from the SMTP relay use the key smtp:<key id>:<Message-ID>. The prefix keeps those keys apart from the keys of your HTTP calls, and one API key apart from another. A message without a Message-ID carries no key.

The worker retries the send itself on transient transport errors (up to 4 attempts, exponential backoff from 30 s). You do not need to retry a 200.