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.
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 another number and connects it to the current call.

FieldValue
input.toRequired, binds. E.164 number, such as +12025550123.
input.timeout_secondsRequired, expr. Seconds to ring, 1 to 120.
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. An unconnected failure fails the run.

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.

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, voice.record_start, voice.record_stop, and logic.voice_goto with dependency_id for managed voicemail or call recording are in early access and are not documented here. Using them requires access for your workspace.

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": 1,
      "config": {},
      "input": { "to": "+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.