POST /v1/calls dials a phone number and connects whoever answers to an
agent — the dashboard’s test on phone, for your code. the bot is started
and the greeting synthesised while the phone rings, so the callee hears it the
moment they pick up.
request
string
required
the agent — its UUID or
ua_… handle. it must be deployed and use a
voice that can take calls (muga or mulberry). a draft answers
409 agent_not_deployed: a call never runs a configuration you did not
release.string
required
the number to dial, in E.164:
+ and 7–15 digits. spaces are tolerated.string
the caller id, as one of your own numbers: a SIP trunk’s
number, or a rented number that is active and connected
to this agent.
string
dial from this SIP trunk, by id. wins over
fromNumber.object
call behaviour for this one call. omit to
use the agent’s stored settings.
curl
response
returns202 Accepted as soon as the carrier takes the dial.
string
the call’s id — what
GET /v1/calls/{callId} and the dashboard’s
conversations show. store it to correlate the call with your own records.string
always
calling here. the call’s real state is on GET /v1/calls/{callId}.string
the agent’s UUID.
string
the number dialed, normalised.
string | null
the caller id the callee sees.
null when the platform’s shared number was
used.which number the call comes from
a rented number dials out only for the agent it is connected to. connect it
first with
POST /v1/phone-numbers/{id}/agent;
otherwise you get 409 number_not_connected. the dashboard does that step for
you; the api keeps it explicit so an inbound route is never moved as a side
effect of placing a call.
following the call
pollGET /v1/calls/{callId} — or list them all with GET /v1/calls.
curl
string
starting (dialing, bot launching) → running (answered) → completed.
failed if it never connected or errored; expired if no end signal ever
arrived (never charged).string
phone for calls placed here and for inbound calls on your numbers; web
for web calls; realtime for the realtime socket.object[] | null
every turn, once the call has ended.
offsetSeconds is where the turn starts
in the recording.string | null
a signed URL valid for a few minutes. fetch it when you need it; do not
store it.
string | null
customer_ended, never_connected, … — why the call ended.call history
GET /v1/calls lists every billed call on the account, newest first, in the
same shape. page with limit (1–100, default 25) and before = the last id
you have; nextCursor is null on the last page. each call names the agent
that ran it in agentSlug, so filter on that for one agent’s history.
billing and limits
a phone call is billed like a web call — per second on pay-as-you-go, on a slot on a concurrency plan — plus the carrier’s per-minute cost when it goes out over a rented number. it takes one concurrent slot for its whole duration (limits), and each account has a daily cap on outbound calls (429 agent_phone_daily_limit).
errors
404 agent_not_found · number_not_found · sip_trunk_not_found
404 agent_not_found · number_not_found · sip_trunk_not_found
no such agent, or
fromNumber / fromTrunkId is not one of your numbers.409 agent_not_deployed
409 agent_not_deployed
the agent was saved but never deployed, so no version is live to run the
call. deploy it with
POST /v1/agents/{agent_ref}/deploy; nothing is
started or billed until you do.409 number_not_connected · number_not_active
409 number_not_connected · number_not_active
the rented number in
fromNumber is not connected to this agent, or its
rental is not active.422 agent_phone_model_unsupported
422 agent_phone_model_unsupported
the agent’s voice engine cannot take phone calls. switch it to
muga or
mulberry.402 insufficient_balance
402 insufficient_balance
the account cannot fund a usable call. top up, or enable auto top-up.
429 concurrency_limit_exceeded · agent_phone_daily_limit
429 concurrency_limit_exceeded · agent_phone_daily_limit
every concurrent slot is busy, or today’s outbound cap is reached.
502 agent_session_failed
502 agent_session_failed
the carrier could not place the call. nothing was charged; retry.