All docs

Rate Limits & Idempotency

Per-key request caps, the 429 contract, and the idempotency story.

Per-key rate limit

Every API key is capped at 100 requests per second across all /v1/* endpoints. The cap is implemented as a sliding-window KV counter; bursts up to ~110 rps are tolerated under eventual consistency.

When you exceed the cap, the response is:

HTTP/1.1 429 Too Many Requests
Retry-After: 1
Content-Type: application/json

{ "error": "rate limited", "code": "RATE_LIMITED" }

Obey Retry-After (in seconds). We do NOT auto-queue; the caller is responsible for retry.

New-contact monthly limit

Plans cap new contacts per month, not message volume. Once a number is on your contact book (because you sent it a message in any prior period), further sends to that number are unlimited regardless of plan.

PlanNew contacts / dayNew contacts / month
Starter ($49)10250
Growth ($249)501,250
Scale ($749)50010,000

When the cap is hit, sends to new numbers fail with 403 QUOTA_EXCEEDED. Existing-contact sends keep flowing.

Idempotency

Until then, deduplicate caller-side. A common pattern:

const seen = new Map<string, string>()

async function sendOnce(payload: { to: string; body: string }) {
  const key = `${payload.to}::${payload.body}`
  if (seen.has(key)) return seen.get(key)!
  const result = await client.messages.send(payload)
  seen.set(key, result.message_id)
  return result.message_id
}

Burst handling

Hard cap is per-second. If you sustain 110+ rps for over a minute, expect intermittent 429s. The Retry-After value reflects when our window will reset — typically 1 second.

Webhook delivery rate

Inbound to your endpoint: best-effort, no rate cap from our side. We deliver as events fire. We retry up to 3 times with 2/4/8-second exponential backoff.

Voice rate limits

Outbound voice calls have a separate cap: 10 calls/minute/tenant. See Voice quickstart.