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 ​