Skip to content

Event Types

Complete reference for all events sent by the Flow service.

Overview

Events are JSON objects sent from the Flow service to your application. All events include a type field and session information.

Base Event Structure

All events include session information:

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

The direction field indicates whether the call was initiated by the caller ("inbound") or by the Flow via the outbound call API ("outbound"). Use it in your session_start handler to tailor the greeting accordingly.

Event Types

Event TypeTransportDescriptionWhen Triggered
session_startHTTP + WebSocketCall session beginsWhen a new call is initiated — or when a failed transfer returns the caller (then it carries transfer_failed_reason)
user_speech_startedWebSocket onlySpeech onset detectedWhen VAD detects the user starting to speak (before full transcript)
user_speakHTTP + WebSocketUser speech detectedAfter speech-to-text completes (includes barged_in flag if user interrupted)
dtmf_receivedHTTP + WebSocketDTMF digit pressedWhen the user presses a key on their phone keypad
assistant_speakHTTP + WebSocketAssistant finished speakingAfter TTS playback completes
assistant_speech_endedHTTP + WebSocketAssistant finished speakingAfter speech playback ends
user_input_timeoutHTTP + WebSocketUser input timeout reachedWhen no speech detected after timeout
session_endHTTP + WebSocketCall session endsWhen the call terminates
sms_failedHTTP + WebSocketSMS delivery failedAfter a send_sms action fails — includes reason so the agent can react
errorHTTP + WebSocketSomething went wrongAn invalid action, an unreachable speech provider, a failed synthesis — includes a machine-readable code and severity

Quick Reference

SMS Failed

Emitted to your webhook / WebSocket when a send_sms action fails. The call continues normally — handle this event to react conversationally (e.g. apologize, retry with a corrected number).

json
{
  "type": "sms_failed",
  "session": { "id": "550e8400-...", "account_id": "...", "phone_number": "...",
                "from_phone_number": "...", "to_phone_number": "..." },
  "recipient": "4915112345678",
  "reason": "sender_not_allowed",
  "message": "SMSC returned faultCode 403"
}
FieldTypeDescription
typestringAlways "sms_failed"
sessionobjectStandard session info
recipientstringPhone number that failed (the phone_number from your send_sms action)
reasonstringOne of: sender_not_allowed, insufficient_balance, no_sms_extension, smsc_unavailable, unknown
messagestringOptional human-readable detail (safe to log, may contain technical error text)

See Send SMS Action for details on each failure reason.

Failed Transfer

When a transfer with a timeout does not connect, the caller is returned to your agent with another session_start for the same session.id. That event carries a transfer_failed_reason telling you why the transfer did not go through:

json
{
  "type": "session_start",
  "session": { "id": "550e8400-...", "account_id": "...", "phone_number": "...",
                "from_phone_number": "...", "to_phone_number": "..." },
  "transfer_failed_reason": "busy"
}
transfer_failed_reasonMeaning
busyThe target was busy
rejectedThe target actively declined the call
no_answerThe target rang until the timeout expired without picking up
number_not_foundThe target number does not exist
technical_errorThe call could not be delivered for technical reasons
unknownThe outcome could not be determined

busy, rejected and no_answer mean the target was reachable but did not take the call — usually worth offering another option or a second target. number_not_found and technical_error point at the number or the route itself, so retrying the same target rarely helps.

The field is absent on a new call, which makes it the reliable way to tell a returning caller from a first-time one. A transfer that connects never returns the caller, so there is no success counterpart — the session simply ends with session_end once the parties hang up.

TIP

transfer_failed_reason requires a timeout on the transfer action. Without one, a failed transfer ends the call and no reason is reported.

Error

Emitted whenever the service could not carry out something during the call — an action that failed validation, a speech provider that could not be reached, a synthesis that failed. Branch on the machine-readable code; use severity (warning = the call continues, error = the effect did not happen) to filter noise.

json
{
  "type": "error",
  "session": { "id": "550e8400-...", "account_id": "...", "phone_number": "...",
                "from_phone_number": "...", "to_phone_number": "..." },
  "code": "synthesis_unavailable",
  "severity": "error",
  "message": "Speech synthesis failed, so the requested audio output was not played.",
  "action_type": "speak"
}

Over HTTP you may answer an error event with action(s) (e.g. respond to synthesis_unavailable with a transfer); over WebSocket it is diagnostic only. This event is additive — sms_failed and transfer_failed_reason are unchanged. See Error Event for the full list of codes.

Event Flow

Handling Events

HTTP Webhook

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

    if event_type == 'session_start':
        # Handle session start
        pass
    elif event_type == 'user_speak':
        # Handle user speech
        pass
    # ... handle other events

WebSocket

javascript
ws.on('message', (data) => {
  const event = JSON.parse(data.toString());

  switch (event.type) {
    case 'session_start':
      // Handle session start
      break;
    case 'user_speak':
      // Handle user speech
      break;
    // ... handle other events
  }
});

Response Requirements

All events (except session_end) accept a single action, an array of actions (executed in sequence), or 204 No Content:

  • session_start: Can return action(s) or 204 No Content
  • user_speak: Can return action(s) or 204 No Content (check barged_in flag for interruptions)
  • dtmf_received: Can return action(s) or 204 No Content
  • assistant_speak: Can return action(s) or 204 No Content
  • assistant_speech_ended: Can return action(s) or 204 No Content
  • user_input_timeout: Can return action(s) or 204 No Content
  • session_end: No action allowed, cleanup only
  • error: Diagnostic. Over HTTP you may return action(s) or 204 No Content; over WebSocket the event carries no response

Next Steps