Skip to content

WebSocket Integration ​

Maintain a persistent WebSocket connection for real-time event streaming.

Overview ​

WebSocket provides lower latency and real-time bidirectional communication compared to HTTP webhooks. When a phone call starts, the Flow Service initiates a WebSocket connection to your application. Your application runs a WebSocket server that accepts these connections.

How It Works ​

Connection ​

When a phone call starts, the Flow Service initiates a WebSocket connection to your application. Your application must run a WebSocket server that accepts incoming connections.

WebSocket Server ​

Your application needs to expose a WebSocket endpoint that the Flow Service can connect to. The service will connect to your configured WebSocket URL when calls begin.

Connection URL ​

Configure your WebSocket server URL in the Flow dashboard. The service will connect to this URL, for example:

wss://your-domain.com/ai-flow/websocket

or for local development:

ws://localhost:8080/websocket

Message Format ​

Receiving Events ​

Events are sent as JSON strings:

json
{
  "type": "user_speak",
  "text": "Hello",
  "session": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "account_id": "account-123",
    "phone_number": "1234567890"
  }
}

Sending Actions ​

Send actions as JSON strings:

json
{
  "type": "speak",
  "session_id": "550e8400-e29b-41d4-a716-446655440000",
  "text": "Hello! How can I help you?"
}

Implementation Examples ​

Python ​

python
import asyncio
import websockets
import json

async def handle_message(websocket, path):
    async for message in websocket:
        event = json.loads(message)

        if event['type'] == 'user_speak':
            action = {
                'type': 'speak',
                'session_id': event['session']['id'],
                'text': f"You said: {event['text']}"
            }
            await websocket.send(json.dumps(action))

async def main():
    async with websockets.serve(handle_message, "localhost", 8765):
        await asyncio.Future()  # run forever

asyncio.run(main())

Node.js ​

javascript
const WebSocket = require('ws');

const wss = new WebSocket.Server({ port: 8080 });

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

    if (event.type === 'user_speak') {
      const action = {
        type: 'speak',
        session_id: event.session.id,
        text: `You said: ${event.text}`
      };
      ws.send(JSON.stringify(action));
    }
  });

  ws.on('error', (error) => {
    console.error('WebSocket error:', error);
  });
});

Go ​

go
package main

import (
    "encoding/json"
    "github.com/gorilla/websocket"
    "net/http"
)

var upgrader = websocket.Upgrader{
    CheckOrigin: func(r *http.Request) bool {
        return true
    },
}

func websocketHandler(w http.ResponseWriter, r *http.Request) {
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        return
    }
    defer conn.Close()

    for {
        var event map[string]interface{}
        err := conn.ReadJSON(&event)
        if err != nil {
            break
        }

        if event["type"] == "user_speak" {
            session := event["session"].(map[string]interface{})
            action := map[string]interface{}{
                "type":       "speak",
                "session_id": session["id"],
                "text":       "You said: " + event["text"].(string),
            }
            conn.WriteJSON(action)
        }
    }
}

func main() {
    http.HandleFunc("/ws", websocketHandler)
    http.ListenAndServe(":8080", nil)
}

Connection Management ​

The Flow Service manages the WebSocket connection lifecycle. When a call starts, it connects to your server. When the call ends, it may close the connection.

Handling Connections ​

Your WebSocket server should handle incoming connections from the Flow Service:

javascript
const WebSocket = require('ws');

const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', (ws, req) => {
  console.log('New connection from Flow Service');

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

  ws.on('error', (error) => {
    console.error('WebSocket error:', error);
  });

  ws.on('close', () => {
    console.log('Connection closed by Flow Service');
  });
});

Heartbeat ​

The Flow Service may send ping frames to keep the connection alive. Your server should respond with pong frames:

javascript
wss.on('connection', (ws) => {
  ws.on('ping', () => {
    ws.pong(); // Respond to ping with pong
  });

  // ... rest of connection handling
});

Error Handling ​

python
async def handle_message(websocket, path):
    try:
        async for message in websocket:
            try:
                event = json.loads(message)
                action = process_event(event)
                if action:
                    await websocket.send(json.dumps(action))
            except json.JSONDecodeError:
                print(f"Invalid JSON: {message}")
            except Exception as e:
                print(f"Error processing event: {e}")
    except websockets.exceptions.ConnectionClosed:
        print("Connection closed")
    except Exception as e:
        print(f"WebSocket error: {e}")

Advantages Over HTTP ​

  • Lower Latency - No HTTP overhead
  • Persistent Connection - No connection setup per request
  • Bidirectional - Can send messages anytime, from either side
  • Real-time - Instant event delivery
  • Proactive Communication - Send actions without waiting for events; receive events without requests

When to Use WebSocket ​

WebSockets enable a more flexible communication pattern than HTTP webhooks. Unlike the request/response model of HTTP webhooks, WebSockets allow:

  • Proactive event delivery - The Flow Service can send events to your application at any time, not just in response to a request
  • Unsolicited actions - Your application can send actions to the service without waiting for an event first
  • True bidirectional communication - Both sides can initiate communication independently

Use WebSocket when:

  • You need the lowest possible latency
  • You're handling high-volume traffic
  • You can run a persistent WebSocket server
  • You're building a real-time application
  • You have control over your server infrastructure
  • You need to send actions proactively without waiting for events

Use HTTP webhooks when:

  • You're using serverless functions (which can't maintain WebSocket connections)
  • You want simpler deployment
  • You prefer the request/response model (each event triggers a response)
  • You're building a simple integration
  • You can't run a persistent server

Next Steps ​