Place an outbound AI call, follow it to a terminal status, read the transcript and summary, and hang up early when you need to.
Give Dairo a destination, a caller id you own, and instructions, and an AI agent makes the call. This page walks the whole lifecycle: place, poll, read, hang up.
| Operation | Method & path | Scope |
|---|---|---|
| Place a call | POST /v1/phone/calls | phone:call |
| List calls | GET /v1/phone/calls | phone:read |
| Get one call | GET /v1/phone/calls/{id} | phone:read |
| Transcript | GET /v1/phone/calls/{id}/transcript | phone:read |
| Recording | GET /v1/phone/calls/{id}/recording | phone:read |
| Hang up | POST /v1/phone/calls/{id}/hangup | phone:call |
Place a call
Pass to, from, and instructions — everything else is optional. from must be a number your account owns with status active; buy one on Phone numbers.
You get back a phone_call at status: "queued" — the request returns before the phone rings, and the call proceeds on its own:
The CLI's --wait flag polls the call for you until it reaches a terminal status, then prints the transcript — the fastest way to try your first call end to end.
Request fields
| Field | Required | Description |
|---|---|---|
to | Yes | Destination, E.164 (e.g. +13125550147). |
from | Yes | Caller id, E.164. Must be a number your account owns with status active — anything else is rejected with 400. |
instructions | Yes | What the agent should accomplish, up to 8,000 characters. This is the whole conversation brief: goal, tone, facts it may share, length. |
greeting | The opening line, spoken when the callee answers, right after Dairo's fixed AI and recording disclosure. | |
voice | One of the 22 Dairo Live voice ids, e.g. marin (the default) or cedar. Any other value is rejected with 400. See Voices. | |
model | dairo-live, the one model every call runs on — you can leave it out. Any other value is rejected with 400. | |
language | ISO code of the language the agent speaks, e.g. de. Calls default to English; the disclosure follows this language, or the callee's country when it is unset. | |
maxDurationSeconds | Hard cap on call length, 30–780 seconds (default 600). Dairo ends the call at the cap. | |
voicemailMessage | Up to 500 characters. When a voicemail picks up, the agent leaves exactly this message and hangs up; unset, it hangs up silently. | |
variables | Values for {{name}} placeholders in instructions and greeting, filled in when the call is created. | |
metadata | Opaque key/value object, stored and echoed back on the call. | |
idempotencyKey | Also accepted as an Idempotency-Key header; when both are set they must match. |
from is not decoration. The caller id must be a number your account owns with status active — that rule is what keeps a key with phone:call from impersonating someone else's number. Pick a from your recipient's carrier will display: for German recipients that means a German local or national number, and Compliance explains why.
Fill in per-call values with variables
instructions and greeting support {{name}} placeholders, filled from variables when the call is created — the call object shows the filled-in text, exactly what the agent was told. A placeholder with no matching variable stays as written. Keep the brief as a stable template and inject the per-call facts:
Retry safely
Pass an Idempotency-Key header (or idempotencyKey in the body). A retried request with the same key returns the original call and never dials twice — with phones, a duplicate isn't a wasted API call, it's a human being rung a second time. Use a key derived from the reason for the call, such as an incident id or an invoice id; Retries & idempotency has the general contract.
Poll the call
Fetch the call until it reaches a terminal status: completed, failed, no_answer, busy, or canceled.
A finished call carries everything you need to reason about what happened — how long it ran, what it cost, and a one-paragraph summary of the conversation:
Dairo writes the summary from the transcript, in the language the conversation was held in. On a call that just ended, summary can be null for a moment — poll once more and it fills in.
List recent calls with GET /v1/phone/calls, filtered by status or to; limit is 1–100 and defaults to 50:
Get notified instead of polling
Subscribe a webhook to call.status_changed and Dairo tells you when a call is answered (status: "in_progress") and again when it reaches its terminal status — no polling loop required:
durationSeconds, hangupCause, and costUsd are null until the call has ended. The agent ends the conversation by itself when the person says goodbye, so most calls finish well before maxDurationSeconds.
Read the transcript
Every conversation produces a turn-by-turn transcript. Roles are agent (your AI), caller (the human who answered), and tool. A call that hasn't produced any conversation yet returns empty turns.
Fetch the recording
When a call has a recording, GET /v1/phone/calls/{id}/recording resolves it to a storage object you can download or share:
Every connected call is recorded. A call with no recording returns 404 — because it never connected, or the audio isn't available yet.
Hang up
End a live call early. Hanging up works at any point before a terminal status — a queued call is canceled before it ever dials, and a call that is already talking stops immediately.
The call settles as canceled. If it had connected, the time already spoken is still billed and transcribed. Hanging up a call that already reached a terminal status returns 409.
Phone calls
Give Dairo a number and plain-English instructions, and an AI agent dials, has the conversation, and reports back with a transcript. Your numbers answer incoming calls too.
Inbound calls
Let your Dairo number answer the phone: an AI agent picks up, takes notes, and drops every call into your inbox.