Skip to content

dial

Requires webhook version 2026-06-01

The dial verb originates an outbound leg from an in-progress Voice App call and bridges it. Use it when the flow needs to reach a human (a sales rep, on-call engineer, or IVR downstream) after the caller lands.

{
"action": "dial",
"to": "+14155550123"
}

Returned from your flow_url when the caller is on the line. Teler originates a leg to +14155550123, waits up to 30 seconds for pickup, then bridges the two legs into a two-way call.

{
"action": "dial",
"to": "+14155550123",
"timeout": 30,
"record": "stereo",
"custom_headers": { "X-Reason": "escalation" },
"status_callback_url": "https://example.com/webhook",
"ringback": "passthrough",
"dial_music": { /* nested action */ },
"confirm_sound": { /* nested action */ },
"on_no_answer": { /* nested action */ },
"on_busy": { /* nested action */ },
"on_failure": { /* nested action */ }
}
FieldTypeRequiredDefaultNotes
actionstringyesnoneMust be "dial".
tostringyesnoneE.164 phone number or SIP URI (sip:user@host). Single target only.
timeoutinteger (seconds)no301..600. Time to wait for pickup before treating as no-answer.
recordmixednofalseSee Recording modes.
custom_headersobjectno{}Extra SIP headers on the outbound INVITE. Keys must start with X-. Max 16 headers, values ≤ 256 bytes.
status_callback_urlstringnoVoice App’s webhook_urlOverride where lifecycle events for this dial land.
ringbackenumnopassthroughpassthrough = the caller hears the target’s ring; suppress = silence until bridge. Use with dial_music to play hold audio instead.
dial_musicnested actionnononePlays to the caller while the target rings. See Nested actions.
confirm_soundnested actionnononePlays to the target immediately after they pick up, before the bridge. Useful for “press 1 to accept this call” patterns.
on_no_answernested actionnononeRuns on the caller’s leg if the target doesn’t answer within timeout.
on_busynested actionnononeRuns if the target rejected with busy (486).
on_failurenested actionnononeRuns on any other failure (network, 404, 503, unreachable, etc.).

record accepts:

ValueWhat gets recorded
false (default)Nothing.
true | "stereo"Both legs into a single stereo file. Caller on left, target on right.
"mono"Both legs mixed into a single mono file.
"per_leg"Two separate mono files, one per leg. Each leg has its own recording.

Recording requires the account-level recording flag to be enabled. If it isn’t, the field is silently ignored and no recording is produced.

Recording lifecycle events (recording.completed / recording.failed) land on the same webhook_url as the rest of the call.

dial_music, confirm_sound, on_no_answer, on_busy, and on_failure accept a single nested action: the same JSON shape as a top-level flow response, one level deep. Nesting is bounded to a depth of 10.

Supported nested actions today: play and hangup. (say is defined in the schema but not yet implemented at runtime.)

{
"action": "dial",
"to": "+14155550123",
"dial_music": {
"action": "play",
"media_url": "https://cdn.example.com/hold.mp3",
"loop": true
},
"on_busy": {
"action": "hangup"
}
}
Target statusBridge attemptFallback runs?Events fired
AnswersBridgednoneleg.created, leg.answered on the target leg
No answer within timeoutNoon_no_answerleg.created, leg.completed (reason: "no_answer")
Busy (SIP 486)Noon_busyleg.created, leg.completed (busy)
Rejected / any other failureNoon_failureleg.created, leg.completed (rejected | unreachable | …)
Caller hangs up firstCancellednoneleg.completed (canceled)

If no fallback is provided for an outcome, the caller’s leg proceeds to the next action in the flow (or ends if the dial was the last action).

The full set of leg reason values is normal, no_answer, busy, canceled, unreachable, rejected, flow_error, system_failure.

custom_headers lets you pass call metadata through to a SIP-terminated destination. Rules:

  • Keys must begin with X-. A non-conforming key is rejected with a validation error and the whole request fails.
  • Maximum 16 headers.
  • Each value ≤ 256 bytes.
{
"action": "dial",
"to": "sip:agent@pbx.example.com",
"custom_headers": {
"X-Ticket-Id": "12345",
"X-Priority": "high"
}
}

dial emits per-leg lifecycle events on the target leg, alongside the usual call-level events on the primary leg. All require the owning Voice App to be on 2026-06-01.

Every event carries the target leg’s leg_id on the envelope. See Call events for the full schemas.

Dial with hold music and no-answer fallback

Section titled “Dial with hold music and no-answer fallback”
{
"action": "dial",
"to": "+14155550123",
"timeout": 25,
"dial_music": {
"action": "play",
"media_url": "https://cdn.example.com/hold.mp3",
"loop": true
},
"on_no_answer": {
"action": "hangup"
}
}
{
"action": "dial",
"to": "+14155550123",
"confirm_sound": {
"action": "play",
"media_url": "https://cdn.example.com/press-one-to-accept.mp3"
},
"dial_music": {
"action": "play",
"media_url": "https://cdn.example.com/hold-music.mp3",
"loop": true
}
}

The following are reserved in the schema but not shipped today:

  • Multiple targets (array on to). Coming in a follow-up release as to: [...] with race-to-answer semantics.
  • machine_detection. Reserved; will detect voicemail vs live human when it ships.
  • SIP + PSTN mixing in a single to array.