For more control than the raw silence timeout gives you, use the customer.speech.timeout hook (documented in full on the Idle Messages page). It supports:
| Option | Type | Range | Default | Description |
|---|
timeoutSeconds | number | 1–1000s | 7.5 | How long to wait for customer speech before triggering |
triggerMaxCount | number | 1–10 | 3 | Maximum times the hook fires per call |
triggerResetMode | string | never | onUserSpeech | never | Whether the trigger count resets when the user speaks |
Stacking several of these hooks at increasing intervals lets you escalate from a gentle check-in to actually ending the call, using the say + endCall tool pattern:
{
"hooks": [
{
"on": "customer.speech.timeout",
"options": { "timeoutSeconds": 10, "triggerMaxCount": 3, "triggerResetMode": "onUserSpeech" },
"do": [{ "type": "say", "exact": "Are you still there? Please let me know how I can help you." }]
},
{
"on": "customer.speech.timeout",
"options": { "timeoutSeconds": 20, "triggerMaxCount": 3, "triggerResetMode": "onUserSpeech" },
"do": [{ "type": "say", "prompt": "The user has not responded in 20s. Based on {{transcript}}, ask if they need help or if not you will be ending the call." }]
},
{
"on": "customer.speech.timeout",
"options": { "timeoutSeconds": 30, "triggerMaxCount": 3, "triggerResetMode": "onUserSpeech" },
"do": [
{ "type": "say", "exact": "I'll be ending the call now, please feel free to call back at any time." },
{ "type": "tool", "tool": { "type": "endCall" } }
]
}
]
}
Note that idle messages (and this hook) are automatically disabled during tool calls and warm transfers, so they don't interrupt system processes. For the full hook mechanics, action types, and filters, see Hooks & Call Control.