Prerequisites
- A published voice agent.
- A workspace API key with
sessions:write. - An outbound SIP trunk configured on the deployment. Without it, the dial step fails.
- The recipient’s number in E.164 format, e.g.
+919876543210.
Place the call
POST /calls fires one outbound call with an API key alone — no human, no login:
status: "queued". Accepting the call is asynchronous — it may be waiting for a calling window or a free concurrency slot before it dials. Add call_config to control retries, the calling window and idle timeouts; see Calls for the full contract.
Get the result
Poll the call until it reaches a terminal status, then read the session behind it:status progresses queued → dialing → in_progress → completed / failed / cancelled, and attempts lists one session per dial — transcript and usage hang off those. In production, register an outbound webhook and receive call_completed instead of polling.
Calling from the dashboard instead
POST /sessions with call_type: "outbound_phone" also dials a number, but it requires a bearer login session and a human user — it’s what the dashboard uses. Prefer POST /calls for anything server-to-server; it is the only path with retries, calling windows and idempotency.
On a phone session you don’t connect the returned
participant_token — the human is on the phone leg, so the token is subscribe-only.Notes & gotchas
- E.164 always — include the country code on every number.
- Stored numbers are masked in session metadata and logs (first char +
***+ last 4). - Dialing outcomes (busy, no-answer, declined) are classified from the SIP result — the same classification campaigns use to decide retries.
- Refused before it dials — a workspace with a negative balance gets
402 insufficient_credits, and where the deployment restricts destinations, a number outside the allowed prefixes gets400 invalid_request. Neither creates a call record. See the Calls error table.
Calls
The full
POST /calls contract.Run your first campaign
Dial many recipients with retries.

