Each IVR action is a class extending BaseAction from automation/abstracts. They share the same execution shape: validate(config) → execute(context) → ActionResult — result.data.twiml is the rendered TwiML, result.nextStepId advances the flow (or stays null while the action waits for caller input).
Source folder: appengine/src/automation/actions/ivr/.
ivr_speak
Reads a text-to-speech message to the caller.
{
"actionType": "ivr_speak",
"config": {
"message": "Hello {{caller}}, welcome to Acme.",
"voice": "Polly.Joanna-Neural",
"language": "en-US",
"nextStepId": "menu"
}
}
| Field | Type | Description |
|---|---|---|
| message* | string | TTS text. Max 4096 characters. Supports |
| voice | string | Twilio voice id. Defaults to |
| language | string | BCP-47 tag. Defaults to |
| nextStepId | string | Step to run next. If omitted, the call ends after the message. |
ivr_collect_input
Gathers DTMF digits or speech.
{
"actionType": "ivr_collect_input",
"config": {
"prompt": "Please enter your 5-digit account number.",
"inputType": "dtmf",
"numDigits": 5,
"timeout": 8,
"saveAs": "accountNumber",
"nextStepId": "lookup",
"onTimeout": "voicemail"
}
}
| Field | Type | Description |
|---|---|---|
| prompt* | string | What the caller hears before the prompt opens. |
| inputType | string |
|
| numDigits* | number | Required for |
| timeout | number | Seconds to wait before triggering |
| saveAs* | string | Variable name for the captured value. |
| nextStepId | string | Step to run after capture. |
| onTimeout | string | Step to run on timeout. If omitted, the call ends. |
ivr_menu
Plays a menu and routes by digit.
{
"actionType": "ivr_menu",
"config": {
"greeting": "For sales press 1, for support press 2.",
"saveAs": "selection",
"options": [
{ "digit": "1", "label": "sales", "nextStepId": "sales" },
{ "digit": "2", "label": "support", "nextStepId": "support" }
],
"timeout": 5,
"onTimeout": "voicemail"
}
}
| Field | Type | Description |
|---|---|---|
| greeting* | string | Menu prompt. Each option's |
| options* | array | At least one option. Each: |
| saveAs* | string | Variable that captures the chosen digit. |
| timeout | number | Seconds. Default 5. |
| onTimeout | string | Step to run on timeout. |
ivr_transfer
Hand off to a phone, agent, or queue.
{
"actionType": "ivr_transfer",
"config": {
"transferType": "phone",
"to": "+14155550100",
"record": true,
"announcement": "Connecting you now."
}
}
| Field | Type | Description |
|---|---|---|
| to* | string | Destination — phone number, queue name, or agent client identity. |
| transferType | string |
|
| agentIdentity | string | Required when |
| queueName | string | Used with |
| record | boolean | Record the call leg. Defaults to |
| announcement | string | Played to the caller before the dial. |
Transfer ends the flow — nextStepId is ignored.
ivr_forward
Ring multiple targets. More flexible than ivr_transfer for ring groups.
| Field | Type | Description |
|---|---|---|
| targets* | array | List of |
| ringMode | string |
|
| ringDuration | number | Seconds per attempt. Default 20. |
| callerId | string | Override the caller ID shown to ringing devices. |
| whisperEnabled | boolean | Play whisperMessage to the answering target before bridging. |
| screeningEnabled | boolean | Require keypress to accept the call. |
| greeting | string | Played to the caller before ringing starts. |
| fallback | string | voicemail | ai-assistant | automation | hangup. Used when no one answers. |
ivr_record
Records a single chunk of caller audio.
| Field | Type | Description |
|---|---|---|
| saveAs* | string | Variable for the recording URL. |
| prompt | string | Played before recording starts. |
| maxLength | number | Seconds. Default 120. |
| transcribe | boolean | Default true. |
| finishOnKey | string | DTMF that ends recording. Default #. |
| nextStepId | string | Step to run after recording. |
| onTimeout | string | Step to run if no audio captured. |
Result variables: {saveAs} (URL), {saveAs}_duration, {saveAs}_transcription if transcribed.
ivr_voicemail
Recording with greeting, transcription, and notifications baked in.
| Field | Type | Description |
|---|---|---|
| greeting | string | Voicemail greeting. Has a default. |
| maxLength | number | Seconds. Default 120, max 600. |
| transcribe | boolean | Default true. |
| playBeep | boolean | Default true. |
| timeout | number | Silence timeout to stop recording. Default 10. |
| finishOnKey | string | Default #. |
| notifyEmail | string | Email to notify with the message + transcript. |
| notifyPhone | string | Phone to notify via SMS. |
| nextStepId | string | Optional step after the recording webhook returns. |
Stored in S3, linked to a voicemail (or call_log) record. Notifications go through Broadcast.
ivr_play_audio
Plays an audio file URL.
| Field | Type | Description |
|---|---|---|
| url* | string | Direct URL to MP3 / WAV. |
| loop | number | Times to repeat. Default 1. |
| nextStepId | string | Step to run after playback. |
ivr_send_sms
Sends an SMS during the call. Doesn't pause the call leg.
| Field | Type | Description |
|---|---|---|
| message* | string | SMS body. Max 1600 chars. |
| to | string | Defaults to {{caller}}. |
| from | string | Defaults to {{calledNumber}}. |
| announce | boolean | Speak announceMessage first. |
| announceMessage | string | Default: "We are sending you a text message with more information." |
| nextStepId | string | Step to run after the SMS is queued. |
ivr_send_email
Sends an email during the call. Goes through the org's email provider via the Broadcast module.
| Field | Type | Description |
|---|---|---|
| to* | string | Recipient. |
| subject* | string | Subject. |
| body | string | HTML body. Required if template not set. |
| template | string | Template id. Required if body not set. |
| from | string | Override sender. Defaults to org default. |
| nextStepId | string | Step to run after queue. |
ivr_ai_assistant
Hands the call to the voice assistant via <Stream>.
{
"actionType": "ivr_ai_assistant",
"config": {
"assistantId": "assistant-abc",
"greeting": "Hi! I'm Acme's virtual assistant. How can I help?",
"handoffMessage": "Connecting you to our assistant.",
"context": "Caller is a high-priority customer. Reference: ABC-12.",
"fallbackStepId": "voicemail"
}
}
| Field | Type | Description |
|---|---|---|
| assistantId* | string | The ai_assistant record id. |
| greeting | string | First line the AI says (overrides onboardingPrompt). |
| handoffMessage | string | Played to the caller before the WebSocket opens. |
| context | string | Free-text appended to the assistant's system prompt. |
| phoneConfigId | string | Phone routing record id, used to load IVR context for the AI. |
| fallbackStepId | string | Step to run if the WebSocket fails to open. |
| fallbackMessage | string | Spoken before hangup if no fallback step. |
The action's TwiML opens <Connect><Stream url="wss://.../simple-voice/stream/{orgId}/{assistantId}?caller=..."> — see Voice streaming.
ivr_twilio_pay
PCI-compliant payment via Twilio Pay.
| Field | Type | Description |
|---|---|---|
| amount* | string|number | Charge amount. |
| currency* | string | ISO currency code. |
| paymentConnector* | string | Pay connector name configured in Twilio (Stripe, Braintree, etc.). |
| description | string | Charge description. Default Payment. |
| saveAs | string | Variable for result. Default paymentResult. |
| prompt | boolean | Play default Twilio Pay prompts. |
| onFailure | string | Step to run if payment fails or is cancelled. |
| nextStepId | string | Step to run on success. |
Result variables: {saveAs} (full result), {saveAs}_confirmation (confirmation code), {saveAs}_error.
ivr_hangup
Ends the call.
| Field | Type | Description |
|---|---|---|
| message | string | Optional last message before hanging up. |
No nextStepId — terminal.