Sign inGet Started

Voice sequence node reference

Warning: Voice sequences are in preview. Steps, entry data, and the sequence definition format can change in ways that break existing sequences and API requests.

Use this reference to write the sequence.definition you send with Create Call. Bird runs an inline definition once and does not save it. To keep a sequence, build it in the dashboard editor.

Definition

FieldValue
schema_version1.
expression_environment"bird.cel.v1".
nodesArray of node objects. Array order has no effect on execution.
settingsOmit it or send {}. A non-empty object fails with unsupported_contract; a value that is not an object fails with invalid_envelope.
presentationOptional editor layout and labels. It does not affect execution but counts toward size limits.

Each node has these fields:

FieldValue
idUnique in the definition. Starts with a lowercase letter, then lowercase letters, digits, or _, up to 64 characters.
typeA node type from this page, such as voice.say.
type_version1 for every node type on this page, except 2 for voice.dial.
configSetup that fixes the node's shape, such as declared outcomes. Use {} when the node has none.
inputValues the node uses when it runs. Use {} when the node has none.
connectionsMap from an outcome name to { "node_id": "<target>", "port": "input" }.

Connections must not form a loop, and every node must be reachable from an entry. An outcome left out of connections is unconnected. Unconnected outcomes end the run normally, except where a node says otherwise.

Values and expressions

Most fields take literal JSON. Fields marked binds also accept $expr or $template; fields marked expr also accept $expr only:

  • {"$expr": "trigger.data.customer_name"} returns a typed value.
  • {"$template": ["Hello ", {"$expr": "trigger.data.customer_name"}, "."]} returns text. Templates are arrays; {{name}} stays literal text.

Expressions use CEL and can read these values:

ValueContents
trigger.dataThe entry data, matching the entry's data_schema.
trigger.node_idThe ID of the entry that started this visit.
trigger.typeThe type of the entry that started this visit, such as trigger.start_call.
steps.<id>.outputOutput of an earlier completed node in this visit.
variables.<key>Values saved by a data.set node in this visit.
execution.id, execution.started_atThe run ID and its start time. Use string(execution.started_at) in speech.
execution.callThe call's id, session_id, and original parties orig and dest, each of which can be null.

Guard optional values before reading them, for example has(trigger.data.name) ? trigger.data.name : 'caller'. The has macro is available; map, filter, all, exists, and exists_one are not.

Entry

trigger.start_call

Where a call starts. entry_node_id in the Create Call request names this node.

FieldValue
config.data_schemaOptional JSON Schema (draft 2020-12) object schema for trigger_data. Only local $ref is supported. Without it, the entry accepts only {}.
Outcomeevent.

Entry data is limited to 16 KiB.

Speech and audio

voice.say

FieldValue
input.textRequired, binds. Text to speak, at most 160 bytes.
input.languageRequired. Speech language code, such as en.
Outcomenext.

voice.play

FieldValue
input.asset_idRequired. ID of an audio asset available in this workspace. An unavailable asset can fail the call when the step runs.
Outcomenext.

voice.tone

FieldValue
input.frequency_hzRequired. 100 to 3000.
input.duration_msRequired. 1 to 10000.
Outcomenext.

logic.pause

Waits with the call connected.

FieldValue
input.duration_msRequired. 1 to 60000.
Outcomenext.

Keypad input

voice.gather

Plays prompts, which a key press interrupts, and collects keypad digits.

FieldValue
input.promptsRequired. Up to 4 prompts. Each is {"type": "say", "text", "language"}, {"type": "play", "asset_id"}, {"type": "tone", "frequency_hz", "duration_ms"}, or {"type": "pause", "duration_ms"}, with the same limits as the matching node. Tone and pause durations together are at most 60000 ms. Prompt text binds.
input.max_digitsRequired. 1 to 32.
input.timeout_secondsRequired. Seconds to wait for the first key, 1 to 10.
input.inter_digit_timeout_secondsRequired. Seconds to wait between keys, 1 to 5.
input.finish_on_keyRequired. One of 0–9, *, #, A–D that ends input, or null.
input.matchesRequired. Map from an outcome name to the exact digits that select it, such as {"hours": "1"}. Names and digits must be unique. A name cannot be input, timeout, or fallback. Digits are at most max_digits long and cannot contain finish_on_key.
input.privateOptional, default false. When true, later steps cannot read the digits, and they are left out of the trace.
OutcomesEach name in matches, timeout when no key is pressed, and fallback for any other input.
Outputdigits and reason: initial_timeout, max_digits, finish_key, or inter_digit_timeout.

Logic and data

logic.branch

Checks conditions in order and follows the first that is true.

FieldValue
config.casesRequired. At least one {"port": "<name>", "when": {"$expr": "<boolean>"}}.
config.default_portRequired. Outcome name when no case is true.
OutcomesEach port in cases, and default_port.
Outputbranch: the selected outcome name.

data.set

Saves values for later steps in the same visit.

