> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ultravox.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Triggers

> Send data messages into a call automatically when something happens in it.

Triggers are rules that run inside a call. When an event occurs, such as a [data message](https://docs.ultravox.ai/apps/datamessages.md) from the server or a
timer firing, each trigger listening for it checks its condition and, if the condition is met, runs its actions. Actions can send
data messages into the call, update the trigger's own variables, and start or cancel timers.

Because triggers run on Ultravox's servers, they react to the call without a client or data connection having to watch for
events and respond.

> [!NOTE]
>
> **Advanced Feature**
>
> Triggers send the same data messages a client can. **Make sure you're comfortable with [Data Messages](https://docs.ultravox.ai/apps/datamessages.md)
> before diving in**, and with [Threads](https://docs.ultravox.ai/agents/threads.md) 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](https://docs.ultravox.ai/agents/guiding-agents.md#deferred-messages).

```js theme={null}
{
  "triggers": [
    {
      "temporaryTrigger": {
        "name": "start_clock",
        "event": { "dataMessage": "call_started" },
        "actions": [{ "startTimer": { "name": "clock", "delay": "300s" } }]
      }
    },
    {
      "temporaryTrigger": {
        "name": "clock",
        "event": { "timer": "clock" },
        "localVariables": { "minutes": 0 },
        "actions": [
          { "incrementLocalVariable": { "name": "minutes", "value": 5 } },
          { "startTimer": { "name": "clock", "delay": "300s" } },
          {
            "ternary": {
              "condition": { "property": "local.minutes", "operator": "OPERATOR_GTE", "value": 15 },
              "whenTrue": [
                {
                  "dataMessage": {
                    "type": "user_text_message",
                    "text": "<instruction>The call has lasted {{local.minutes}} minutes. Start wrapping up.</instruction>",
                    "urgency": "later"
                  }
                }
              ],
              "whenFalse": [
                {
                  "dataMessage": {
                    "type": "user_text_message",
                    "text": "<instruction>The call has lasted {{local.minutes}} minutes.</instruction>",
                    "urgency": "later"
                  }
                }
              ]
            }
          }
        ]
      }
    }
  ]
}
```

Each trigger has:

* **`name`** → Identifies the trigger in call events and in [`triggerOverrides`](#overriding-an-agents-triggers). Names are 1-64
  letters, digits, or underscores, unique among the call's triggers.
* **`event`** → What causes the trigger to run. See [Events](#events).
* **`condition`** → Optional. Filters events, so the actions only run when it's met. See [Conditions](#conditions).
* **`actions`** → What the trigger does, in order. See [Actions](#actions).
* **`localVariables`** → Optional. Variables only this trigger can read and write, with their initial values. See
  [Local Variables](#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 its `triggers`. For a call created with an agent, it's the agent's remaining triggers, then any
added with [`triggerOverrides`](#overriding-an-agents-triggers). [List Call Triggers](https://docs.ultravox.ai/api-reference/calls/calls-triggers-list.md)
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's `event` sets either `dataMessage` or `timer`.

### Data Messages

`dataMessage` is the type of a [server-to-client data message](https://docs.ultravox.ai/apps/datamessages.md#server-to-client-messages), 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`](https://docs.ultravox.ai/apps/datamessages#transcript)
or `event.state` for a [`state`](https://docs.ultravox.ai/apps/datamessages#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](#starting-and-canceling-timers).

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](#defining-a-trigger).

## Conditions

A condition is either simple or complex.

A **simple condition** compares a `property` to a `value`:

```js theme={null}
{ "property": "event.role", "operator": "OPERATOR_EQ", "value": "user" }
```

A **complex condition** combines child `conditions`:

```js theme={null}
{
  "operator": "OPERATOR_AND",
  "conditions": [
    { "property": "event.role", "operator": "OPERATOR_EQ", "value": "user" },
    { "property": "event.final", "operator": "OPERATOR_EQ", "value": true }
  ]
}
```

### Operators

| Operator | Kind | Met when |
| - | - | - |
| `OPERATOR_EQ` | Simple | The property equals the value. Values of different types are never equal (for example `true` and `1`). A `null` value matches a null or missing property. |
| `OPERATOR_NEQ` | Simple | The property doesn't equal the value. |
| `OPERATOR_LT`, `OPERATOR_LTE`, `OPERATOR_GT`, `OPERATOR_GTE` | Simple | The property is less than, at most, greater than, or at least the value. The value must be a number. |
| `OPERATOR_AND` | Complex | Every child is met. Children are evaluated in order, stopping at the first that isn't met, so earlier children can guard later ones (for example by checking a property isn't null before comparing it to a number). |
| `OPERATOR_OR` | Complex | At least one child is met. Children are evaluated in order, stopping at the first that is met. |
| `OPERATOR_XOR` | Complex | Exactly one child is met. Every child is evaluated. |

If a comparison like `OPERATOR_LT` finds a property that isn't a number, that run of the trigger stops. See
[Errors](#errors).

### Properties

A property is a dotted path in one of three scopes:

* **`event`** → The event's properties, such as `event.text` or `event.metadata.role`.
* **`local`** → The trigger's [local variables](#local-variables), such as `local.minutes`.
* **`global`** → State the call has reported so far:
  * `global.callState` → The `state` of the call's latest [`state`](https://docs.ultravox.ai/apps/datamessages#state) message, or null before the first.
  * `global.threadState` → The `state` of a thread's latest [`thread_state`](https://docs.ultravox.ai/apps/datamessages#threadstate) message, or null if the
    thread hasn't reported one or has terminated. Takes a `threadId` argument in `propertyArguments`.

Arguments in `propertyArguments` are [templates](#templates), so they can refer to the event or local variables:

```js theme={null}
{
  "property": "global.threadState",
  "propertyArguments": { "threadId": "{{event.threadId}}" },
  "operator": "OPERATOR_NEQ",
  "value": "idle"
}
```

## 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:

* [`user_text_message`](https://docs.ultravox.ai/apps/datamessages#usertextmessage)
* [`forced_agent_message`](https://docs.ultravox.ai/apps/datamessages#forcedagentmessage)
* [`spawn_thread`](https://docs.ultravox.ai/apps/datamessages#spawnthread)

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](#templates); its `type` can't be templated.

```js theme={null}
{
  "dataMessage": {
    "type": "user_text_message",
    "text": "The user said: {{event.text}}",
    "urgency": "later"
  }
}
```

### Ternaries

`ternary` runs one list of actions or the other depending on a [condition](#conditions). At least one of `whenTrue` and `whenFalse`
must have actions.

```js theme={null}
{
  "ternary": {
    "condition": { "property": "event.role", "operator": "OPERATOR_EQ", "value": "user" },
    "whenTrue": [{ "incrementLocalVariable": { "name": "userTurns" } }],
    "whenFalse": [{ "incrementLocalVariable": { "name": "agentTurns" } }]
  }
}
```

### Local Variables

A trigger declares its local variables in `localVariables`, 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](#templates).
* `incrementLocalVariable` → Adds `value` (1 by default, and possibly negative) to a number variable.

```js theme={null}
{ "setLocalVariable": { "name": "lastTopic", "value": "{{event.text}}" } }
```

String values are limited to 32,768 characters. If `setLocalVariable` renders a longer string, it's truncated, and a
`trigger.truncated` call event is recorded.

### Starting and Canceling Timers

* `startTimer` → Starts the timer called `name`, firing after `delay` (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 called `name` from firing. Does nothing if it isn't running.

Timers last until they fire, are canceled, or the call ends. To fire repeatedly, a timer's trigger can restart it.

### Templates

Templated strings use [Mustache](https://mustache.github.io/mustache.5.html) 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

Set `triggers` when [creating a call](https://docs.ultravox.ai/api-reference/calls/calls-post.md). Each entry selects one trigger, as one of:

* `temporaryTrigger` → A trigger defined only for this call.
* `triggerId` → The ID of a [global trigger](#global-triggers).
* `triggerName` → The name of a global trigger.

```js theme={null}
{
  "systemPrompt": "You are a helpful assistant...",
  "triggers": [
    { "triggerName": "start_clock" },
    { "temporaryTrigger": { "name": "clock", /* the rest of the trigger */ } }
  ]
}
```

### In Agents

Set `triggers` 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](https://docs.ultravox.ai/api-reference/agents/agents-calls-post.md), `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 with `remove`.
* `add` → Triggers to add, selected as in `triggers`.

The call's triggers are the agent's, in their order and without those removed, followed by those added. An added trigger may not
have the same name as one of the agent's that remains, so to replace one of the agent's triggers, remove it and add the new one.

```js theme={null}
{
  "triggerOverrides": {
    "remove": ["clock"],
    "add": [{ "temporaryTrigger": { "name": "clock", /* a different schedule */ } }]
  }
}
```

### Listing a Call's Triggers

[List Call Triggers](https://docs.ultravox.ai/api-reference/calls/calls-triggers-list.md) returns a call's triggers, in order, as they were when the call was
created. Each one's `triggerId` 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](https://docs.ultravox.ai/api-reference/triggers/triggers-post.md):

```bash theme={null}
curl -X POST "https://api.ultravox.ai/api/triggers" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-api-key" \
  -d '{
    "trigger": {
      "name": "start_clock",
      "event": { "dataMessage": "call_started" },
      "actions": [{ "startTimer": { "name": "clock", "delay": "300s" } }]
    }
  }'
```

Then select it by `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.

[Updating a trigger](https://docs.ultravox.ai/api-reference/triggers/triggers-put.md) replaces its whole definition.

### Public Triggers

Your account can also see and select public triggers, whose `ownership` 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

| Limit | Value |
| - | - |
| Triggers per call, counting an agent's and those added | 10 |
| Actions per trigger, counting those within ternaries | 10 |
| Conditions per trigger, counting every child and those of ternaries | 20 |
| Local variables per trigger | 10 |
| Characters in a local variable's string value | 32,768 |
| Timer delay | At least 10 seconds |

## 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 example `Trigger 'clock': A trigger must have at least one action.`).

Some problems only show up while the call runs. These are recorded as [call events](https://docs.ultravox.ai/api-reference/calls/calls-events-list.md):

* `trigger.failed` → A condition couldn't be evaluated, for example because `OPERATOR_GT` found 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.

Each event's `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 public `threadsReportToParentOnIdle` trigger:

```js theme={null}
{ "triggerName": "threadsReportToParentOnIdle" }
```

Then spawn each thread that should report back with `reportToParent` in its [metadata](https://docs.ultravox.ai/apps/datamessages.md#spawnthread). Threads spawned
without it don't report back:

```js theme={null}
{
  "type": "spawn_thread",
  "metadata": { "reportToParent": "true" },
  "additionalMessages": [
    { "type": "user_text_message", "text": "Look up the latest pricing for the Enterprise plan and summarize it." }
  ]
}
```

The parent receives the thread's final response as a user message with `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](https://docs.ultravox.ai/agents/threads.md) spawned with
`"metadata": { "role": "delegate" }` reports its result back to the thread that spawned it the first time it finishes its work:

```js theme={null}
{
  "name": "return_to_parent",
  "event": { "dataMessage": "thread_state" },
  "condition": {
    "operator": "OPERATOR_AND",
    "conditions": [
      { "property": "event.state", "operator": "OPERATOR_EQ", "value": "idle" },
      { "property": "event.metadata.role", "operator": "OPERATOR_EQ", "value": "delegate" },
      { "property": "event.idleCount", "operator": "OPERATOR_EQ", "value": 1 }
    ]
  },
  "actions": [
    {
      "dataMessage": {
        "type": "user_text_message",
        "threadId": "{{event.parentThreadId}}",
        "text": "<delegate_result>{{event.lastResponse}}</delegate_result>",
        "urgency": "later"
      }
    }
  ]
}
```

## Next Steps

> [card] [Data Messages Reference](https://docs.ultravox.ai/apps/datamessages.md)
>
> The messages triggers can listen for and send.

> [card] [Threads](https://docs.ultravox.ai/agents/threads.md)
>
> Run parallel conversations that triggers can start and follow.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.