Advanced FeatureTriggers send the same data messages a client can. Make sure you’re comfortable with Data Messages
before diving in, and with Threads if your triggers work with them.
When to Use Triggers
Keeping Track of Time → Tell the agent how long the call has lasted, so it can pace the conversation and wrap up in time. Returning Thread Results → When a background thread finishes its work, send its result to the thread that spawned it. Reacting to What’s Said → Watch transcripts and spawn a thread or send a message when a condition is met.Defining a Trigger
These two triggers tell the agent how long the call has lasted every 5 minutes, and ask it to start wrapping up after 15. The first starts a timer when the call starts. The second runs each time the timer fires: it counts the minutes in a local variable, restarts the timer, and sends the agent a deferred instruction.name→ Identifies the trigger in call events and intriggerOverrides. Names are 1-64 letters, digits, or underscores, unique among the call’s triggers.event→ What causes the trigger to run. See Events.condition→ Optional. Filters events, so the actions only run when it’s met. See Conditions.actions→ What the trigger does, in order. See Actions.localVariables→ Optional. Variables only this trigger can read and write, with their initial values. See Local Variables.
How Triggers Run
Triggers run shortly after their events, in the order the events occur. Their actions may interleave with other activity in the call, so don’t rely on a trigger’s message arriving before or after any other particular message. When several triggers run for the same event, they run one after another in the call’s trigger order. For a call created directly, that’s the order of itstriggers. For a call created with an agent, it’s the agent’s remaining triggers, then any
added with triggerOverrides. List Call Triggers
shows a call’s order.
A trigger’s local variables and the call’s timers last for the rest of the call. Triggers stop running when the call ends.
Events
A trigger’sevent sets either dataMessage or timer.
Data Messages
dataMessage is the type of a server-to-client data message, as in the
message’s type field (for example user_started_speaking, not userStartedSpeaking). The trigger runs each time the server
produces a message of that type, whether or not any client receives it, so there’s no need to enable a message for your triggers.
The event’s properties are the message’s fields, such as event.role and event.final for a transcript
or event.state for a state message.
Timers
timer is the name of a timer, which runs the trigger each time it fires. Timer names are 1-64 letters, digits, or underscores.
Only one trigger may listen for each timer, but any trigger can start or cancel it.
A timer event’s only property is forwardedEvent: the event of the trigger run that started the timer. If that run was itself for a
timer, it’s that timer’s forwardedEvent instead, so a timer that restarts itself keeps forwarding the event that started the chain.
Timers don’t start on their own. To start one when the call starts, use a separate trigger for the call_started message, as in
the example above.
Conditions
A condition is either simple or complex. A simple condition compares aproperty to a value:
conditions:
Operators
If a comparison like
OPERATOR_LT finds a property that isn’t a number, that run of the trigger stops. See
Errors.
Properties
A property is a dotted path in one of three scopes:event→ The event’s properties, such asevent.textorevent.metadata.role.local→ The trigger’s local variables, such aslocal.minutes.global→ State the call has reported so far:global.callState→ Thestateof the call’s lateststatemessage, or null before the first.global.threadState→ Thestateof a thread’s latestthread_statemessage, or null if the thread hasn’t reported one or has terminated. Takes athreadIdargument inpropertyArguments.
propertyArguments are templates, so they can refer to the event or local variables:
Actions
A trigger has at least one action. Its actions run in order.Sending Data Messages
dataMessage sends a data message into the call. Triggers can send these message types:
The message is handled as if your server had sent it to the call, so it can target a thread with threadId (or
parentThreadId for spawn_thread). String values in the message are templates; its type can’t be templated.
Ternaries
ternary runs one list of actions or the other depending on a condition. At least one of whenTrue and whenFalse
must have actions.
Local Variables
A trigger declares its local variables inlocalVariables, by name, with their initial values. Names are letters, digits, or
underscores, and may not start with a digit. Each variable keeps the type of its initial value, which must be a string, number, or
boolean. Values persist across the trigger’s runs for the rest of the call. Only the trigger that declares a variable can read or
change it.
setLocalVariable→ Sets a variable to a value of its type. String values are templates.incrementLocalVariable→ Addsvalue(1 by default, and possibly negative) to a number variable.
setLocalVariable renders a longer string, it’s truncated, and a
trigger.truncated call event is recorded.
Starting and Canceling Timers
startTimer→ Starts the timer calledname, firing afterdelay(at least"10s"). Starting a timer that’s already running restarts it. Starting a timer that no trigger listens for does nothing.cancelTimer→ Stops the timer callednamefrom firing. Does nothing if it isn’t running.
Templates
Templated strings use Mustache syntax and are rendered against the event and the trigger’s local variables, for example{{event.text}} or {{local.minutes}}. They aren’t HTML-escaped. Sections such as
{{#event.metadata}}...{{/event.metadata}} work as usual, but partials aren’t supported, and a template can only refer to local
variables the trigger declares.
Using Triggers
In Calls
Settriggers when creating a call. Each entry selects one trigger, as one of:
temporaryTrigger→ A trigger defined only for this call.triggerId→ The ID of a global trigger.triggerName→ The name of a global trigger.
In Agents
Settriggers in an agent’s callTemplate to give every call to the agent the same triggers. Updating the agent’s callTemplate
replaces its triggers.
Overriding an Agent’s Triggers
When creating a call with an agent,triggerOverrides changes the agent’s triggers for
that call:
remove→ Names of the agent’s triggers to remove.removeAll→ If true, removes all of the agent’s triggers. May not be set together withremove.add→ Triggers to add, selected as intriggers.
Listing a Call’s Triggers
List Call Triggers returns a call’s triggers, in order, as they were when the call was created. Each one’striggerId is the ID of the global trigger it was selected from, or null if it was defined in the call or
agent itself.
Global Triggers
Global triggers are defined once and selected by many calls and agents. Create one with the Triggers API:triggerId or triggerName. A trigger’s name is unique among your account’s triggers.
- Calls use the trigger as it is when the call is created. Later changes to it don’t affect the call.
- Agents use its latest version. Updating a global trigger updates the agents that use it. If the change would make any agent’s triggers invalid, for example by giving it the name of another of that agent’s triggers, the update fails with a 409 and nothing changes.
- Deleting a global trigger fails with a 409 while any agent uses it.
Public Triggers
Your account can also see and select public triggers, whoseownership is public. They can’t be updated or deleted. When
selecting by name, your account’s own trigger takes precedence over a public one with the same name.
Limits
Errors
Ultravox checks triggers when you create a call, an agent, or a global trigger, and responds with a 400 describing each problem, labeled with the trigger’s name (for exampleTrigger 'clock': A trigger must have at least one action.).
Some problems only show up while the call runs. These are recorded as call events:
trigger.failed→ A condition couldn’t be evaluated, for example becauseOPERATOR_GTfound a property that wasn’t a number. That run of the trigger stops. A trigger that fails three runs in a row is dropped for the rest of the call.trigger.action_failed→ An action failed, for example because its data message was invalid once rendered. The trigger’s other actions still run.trigger.truncated→ A local variable’s string was truncated to 32,768 characters.trigger.invalid→ A trigger was dropped when the call started, for example because a field in its data message was invalid.
trigger_name extra names the trigger.
Examples
Returning a thread’s result to its parent
To have a thread send its result to its parent each time it finishes its work, select the publicthreadsReportToParentOnIdle trigger:
reportToParent in its metadata. Threads spawned
without it don’t report back:
soon urgency, wrapped as
<thread_result threadId="…">…</thread_result>.
To change when threads report back or what they send, define your own trigger. Here, a thread spawned with
"metadata": { "role": "delegate" } reports its result back to the thread that spawned it the first time it finishes its work:
Next Steps
Data Messages Reference
The messages triggers can listen for and send.
Threads
Run parallel conversations that triggers can start and follow.