Skip to content
Discord

Limits & compliance

Two kinds of limit apply to you: ours (technical, we enforce them) and India’s (regulatory, you are responsible for them).

Limits are per secret key.

LimitPilot defaultApplies toOver the limit
Request rate10 requests/second, burst 20all /v2/* endpoints429 rate_limited
Concurrent live calls5calls in dialing or in_progressthe call queues
Queue depth500calls accepted and not yet ended429 rate_limited

Exceeding the request rate returns 429 with error.code: rate_limited and a Retry-After header in seconds. It is about how fast you call the API, not about how many phones are ringing.

429 Too Many Requests
{
  "error": {
    "code": "rate_limited",
    "message": "rate limit exceeded, retry in 0.4s"
  }
}

Concurrency does not produce a 429. A POST /v2/calls beyond your concurrent-call ceiling is still accepted with 202 and sits in queued until a slot frees, then dials — nothing is rejected and nothing is lost. 429 is request-rate only.

That makes the ceiling a pacer, not a gate. Two consequences:

  • A queued call’s phone rings later than you asked. If a call is only useful inside a window, check status before you assume it went out — or do not submit it until you have the capacity.
  • Submitting a burst does not fail; it builds a queue that drains at your concurrency.

The queue itself is bounded. Once you have 500 calls accepted and not yet ended, further POST /v2/calls return 429 rate_limited with a Retry-After header until calls drain. The message names the ceiling, so you can tell it apart from a request-rate 429:

429 Too Many Requests
{
  "error": {
    "code": "rate_limited",
    "message": "queue depth limit reached for this workspace (500 calls accepted and not yet ended, limit 500); wait for calls to drain or ask ops to raise it"
  }
}

Both limits share the rate_limited code on purpose: the correct client behaviour is identical — honour Retry-After and retry. Read error.message if you want to log which one you hit.

The count is calls accepted and not yet endedqueued plus the handful actually dialing or in_progress — not strictly queued. With a concurrency of 5 the difference is at most 5 calls.

Queue depth is provisioned per workspace, like concurrency. If a campaign genuinely needs to submit more than 500 rows in one batch, ask ops before the campaign, not during it.

Keeping the queue short is still the better shape, because a queue you own is one you can reorder, cancel and re-prioritise. The simplest correct pattern:

# keep N calls in flight; refill as terminal webhooks arrive
in_flight = 0
MAX_IN_FLIGHT = 5   # your provisioned concurrency

def on_terminal_webhook(event):
    global in_flight
    in_flight -= 1
    pump()

def pump():
    global in_flight
    while in_flight < MAX_IN_FLIGHT and queue:
        place_call(queue.pop())
        in_flight += 1

Do not drive pacing off a fixed sleep(). Answer rates vary by hour, and a fixed delay either wastes capacity or hammers the limit.

ThingLimit
Request body1 MB
system_prompt8,000 characters
first_message500 characters
variables32 keys, 512 characters per value
max_duration_secs30–1800, default 300
webhook_urlHTTPS only, 2,048 characters
Idempotency key255 characters, 24-hour window

Long prompts are a latency problem before they are a limit problem. The transactional tier is tuned for prompts in the hundreds of tokens, not thousands.

StageBehaviour
API requestRespond within 30 seconds or treat as failed and retry with the same Idempotency-Key.
Ring / answer~60 seconds. No media by then → no_answer.
Call durationEnds at max_duration_secs with status: timeout.
Webhook deliveryYour endpoint should answer well under a second. Slow responses are treated as failures and retried.
DataRetained
Call metadata (status, duration, cost)12 months
Wallet ledger12 months
Call recordings and transcripts30 days, then deleted

Recordings are not exposed through the v2 API. If you need them, ask ops — and tell us up front if your use case requires that we not record at all.


You are the sender. Under Indian telecom regulation the obligations for commercial voice calls sit with the business placing them, not with the platform carrying them. Reading this page is not legal advice, and it is not a substitute for your own compliance review.

Commercial and promotional voice calls are restricted to daytime hours. The window applied in practice is 09:00–21:00 IST, and several enterprise programmes tighten it further to 10:00–19:00.

The v2 API does not enforce a calling window for you. POST /v2/calls at 02:00 IST will dial at 02:00 IST. Gate it in your scheduler:

from datetime import datetime
from zoneinfo import ZoneInfo

IST = ZoneInfo("Asia/Kolkata")

def within_calling_window(now=None) -> bool:
    now = now or datetime.now(IST)
    return 9 <= now.hour < 21
  • Get consent before you call. Explicit, recorded, and revocable. Keep the record — it is what you produce when a complaint arrives.
  • Scrub against the DND registry (TRAI’s Do Not Disturb / NCPR list) and against your own opt-out list before every campaign. A number can register between two campaigns.
  • Honour opt-outs immediately. If a customer says “stop calling me” during a call, that is an opt-out — capture it and suppress the number, on every channel it applies to.
  • Transactional vs promotional matters. A delivery confirmation to an existing customer is treated differently from a marketing pitch to a cold list. Classify each campaign, and do not let a transactional pretext carry a promotional payload.
  • Register as required. Commercial communication under TCCCPR 2018 runs through registered entities, headers and consent templates. Confirm your registration status with your telecom provider or counsel.

Tell people. Put it in the agent’s first_message or its opening turn:

{
  "first_message": "नमस्ते {{customer_name}}, मैं Acme की AI असिस्टेंट Priya बोल रही हूँ।"
}

This is the direction regulation is moving in worldwide, it costs you one clause, and in practice it reduces early hang-ups — callers who feel misled hang up harder than callers who were told.

If you record calls, say so in the opening turn and keep the recordings under the same retention and access controls as the rest of your customer data.

RuleEnforced by us
E.164 destination format400 invalid_request
Wallet balance before dialling402 insufficient_balance
Request rate429 rate_limited
Concurrency ceiling✅ over-cap calls wait in queued
Queue depth429 rate_limited past 500 outstanding
Maximum call durationstatus: timeout
Calling window❌ your scheduler
DND / opt-out scrubbing❌ your list
Consent records❌ your records
AI disclosure❌ your prompt

Persistent complaint patterns against a workspace will get its keys suspended. That is not a regulatory mechanism, it is ours — we would rather suspend one campaign than lose the numbering range for everyone on the platform.