Place a call to any phone number over one of your SIP trunks with a single control-plane call. You supply the destination, a caller-id, and the trunk to route over. The engine dials the carrier. You get back a Call handle. Its sid addresses everything else: audio, transfer, hangup, telemetry.
Outbound originate is a control-plane operation. It returns as soon as the call is dialing, not when the callee answers. To read the outcome, poll calls.get (below), or consume call-lifecycle events.

Before you start

1

A configured SIP trunk

Outbound calls route over a trunk that you own. Create one and note its trunkId — see SIP trunking.
2

A caller-id that you are allowed to present

The from number must be one that the trunk (or your carrier) permits. The numbers that you allocated live in number provisioning.
3

An initialized Voice client

Place a call

Call calls.originate with the destination, caller-id, and trunk. The returned handle carries the sid. The sid is the only identifier that you need for everything that follows.
string
required
The E.164 destination number.
string
required
The caller-id, in E.164 form. The trunk must permit it.
string
required
The SIP trunk to route the call over.
string
The AI agent id to attach automatically on answer (see below).
number
The seconds to ring before the engine gives up. The server clamps the value to 5..120; the default is 30.

Attach an AI agent

Pass agent, and the engine wires the audio bridge for you the moment the callee answers. The agent starts talking with no AudioBridge code on your side. This one call is the whole outbound-AI path.
The agent id names a server-side agent that you configured: its speech-to-speech or ASR/LLM/TTS pipeline, prompt, and tools. Build one in the agent runtime. To attach an agent to a call that is already connected, or to hand a call between a bot and a person, see AI ↔ human handoff.
You can also own the media yourself: feed the caller’s audio to your own recognizer, and push your own synthesized audio back. To do this, omit agent and attach an audio bridge to the sid instead.

Cap the ring time

ringTimeoutSec bounds how long the callee’s phone rings before the engine abandons the call as no_answer. Pass a shorter value for tight retry loops. Pass a longer value for numbers that are slow to pick up. The engine clamps the value to 5..120 seconds. A value below 5 becomes 5. A value above 120 becomes 120. You never have to validate the value yourself.
ringTimeoutSec: 3 is accepted but behaves as 5. ringTimeoutSec: 240 behaves as 120. The clamp is silent. The value that you read back on the call can differ from the value that you sent.

Poll for the outcome

originate returns at dialing. To learn whether the call connected, fetch the call again. calls.get({ sid }) returns a fresh Call with the current status.
A call moves through these statuses: Poll until the call leaves the ringing states to get its terminal outcome:
Polling is fine for one-off calls. For fleets of calls, subscribe to call-lifecycle events instead of polling each sid. The engine pushes every transition (initiated, ringing, answered, cleared) as it happens.

Placing many calls

calls.originate places one call. For high-volume outbound — pacing thousands of numbers with a rate limit and a concurrency cap — use the control-plane bulk dialer. Do not loop originate yourself. The bulk dialer owns the pacing and back-pressure. See the PBX & ACD guide for campaign setup.

SIP trunking

Create and configure the trunks that outbound calls route over.

Number provisioning

Allocate the numbers that you present as caller-id.

Call lifecycle

The full event stream — a push alternative to polling status.

AI ↔ human handoff

Attach an agent mid-call, or hand a call between a bot and a person.