FieldValue
inputObject of values, each of which binds. Each key becomes variables.<key>. Every value is computed from the variables as they were before this node.
Outcomenext.
OutputThe saved object.

Calls and transfers

voice.dial

Calls a phone number, or a number on one of your workspace's inbound SIP trunks, and connects it to the current call. Use type_version 2.

FieldValue
input.typeRequired. pstn to call a phone number, or sip_trunk to call a number through one of your inbound SIP trunks.
input.pstnRequired when type is pstn, and omitted otherwise. Object with dest and optional orig.
input.sip_trunkRequired when type is sip_trunk, and omitted otherwise. Object with trunk_id, dest, and optional orig.
trunk_idRequired in sip_trunk. ID of an inbound SIP trunk in your workspace, such as spt_01jzj6c0p4f8b3x2m9k7q5r1tw. Literal value only.
destRequired, binds. For pstn, the E.164 number to call, such as +12025550123. For sip_trunk, a number, extension or name, such as 1001: 1 to 64 letters, digits and +*._-. The trunk's inbound routing delivers the call as if it arrived for this value.
origOptional, binds. Caller ID to present. Omit it to present the current call's own number. For pstn, it must be an E.164 number your workspace can use as caller ID. For sip_trunk, it takes the same values as dest, such as sales.
input.timeout_secondsRequired, expr. Seconds to wait for an answer, including failover between trunk gateways, 1 to 120. Unanswered calls take no_answer; an answered call is not limited.
Outcomessuccess, busy, no_answer, and failure. success follows after the connected call ends and the original call's audio is restored, not when the destination answers. A SIP trunk that rejects or forwards the call selects failure. An unconnected failure fails the run.

Version 1 takes the number in input.to and has no orig. Steps that use it keep running. When you upgrade a version 1 step in the editor, its to value moves to pstn.dest.

logic.voice_goto

Starts another entry in the same definition. The new visit gets fresh trigger.data and clears earlier step outputs and variables; the call continues.

FieldValue
input.entry_node_idRequired. ID of a trigger.start_call node in this definition.
input.dataOptional, expr, default {}. Entry data for that node's schema.
OutcomesNone.

Automations

automation.send_event

Sends an application event to an Automation without waiting for a run. The call continues once the event is queued; whether a run starts is visible only in Automations.

FieldValue
input.automation_idRequired. ID of an automation in this workspace.
input.eventRequired. The automation's event name: 1 to 128 letters, digits, dots, underscores, or hyphens.
input.dataOptional, default {}. The event's entire data. Its top-level values bind, or the whole object can be one $expr. Values nested deeper stay literal. The whole input is at most 16 KiB.
Outcomessuccess once the event is queued, or failure if it cannot be. Neither reports the automation's run. An unconnected failure fails the run.

Ending the call

logic.exit

Ends the call with a result.

FieldValue
config.statusRequired. succeeded or failed.
config.reasonOptional, expr. Stable code of lowercase letters, digits, and _, starting with a letter or digit, up to 64 characters. Omit it rather than sending null.
input.outputRequired object, which can be {}. Its top-level values bind.
OutcomesNone.

voice.hangup

Ends the call without an authored result. It has no fields and no outcomes.

Early access steps

voice.webhook is in early access and is not documented here. Using it requires access for your workspace. voice.record_start, voice.record_stop, and logic.voice_goto with dependency_id for managed voicemail or call recording are not documented here either.

Example: transfer to a person

This definition greets the recipient, dials a support number, and records whether the transfer connected:

Code example
{
  "schema_version": 1,
  "expression_environment": "bird.cel.v1",
  "nodes": [
    {
      "id": "start",
      "type": "trigger.start_call",
      "type_version": 1,
      "config": {},
      "input": {},
      "connections": { "event": { "node_id": "greeting", "port": "input" } }
    },
    {
      "id": "greeting",
      "type": "voice.say",
      "type_version": 1,
      "config": {},
      "input": { "text": "Connecting you to our support team.", "language": "en" },
      "connections": { "next": { "node_id": "support", "port": "input" } }
    },
    {
      "id": "support",
      "type": "voice.dial",
      "type_version": 2,
      "config": {},
      "input": { "type": "pstn", "pstn": { "dest": "+12025550123" }, "timeout_seconds": 30 },
      "connections": {
        "success": { "node_id": "connected", "port": "input" },
        "busy": { "node_id": "unavailable", "port": "input" },
        "no_answer": { "node_id": "unavailable", "port": "input" },
        "failure": { "node_id": "unavailable", "port": "input" }
      }
    },
    {
      "id": "connected",
      "type": "logic.exit",
      "type_version": 1,
      "config": { "status": "succeeded", "reason": "transferred" },
      "input": { "output": {} }
    },
    {
      "id": "unavailable",
      "type": "logic.exit",
      "type_version": 1,
      "config": { "status": "failed", "reason": "support_unavailable" },
      "input": { "output": {} }
    }
  ]
}

Send it as sequence.definition with "entry_node_id": "start" and "trigger_data": {}.

Continue with the documentation, guides and examples for this topic.