Logo
Search
API Docs

Hooks & Call Control

Conversation Flow & Multilingual

Assistant Hooks & Call Control Actions

Overview

Hooks let you wire automated, deterministic behavior into an assistant that runs alongside the model's own reasoning. Each hook pairs a trigger (something that happens during the call) with one or more actions (something the assistant does in response) — for example, warning a customer as a call approaches its time limit, or ending a call automatically after repeated silence. Hooks are configured as an array in the assistant's hooks field.


Hook Structure

Each object in the hooks array supports the following fields:

FieldRequiredDescription
onYesThe event that triggers the hook
doYesArray of actions to perform when the trigger fires
filtersNoConditions that must be met for the hook to trigger
optionsNoTrigger-specific configuration (used by call.timeElapsed, customer.speech.timeout, and assistant.transcriber.endpointedSpeechLowConfidence)
nameNoAn optional custom label to identify the hook

Trigger Events

The on field accepts one of the following events:

EventFires when…
call.endingA call is in the process of ending
call.timeElapsedA specified number of seconds has elapsed since the call started
assistant.speech.interruptedThe assistant's speech is interrupted (barge-in)
customer.speech.interruptedThe customer's speech is interrupted
customer.speech.timeoutThe customer doesn't speak within a specified window
assistant.transcriber.endpointedSpeechLowConfidenceA finalized transcript comes back with low confidence

Trigger-specific options

call.timeElapsedseconds: when the hook should fire, 1–3600. Fires once per call.

customer.speech.timeouttimeoutSeconds: how long to wait for the customer to speak (1–1000, default 7.5); triggerMaxCount: max times this hook can fire in a call (1–10, default 3); triggerResetMode: whether the trigger count resets after the customer speaks (default never).

assistant.transcriber.endpointedSpeechLowConfidenceconfidenceMin / confidenceMax: the confidence band (0–1) that counts as low-confidence.


Action Types

Each entry in a hook's do array is one of three action types:

  • say – speak a message. Use exact for predetermined text (a string or array of strings to vary between triggers) or prompt to have the model generate the line in the moment.
  • tool – execute a tool, such as transferCall, a custom function, or endCall.
  • message.add – silently inject a system message into the conversation to steer the model's next response, without speaking anything itself.

The endCall Tool

endCall is a built-in tool that terminates the call. It can be used in two ways:

Standalone, as an assistant tool

Add endCall directly to the assistant's tools so the model can decide, based on the conversation itself, when to hang up — for example once it recognizes the caller has said goodbye.

Inside a hook, as an automated action

Pair endCall with a tool action inside a hook's do array so the call ends automatically and deterministically when a trigger fires, regardless of what the model would otherwise decide. This is the more reliable option for hard limits, like enforcing a maximum silence count or a firm call-duration ceiling.

The say + endCall pattern

The most common pattern pairs a say action with a tool action calling endCall, so the caller hears a closing line before the line actually drops:

{
  "on": "customer.speech.timeout",
  "options": { "timeoutSeconds": 30, "triggerMaxCount": 3, "triggerResetMode": "onUserSpeech" },
  "do": [
    { "type": "say", "exact": "I haven't heard from you, so I'll go ahead and end the call now." },
    { "type": "tool", "tool": { "type": "endCall" } }
  ]
}

Without the leading say, the call simply drops with no warning — almost always worse for the caller experience.


Example Configurations

You can stack multiple hooks to handle different moments in the same call. This example warns the caller at 8 minutes and again at 9 minutes, then ends the call automatically after three rounds of silence:

{
  "maxDurationSeconds": 600,
  "hooks": [
    {
      "on": "call.timeElapsed",
      "options": { "seconds": 480 },
      "do": [{ "type": "say", "exact": "We're approaching our time limit for this call." }]
    },
    {
      "on": "call.timeElapsed",
      "options": { "seconds": 540 },
      "do": [{ "type": "say", "exact": "We have about one minute left." }]
    },
    {
      "on": "customer.speech.timeout",
      "options": { "timeoutSeconds": 30, "triggerMaxCount": 3, "triggerResetMode": "onUserSpeech" },
      "do": [
        { "type": "say", "exact": "I'll be ending the call now." },
        { "type": "tool", "tool": { "type": "endCall" } }
      ]
    }
  ]
}

A filters array can further scope a hook — for instance, only running a fallback message-and-transfer sequence when a call is ending due to a pipeline error:

{
  "on": "call.ending",
  "filters": [
    { "type": "oneOf", "key": "call.endedReason", "oneOf": ["pipeline-error"] }
  ],
  "do": [
    { "type": "say", "exact": "I apologize for the technical difficulty. Let me transfer you." },
    {
      "type": "tool",
      "tool": {
        "type": "transferCall",
        "destinations": [{ "type": "number", "number": "+1234567890", "callerId": "+1987654321" }]
      }
    }
  ]
}