Skip to content

User Input Timeout Event

Sent when no user speech is detected within the configured timeout period after the assistant finishes speaking.

Event Structure

json
{
  "type": "user_input_timeout",
  "session": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "account_id": "account-123",
    "phone_number": "+1234567890",
    "direction": "inbound",
    "from_phone_number": "+9876543210",
    "to_phone_number": "+1234567890"
  }
}

When Triggered

This event is sent when:

  1. A speak action includes a user_input_timeout_seconds field
  2. The assistant finishes speaking (assistant_speech_ended event fires)
  3. The specified timeout period elapses without any user speech detected

Response

You can respond with any action:

json
{
  "type": "speak",
  "session_id": "550e8400-e29b-41d4-a716-446655440000",
  "text": "I didn't hear anything. Let me repeat the question."
}

Use Cases

Retry Question

javascript
app.post('/webhook', (req, res) => {
  const event = req.body;

  if (event.type === 'user_input_timeout') {
    return res.json({
      type: 'speak',
      session_id: event.session.id,
      text: 'Are you still there? Please say yes or no.',
      user_input_timeout_seconds: 5
    });
  }
});

Escalate to Human

javascript
app.post('/webhook', (req, res) => {
  const event = req.body;

  if (event.type === 'user_input_timeout') {
    return res.json({
      type: 'speak',
      session_id: event.session.id,
      text: 'Let me transfer you to a human agent.',
      // Follow with transfer action
    });
  }
});

Hangup After Multiple Timeouts

javascript
const timeoutCounts = new Map();

app.post('/webhook', (req, res) => {
  const event = req.body;

  if (event.type === 'user_input_timeout') {
    const sessionId = event.session.id;
    const count = (timeoutCounts.get(sessionId) || 0) + 1;
    timeoutCounts.set(sessionId, count);

    if (count >= 3) {
      return res.json({
        type: 'hangup',
        session_id: sessionId
      });
    }

    return res.json({
      type: 'speak',
      session_id: sessionId,
      text: `I didn't hear anything. Please respond. Attempt ${count} of 3.`,
      user_input_timeout_seconds: 5
    });
  }
});

Configuration

The timeout is configured in the speak action:

json
{
  "type": "speak",
  "session_id": "550e8400-e29b-41d4-a716-446655440000",
  "text": "What is your account number?",
  "user_input_timeout_seconds": 5
}

See Speak Action for details.

Behavior

  • Timer starts: When assistant_speech_ended event fires
  • Timer cleared: When any user speech is detected (STT events)
  • Event sent: When timeout period elapses without speech
  • New speak action: Clears any existing timeout and sets a new one (if specified)

Examples

Python

python
@app.route('/webhook', methods=['POST'])
def webhook():
    event = request.json

    if event['type'] == 'user_input_timeout':
        return jsonify({
            'type': 'speak',
            'session_id': event['session']['id'],
            'text': 'I didn\'t hear you. Please try again.'
        })

Go

go
if event["type"] == "user_input_timeout" {
    action := map[string]interface{}{
        "type":       "speak",
        "session_id": session["id"],
        "text":       "I didn't hear you. Please try again.",
    }
    json.NewEncoder(w).Encode(action)
}

Ruby

ruby
post '/webhook' do
  event = JSON.parse(request.body.read)

  if event['type'] == 'user_input_timeout'
    content_type :json
    {
      type: 'speak',
      session_id: event['session']['id'],
      text: 'I didn\'t hear you. Please try again.'
    }.to_json
  end
end

Best Practices

  1. Set reasonable timeouts - 5-10 seconds is typical for most interactions
  2. Provide feedback - Let users know why they're being prompted again
  3. Limit retries - After 2-3 timeouts, consider escalating or hanging up
  4. Use context - Different questions may need different timeout durations
  5. Handle gracefully - Don't frustrate users with immediate hangups