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 AI 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 AI 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 AI 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 AI 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 AI 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 AI Flow Service:

javascript
const WebSocket = require('ws');

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

wss.on('connection', (ws, req) => {
  console.log('New connection from AI 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 AI Flow Service');
  });
});

Heartbeat

The AI 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 AI 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