Webhooks and Callbacks
How Talkr AI handles telephony webhooks and audio streaming
Overview
Talkr AI uses webhooks to communicate with telephony providers for call events and audio streaming. For outbound calls, Talkr builds these URLs and hands them to the provider when it dials — you never configure them by hand. For inbound calls, you point your provider at a single dispatcher URL; see Inbound Calls.
Every webhook path lives under /api/v1/telephony.
Webhook Types
1. Answer Webhook
When an outbound call connects, the provider requests instructions. The path is provider-specific, and Talkr appends the routing parameters as a query string:
?workflow_id={workflow_id}&workflow_run_id={workflow_run_id}&organization_id={organization_id}| Provider | Method | Path |
|---|---|---|
| Twilio, Cloudonix | POST | /twiml |
| Plivo | POST | /plivo-xml |
| Vobiz | POST | /vobiz-xml |
| Vonage | GET | /ncco |
Telnyx and Asterisk ARI have no answer webhook. Telnyx is call-control style — Talkr POSTs the stream and event URLs to Telnyx's API instead of returning markup. ARI streams over a WebSocket only.
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Connect>
<Stream url="wss://your-domain/api/v1/telephony/ws/123/11/789" />
</Connect>
</Response>Here 123 is the workflow, 11 the organization, and 789 the workflow run.
2. Status Callbacks
Receive call lifecycle events. Each is keyed on the workflow run:
| Provider | Path |
|---|---|
| Twilio | /twilio/status-callback/{workflow_run_id} |
| Plivo | /plivo/hangup-callback/{workflow_run_id}, /plivo/ring-callback/{workflow_run_id} |
| Vobiz | /vobiz/hangup-callback/{workflow_run_id}, /vobiz/ring-callback/{workflow_run_id} |
| Vonage | /vonage/events/{workflow_run_id} |
| Telnyx | /telnyx/events/{workflow_run_id} |
| Cloudonix | /cloudonix/status-callback/{workflow_run_id}, /cloudonix/cdr |
Providers report their own vocabulary; Talkr normalizes it into a common set of states:
initiated- Call request receivedringing- Call is ringingin-progress- Call is connected and streaminganswered- Call was answeredcompleted- Call ended normallybusy- Line was busyno-answer- Call not answeredcanceled- Call was canceled before connectingfailed- Call failederror- Provider reported an error
A status Talkr does not recognize is passed through unchanged rather than dropped.
3. WebSocket Audio Stream
Real-time audio streaming for voice interaction.
Endpoint: /api/v1/telephony/ws/{workflow_id}/{organization_id}/{workflow_run_id}
When TELEPHONY_WS_TOKEN_SECRET is set, the URL Talkr hands the carrier gains a fourth segment holding the HMAC signature: /api/v1/telephony/ws/{workflow_id}/{organization_id}/{workflow_run_id}/{token}. It is a path segment rather than a query parameter because carriers do not reliably forward query strings — Twilio strips them from <Stream url> entirely.
Asterisk ARI instead connects to /api/v1/telephony/ws/ari and passes the same three values as query parameters, plus token when a secret is configured — see Asterisk ARI.
The organization_id segment is the tenant that owns the workflow. Talkr scopes every workflow and workflow-run lookup by it, so a run belonging to one organization can never be served under another's id.
Audio Formats:
- Twilio / Plivo / Vobiz: 8kHz μ-law (MULAW), Base64-encoded in JSON messages
- Vonage: 16kHz Linear PCM, Binary frames
- Asterisk ARI: 8kHz Linear PCM via externalMedia
How It Works
Talkr AI automatically:
- Constructs webhook URLs based on your deployment
- Passes them to the telephony provider when initiating calls
- Verifies webhook signatures for security:
- Twilio: HMAC-SHA1 signature validation
- Plivo / Vobiz: HMAC-SHA256 signature validation
- Vonage: JWT token verification
- Processes status updates to track call lifecycle
- Manages WebSocket connections for audio streaming
- Handles provider-specific audio formats and protocols
Signature verification is implemented per provider in verify_inbound_signature. If you are adding a provider, see Custom Telephony Provider.
Local Development
For local development, use the built-in Cloudflare tunnel:
# docker-compose.yml includes:
cloudflared:
image: cloudflare/cloudflared:latest
command: tunnel --no-autoupdate --url http://api:8000The tunnel URL is automatically detected and used for webhooks.