Webhooks
Webhooks let you receive real-time notifications when events occur in VOCALS. Use them to sync call data with your CRM, trigger workflows, update databases, or alert your team.
Configuring a Webhook Endpoint
- Navigate to Settings > Webhooks in the dashboard.
- Click Add Endpoint.
- Enter the URL of your webhook receiver (must be HTTPS).
- Select which event types you want to receive.
- Optionally set a signing secret for verifying webhook authenticity.
- Click Save.
VOCALS will send a test ping to your endpoint to verify it is reachable. The endpoint must respond with a 2xx status code within 5 seconds.
Event Types
call.started
Fired when a call connects and the voice pipeline begins.
{
"event": "call.started",
"timestamp": "2026-03-02T14:30:00.000Z",
"data": {
"call_id": "call_abc123",
"direction": "inbound",
"from": "+15559876543",
"to": "+15551234567",
"agent_id": "agent_xyz789",
"agent_name": "Inbound Sales",
"phone_number_id": "pn_456"
}
}
call.ended
Fired when a call terminates, regardless of the reason.
{
"event": "call.ended",
"timestamp": "2026-03-02T14:35:22.000Z",
"data": {
"call_id": "call_abc123",
"direction": "inbound",
"from": "+15559876543",
"to": "+15551234567",
"agent_id": "agent_xyz789",
"agent_name": "Inbound Sales",
"status": "completed",
"duration_seconds": 322,
"turns": 12,
"cost": {
"stt": 0.0048,
"llm": 0.0135,
"tts": 0.0210,
"telephony": 0.0180,
"total": 0.0573
},
"recording_url": "https://your-vocals-domain.com/api/v1/recordings/rec_abc123",
"metadata": {}
}
}
call.failed
Fired when a call fails due to a technical error. This does not fire for normal no-answer scenarios.
{
"event": "call.failed",
"timestamp": "2026-03-02T14:30:05.000Z",
"data": {
"call_id": "call_def456",
"direction": "outbound",
"from": "+15551234567",
"to": "+15559876543",
"agent_id": "agent_xyz789",
"error": {
"code": "provider_timeout",
"message": "STT provider (Deepgram) did not respond within 10 seconds",
"provider": "deepgram",
"stage": "stt"
}
}
}
transcript.ready
Fired when the full call transcript has been processed and is available. This event is sent after call.ended, typically within a few seconds.
{
"event": "transcript.ready",
"timestamp": "2026-03-02T14:35:30.000Z",
"data": {
"call_id": "call_abc123",
"transcript": [
{
"speaker": "agent",
"text": "Hello, thank you for calling Acme Corp. How can I help you today?",
"timestamp": "2026-03-02T14:30:01.000Z"
},
{
"speaker": "caller",
"text": "Hi, I'd like to check the status of my order.",
"timestamp": "2026-03-02T14:30:05.500Z"
},
{
"speaker": "agent",
"text": "Of course! Could you give me your order number?",
"timestamp": "2026-03-02T14:30:07.200Z"
}
],
"summary": "Customer called to check order status. Agent provided tracking information. Customer confirmed receipt.",
"duration_seconds": 322,
"turns": 12
}
}
Verifying Webhook Signatures
If you set a signing secret, VOCALS includes a signature in the X-Vocals-Signature header of each webhook request. Use this to verify that the request came from VOCALS and was not tampered with.
The signature is computed as an HMAC-SHA256 of the raw request body using your signing secret:
import hmac
import hashlib
def verify_signature(payload_body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode("utf-8"),
payload_body,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature)
const crypto = require("crypto");
function verifySignature(payloadBody, signature, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(payloadBody)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(`sha256=${expected}`),
Buffer.from(signature)
);
}
Retry Policy
If your endpoint does not respond with a 2xx status code within 5 seconds, VOCALS retries the delivery with exponential backoff:
| Attempt | Delay |
|---|---|
| 1st retry | 10 seconds |
| 2nd retry | 1 minute |
| 3rd retry | 10 minutes |
| 4th retry | 1 hour |
| 5th retry | 4 hours |
After 5 failed retries, the webhook delivery is marked as failed and no further attempts are made for that event.
If your endpoint is temporarily down, you can replay failed deliveries from the webhook logs once it is back up.
Delivery Logs
Every webhook delivery is logged in Settings > Webhooks > Delivery Logs. Each log entry shows:
- Event type and timestamp.
- Request payload sent to your endpoint.
- Response status code and response body from your endpoint.
- Delivery status:
delivered,retrying, orfailed. - Latency: how long your endpoint took to respond.
Use delivery logs to debug integration issues. You can filter by event type, delivery status, and date range.
Replaying Deliveries
To replay a failed or missed delivery:
- Go to Settings > Webhooks > Delivery Logs.
- Find the delivery you want to replay.
- Click Replay.
- VOCALS will re-send the exact same payload to your current endpoint URL.
This is useful after fixing a bug in your webhook receiver or recovering from downtime.
Best Practices
- Respond quickly. Return a
200 OKas soon as you receive the webhook. Process the payload asynchronously. If your handler takes too long, it will be treated as a failure and retried. - Implement idempotency. Use the
call_idandeventfields to deduplicate deliveries. The same event may be delivered more than once due to retries. - Validate signatures. Always verify the
X-Vocals-Signatureheader in production to prevent spoofed requests. - Use HTTPS. Webhook endpoints must use HTTPS. Plaintext HTTP endpoints are rejected.
- Monitor delivery logs. Check your delivery logs regularly to catch integration failures early. Set up alerts for sustained delivery failures.