Documentation Index
Fetch the complete documentation index at: https://patter-06b046ce-feat-observability-otel-attrs-0-6-1.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Local Mode
Local mode runs an embedded Express server on your infrastructure. It handles telephony webhooks, manages WebSocket audio streams, and connects to AI providers directly — no external service required.Starting the Server
ServeOptions
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
agent | Agent | Yes | — | Agent configuration from phone.agent(...). |
port | number | No | 8000 | Port for the embedded server (1-65535). |
tunnel | boolean | No | false | When true, start a cloudflared tunnel automatically (requires cloudflared npm package). Cannot be used together with webhookUrl. |
onCallStart | (data) => Promise<void> | No | — | Called when a call connects. |
onCallEnd | (data) => Promise<void> | No | — | Called when a call disconnects. |
onTranscript | (data) => Promise<void> | No | — | Called for each transcript segment. |
onMessage | (data) => Promise<string> | No | — | Pipeline mode only. Receives user transcript, returns response text. Can also be a URL string for remote webhook/WebSocket integration. |
onMetrics | (data) => Promise<void> | No | — | Called after each conversational turn with per-turn latency and cost metrics. |
recording | boolean | No | false | Enable call recording (Twilio only). |
voicemailMessage | string | No | — | Default voicemail message for AMD. |
pricing | Record<string, Record<string, unknown>> | No | — | Custom pricing overrides for cost calculation. |
dashboard | boolean | No | true | When true, serve a dashboard UI at /dashboard. |
dashboardToken | string | No | — | Bearer token for dashboard/API authentication. |
manageWebhook | boolean | No | true | When true, serve() updates the carrier’s webhook URL (Twilio voice_url) on startup. Set to false if the webhook is managed externally (Terraform, an edge gateway, or a router function in front of the agent) — otherwise every boot will silently overwrite the externally-managed value. Ignored when tunnel: true, because the tunnel hostname is dynamic and only known at runtime. |
Webhook Endpoints
The embedded server exposes these HTTP endpoints:Health Check
{ "status": "ok", "mode": "local" }.
Twilio Endpoints
| Endpoint | Method | Purpose |
|---|---|---|
/webhooks/twilio/voice | POST | Handles incoming calls. Returns TwiML to connect a media stream. |
/webhooks/twilio/recording | POST | Receives recording status callbacks. |
/webhooks/twilio/amd | POST | Receives AMD (answering machine detection) results. |
/webhooks/twilio/status | POST | Receives call status callbacks for outbound calls. |
Telnyx endpoints are fully supported with feature parity to Twilio (DTMF, transfer, recording).
Telnyx Endpoints
| Endpoint | Method | Purpose |
|---|---|---|
/webhooks/telnyx/voice | POST | Handles incoming calls. Returns commands to answer and start streaming. |
WebSocket Streams
Audio streams are handled over WebSocket:/ws/stream/ path. Each call gets its own WebSocket connection.
Rate Limiting
WebSocket connections are rate-limited to 10 concurrent connections per IP address. Connections exceeding the limit receive a429 Too Many Requests response. This protects against DoS attacks while being generous enough for legitimate telephony provider traffic (which only opens 1 connection per call).
Security
Twilio Signature Validation
When a Twilio Auth Token is configured (either passed tonew Twilio({ authToken }) or via TWILIO_AUTH_TOKEN), all Twilio webhook requests are validated using HMAC-SHA1 signature verification:
- The SDK reconstructs the URL from the webhook hostname and request path
- Parameters are sorted and concatenated
- An HMAC-SHA1 digest is computed using the Twilio Auth Token
- The result is compared with the
X-Twilio-Signatureheader using timing-safe comparison
Telnyx Signature Validation
When a Telnyx public key is configured (either passed tonew Telnyx({ publicKey }) or via TELNYX_PUBLIC_KEY), Telnyx webhook requests are verified using Ed25519 signatures:
- The raw request body is captured before JSON parsing
- The signed payload is:
{timestamp}|{rawBody} - The Ed25519 signature is verified against the Telnyx public key
- Requests older than 5 minutes are rejected (replay protection)
Architecture
Audio Transcoding
| Provider | Input Format | Transcoding |
|---|---|---|
| Twilio | mulaw 8kHz | Decoded to PCM 16kHz |
| Telnyx | PCM 16kHz | No transcoding needed |
| OpenAI TTS | PCM 24kHz | Resampled to 16kHz |
Graceful Shutdown
Callphone.disconnect() to gracefully stop the embedded server. The shutdown sequence:
- Stop accepting new connections — the HTTP server stops listening.
- Hang up active calls — each active call is terminated via the telephony provider API (Twilio or Telnyx).
- Close WebSocket connections — a close frame (
1001 Server shutting down) is sent to all active WebSocket connections. - Wait for drain — the server waits up to 10 seconds for active connections to close cleanly.
- Force-terminate — any connections still open after the drain timeout are forcibly terminated.
- Close HTTP server — the underlying HTTP server is fully closed.
If a cloudflared tunnel was started with
tunnel: true, it is also stopped when disconnect() is called.Binding Address
The server binds to0.0.0.0 by default, which means it listens on all network interfaces. This is necessary for the server to accept connections from telephony providers and tunnels, but it also means the server is accessible from other machines on your network.
Use a tunnel (Cloudflare Tunnel, ngrok) to expose the server to the internet for telephony provider webhooks.
