Developer docs

Rate limits & idempotency

Per-key rate limits with standard headers, and Idempotency-Key support so retries never double-send.

Two request-level features make automating against the API safe: rate limits tell you how much budget you have, and idempotency lets you retry sending endpoints without sending twice.

Rate limiting

Each API key is limited to 300 requests per 60 seconds (5 req/s sustained). Every response carries the current budget:

HeaderMeaning
X-RateLimit-LimitThe per-window ceiling.
X-RateLimit-RemainingRequests left in the current window.
X-RateLimit-ResetSeconds until the window frees a slot.

Going over the limit returns 429 Too Many Requests with a Retry-After header (in seconds). Wait that long, then retry.

The AI endpoint has its own, much lower limit

POST /conversations/:id/ai-draft is additionally limited to 20 requests per 60 seconds per key, reported under its own headers so the general budget above stays readable:

HeaderMeaning
X-RateLimit-AI-LimitThe per-window ceiling for AI calls.
X-RateLimit-AI-RemainingAI calls left in the current window.
X-RateLimit-AI-ResetSeconds until that window frees a slot.

It is separate because this endpoint spends money, not just a database round trip. At the general ceiling a runaway loop would bill three hundred generations a minute while looking completely healthy — every request valid, nothing to alarm on. Your workspace AI budget is still the real backstop; this is the earlier, cheaper one.

Both limiters run on an AI request, and the stricter one bites first.

Idempotency

Creating a conversation and replying both send email, so a blind retry after a network blip could send twice. Prevent that by sending an Idempotency-Key header — any string unique to the operation (a UUID is ideal):

POST /conversations/:id/reply
Authorization: Bearer rp_live_…
Idempotency-Key: 3f9c1e7a-9b2d-4c8e-a1f0-6d5b4c3a2e10
Content-Type: application/json
  • The first request runs normally; its response is stored against the key.
  • A retry with the same key and body replays that stored response — no second email.
  • Reusing the key with a different body returns 409 Conflict.
  • A retry sent while the first is still in flight returns 409 — wait, then retry.

Keys are remembered for 24 hours. A request without the header is processed normally (not deduplicated), so always send one whenever a retry is possible.

Recovery after an interrupted request (next grouped release)

For conversation creation and replies, an accepted message source is retained with the idempotency reservation. If the connection is lost before a response is saved, retry using the same key and unchanged body. The retry can return the existing conversation and its current message state without creating or sending another message. A conversation response can contain queued or uncertain delivery; check the message’s deliveryState before treating it as delivered.

Completed responses keep the normal 24-hour replay window. An unresolved committed source is retained beyond that window until reconciled. A missing retained message returns 409 and is not recreated. A request that committed no source can safely retry after its reservation is released or expires. Older uncertain requests without a recoverable source still return 409; inspect the conversation before starting a separate send.

A retained source does not imply successful provider delivery; inspect the existing outcome before taking further action.