Skip to main content
A call is one outbound dial attempt driven by an agent. Creating a call is asynchronous: you get 202 Accepted immediately and the outcome arrives by webhook (or by polling GET /v2/calls/{id}). Base URL https://api.voice.miraiminds.co.

The call object

Statuses

Statuses only move forward. A terminal status never changes.

Ended reasons

ended_reason explains why a terminal status was reached. Match on status for control flow; use ended_reason for analytics and support.
Treat ended_reason as an open vocabulary. New values are added without a version bump — always have a default branch. The last two rows above are in the vocabulary but no call emits them today; they arrive with the warm-transfer rollout and the t3/t5 tiers — see the roadmap.
no_answer is under-reported todaySome calls that genuinely rang out are reported as failed with ended_reason: "no-media" rather than as no_answer.Whether we can tell the two apart depends on what the carrier tells us. When the carrier returns a clear verdict (SIP 480/408 → rang out, 486/600 → busy) you get no_answer / busy correctly. When it black-holes the call instead — accepts the invite and returns nothing — we have no signal to distinguish “rang, nobody picked up” from “answered into silence”, and the call ends failed / no-media after the media gate expires.What this means for you: if you are counting unanswered calls for retry logic, treat no_answer, busy and failed + no-media as the did-not-connect bucket. None of the three is billed, so your costs are unaffected either way. We are working on tightening this; the reported status will get more specific over time, never less.

Create a call

Request

202 Accepted
202 means the call is admitted to the queue — the phone has not rung yet. The full call object is available from GET /v2/calls/{id}.

Errors

Variables

variables is a flat map of string keys to string values. Each key replaces the matching {{key}} placeholder in the agent’s system_prompt and first_message.
  • Keys are matched literally and case-sensitively.
  • A placeholder with no matching variable is substituted with an empty string — it does not error, and it does not leave {{braces}} for the agent to read aloud. Validate on your side.
  • Keep values short. They are part of the prompt, and the prompt is on the latency path.
  • Variables are static per call. There is no way to change them mid-call.

Idempotency

Send Idempotency-Key with a value derived from your own domain object:
If we have seen that key in the last 24 hours, we replay the original response byte for byte and place no second call. This is the safe way to retry a request that timed out — you cannot tell from a network timeout whether the call was placed, and without the key a retry means the customer’s phone rings twice. The key is scoped to your workspace. Reusing a key with a different body still replays the original response — pick keys that are unique per intended call. There is one window where a reused key does not replay: while the first request with that key is still being processed, there is no stored response to replay yet, so the second request gets 409 duplicate_call. It means “already in flight, no second call placed” — retry a moment later and you will get the original response, or wait for the webhook.

Get a call

200 OK — the call object. 404 not_found for an unknown ID, and for an ID that belongs to another workspace — the two are deliberately indistinguishable.
Poll no faster than every 5 seconds, and only when you cannot receive webhooks. Polling counts against your rate limit; webhooks do not.

Abort a call

Cancels a call that has not ended yet. Accepted while the call is queued, dialing or in_progress — a live call is hung up on the SIP server mid-conversation, not merely flagged. Only a call that has already reached a terminal status is refused: there is nothing left to stop.
202 Accepted
202 means the cancel was signalled. The call reaches aborted shortly after with ended_reason: "aborted-by-api", and a call.aborted event fires. An aborted call is never billed — including one aborted after media went live.

List calls

200 OK
Results are newest first. See pagination.
The list endpoint is for reconciliation and reporting, not for driving your application state. For that, use webhooks.