Rate limits
Limits are per secret key.Request rate
Exceeding the request rate returns429 with error.code: rate_limited and
a Retry-After header in seconds. This limit measures how fast you call the
API, not how many phones are ringing.
429 Too Many Requests
Concurrency
Call concurrency does not produce a429. A POST /v2/calls beyond
your concurrent-call ceiling is still accepted with 202. It waits in queued
until a slot frees and then dials, so no call is rejected or lost. On the call
path, 429 is request-rate only. (Text to speech over HTTP
is the one exception: it has no queue, so it refuses the request.)
So the ceiling paces your calls instead of refusing them. That has two
consequences:
- A queued call’s phone rings later than you asked. If a call is only useful
inside a window, check
statusbefore 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.
Queue depth
The queue itself is bounded. Once you have 500 calls accepted and not yet ended, furtherPOST /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
rate_limited code on purpose, because your client should
handle them the same way: honour Retry-After and retry. Read error.message
if you want to log which one you hit.
The count covers calls accepted and not yet ended. That is queued plus the
few calls actually dialing or in_progress, not queued alone. With a
concurrency of 5, the difference is at most 5 calls.
Queue depth is provisioned per workspace, like concurrency. If a campaign needs
to submit more than 500 rows in one batch, ask your Mirai contact before the
campaign starts, not during it.
Even so, it is better to keep our queue short and hold the rest on your side,
where you can reorder, cancel and re-prioritise it. The simplest correct pattern
looks like this:
sleep(). Answer rates vary by hour, and a
fixed delay either wastes capacity or hammers the limit.
Text to speech
Every workspace has one pool of synthesis slots, 10 by default. An HTTP request to the speech API holds a slot while it runs, and so does each sentence on a WebSocket stream while it is being synthesised. An open socket that is not speaking holds none. The two handle a full pool differently. The HTTP endpoint has no queue, so it refuses the request. On a stream, a sentence whose turn has come waits up to 3 seconds for a slot, in a queue shared by all your sockets, before it fails.at_capacity can also come from a deployment-wide ceiling when the speech node
is saturated. It is the same code, and you handle it the same way. A refused
request holds no slot and is never charged.
The limit is raised on request, with no change to your code. If you run many
calls at once, ask your Mirai contact for a limit a little above your peak
number of simultaneous calls: each speaking call needs a slot most of the
time, and it starts its next sentence shortly before the current one ends.
Streams have their own limits:
See Streaming text to speech for what each limit
does to an open socket.
Speech to text
A workspace can run 10 speech-to-text sessions at once. Each HTTP request is a session while it runs, and so is each open socket. One more returns429 at_capacity with Retry-After and costs nothing; a socket is refused
before the upgrade. The limit is raised on request, with no change to your code.
See the STT quickstart and the
WebSocket reference for what each limit does.
Payload and duration ceilings
Invalid values return
400 invalid_request.
Call timing
max below is the call’s effective max_duration_secs. See
timing policy.
Live events
These apply to every call’s live event stream: phone, campaign, inbound, browser and realtime.Browser calls
Node-based agents
We check a node-based agent’sflow on every save. A flow
over a graph limit returns 400 invalid_flow with the path of each problem. A
generation or transcription request over its limits returns
400 invalid_request.
A flow generation typically takes 15 to 60 seconds, depending on the model; set
a client timeout of a few minutes. When the generator is busy with other
requests, it answers
429 rate_limited with Retry-After, and that refusal
does not count against the hourly limit. A transcription typically takes 5 to
10 seconds for a two-minute call, and the transcriber answers 429 the same way
when it is busy. Each generation and transcription is charged to your wallet at
the provider’s reported cost plus 20%; see
AI flow drafts.
Offline transcription
Offline transcription checks the job count and your wallet before it reads the recording, and nothing is charged for a refused request.Campaign ceilings
Campaigns carry their own bounds, all enforced at the API edge with400 invalid_request.
Bad contact rows do not fail the batch: they come back by index in
contacts_rejected. Only exceeding 1000 rows fails the whole request.
Long prompts add latency well before they reach a size limit. The stack is
tuned for prompts in the hundreds of tokens, not thousands.
Timeouts
Data retention
You can fetch recordings and transcripts through the API with
GET /v2/calls/{id}/recording and
/transcript. Pull anything you need to keep
beyond 90 days into your own system. To store no audio, create calls with
recording_enabled: false, or ask us to turn recording off for your whole
workspace.
Save your own copy of each offline transcript when its job completes. If a
transcript is no longer available, its job still reads completed with its
cost, but without the text. To have a transcript removed, write to
help@miraiminds.co.
India calling rules
Under Indian telecom regulation you are the sender: the obligations for commercial voice calls sit with the business placing them, not with the platform carrying them. This page is not legal advice, and it does not replace your own compliance review.Calling window
Commercial and promotional voice calls are restricted to daytime hours. The window applied in practice is 09:00 to 21:00 IST, and several enterprise programmes tighten it further to 10:00 to 19:00. On a campaign, the platform enforces the window you declare. The platform evaluatestimezone, start_date/end_date and 1 to 4 slots in
local time on every dialling tick. Outside the window the campaign stays in
play but rings nobody. Declaring 10:00 to 19:00 Asia/Kolkata is enough,
and you do not need your own scheduler in front of it.
POST /v2/calls there is no window.
A direct call is an explicit instruction to ring one number now, and it will
dial at 02:00 IST if you ask it to. Enforce the window for those calls in your
own scheduler:
Consent and DNC/DND
- Get consent before you call. Consent should be explicit, recorded and revocable. Keep the record, because you will need to produce it when a complaint arrives.
- Push your opt-outs to
POST /v2/dnc. We enforce that list: every campaign checks it at dial time, so a number added mid-campaign is suppressed from that moment, markedsuppressedin the report, and never billed. It does not apply to singlePOST /v2/calls, because a single call is an explicit instruction. - Scrub against the DND registry (TRAI’s Do Not Disturb / NCPR list) as well. We do not scrub against the national register for you, and our suppression list is not a substitute for it. 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.
- Classify each campaign as transactional or promotional. A delivery confirmation to an existing customer is treated differently from a marketing pitch to a cold list. Do not put promotional content in a call you present as transactional.
- 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.
Disclosure that it is an AI
Tell people they are talking to an AI. Put the disclosure in the agent’sfirst_message or its opening turn:
Recording
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. If you do not need the audio, do not store it:recording_enabled: false keeps no
recording for that call, and a workspace with recording turned off refuses
recording_enabled: true with 403 recording_disabled.
What we do enforce
If complaints against a workspace persist, we suspend its keys. This is our own
policy rather than a regulatory one: we would rather suspend one campaign than
lose the numbering range for everyone on the platform.