Skip to content

CRM webhooks

CRM webhooks send call outcomes from VaniAgent to an HTTPS endpoint you control.

  • call.completed
  • call.recording_ready
  • call.failed

Events may originate from campaign, direct/send-call, web test, or inbound calls. Subscribe only to events your consumer handles.

The endpoint must use HTTPS. Configure a timeout from 5–120 seconds and 0–10 retries. Return a 2xx response promptly; queue slower CRM work after authentication.

VaniAgent signs the raw request body with HMAC-SHA256 and sends the digest in X-Webhook-Signature.

import hashlib, hmac
def valid_signature(raw_body: bytes, received: str, secret: str) -> bool:
expected = hmac.new(
secret.encode("utf-8"),
raw_body,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(f"sha256={expected}", received)

Do not parse and re-serialize JSON before verification; verify the exact raw bytes received.

Use Test delivery, confirm the signature check succeeds, and inspect delivery logs. Logs include event, attempt, HTTP result, and error details. Repeated failures can degrade or disable a webhook; fix the receiver, test successfully, then re-enable it.

Make processing idempotent because retries can deliver the same logical event more than once.

All payloads contain event, timestamp, and data.

call.completed includes call identity, direction, status, duration, timestamps, provider identifiers, agent, optional campaign, transcript, analysis, and billing. Recordings are included when enabled for the webhook configuration.

{
"event": "call.completed",
"timestamp": "2026-07-28T10:30:00Z",
"data": {
"call": {
"id": "call_id",
"phone_number": "+919876543210",
"call_type": "campaign",
"call_direction": "outbound",
"status": "completed",
"duration_seconds": 84,
"provider": "exotel",
"provider_call_id": "provider_id"
},
"campaign": { "id": "campaign_id", "name": "Lead qualification" },
"agent": { "id": "agent_id" },
"transcript": { "text": "...", "with_timestamps": [] },
"analysis": {
"summary": "...",
"sentiment": "positive",
"structured_data": {}
},
"billing": { "cost": "4.20", "rate_per_minute": "3.00", "currency": "INR" }
}
}

call.recording_ready contains call_id, phone number, call type/direction, and provider/S3 recording URLs. call.failed contains call identifiers and an error object.

Additional delivery headers include X-Webhook-Event and the signature header. Consumers should tolerate additional JSON fields.