Skip to main content

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

  1. Navigate to Settings > Webhooks in the dashboard.
  2. Click Add Endpoint.
  3. Enter the URL of your webhook receiver (must be HTTPS).
  4. Select which event types you want to receive.
  5. Optionally set a signing secret for verifying webhook authenticity.
  6. 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:

AttemptDelay
1st retry10 seconds
2nd retry1 minute
3rd retry10 minutes
4th retry1 hour
5th retry4 hours

After 5 failed retries, the webhook delivery is marked as failed and no further attempts are made for that event.

tip

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, or failed.
  • 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:

  1. Go to Settings > Webhooks > Delivery Logs.
  2. Find the delivery you want to replay.
  3. Click Replay.
  4. 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 OK as 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_id and event fields to deduplicate deliveries. The same event may be delivered more than once due to retries.
  • Validate signatures. Always verify the X-Vocals-Signature header 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.