Webhooks

Webhooks let you receive real-time notifications when calls end. Use them to update your CRM, trigger follow-ups, or sync call data to your systems.

Setup

Configure webhooks on your agent:

$curl -X PATCH https://api.levrage.ai/v1/agents/{agent_id} \
> -H "Authorization: Bearer $API_KEY" \
> -H "Content-Type: application/json" \
> -d '{
> "webhook_config": {
> "url": "https://your-server.com/webhook/levrage",
> "events": ["CALL_ENDED"],
> "secret": "whsec_your_secret_key"
> }
> }'

CALL_ENDED Event

Sent when any call handled by the agent ends. Contains the full call record.

Payload

1{
2 "event": "CALL_ENDED",
3 "timestamp": "2025-01-15T10:30:00Z",
4 "data": {
5 "session_id": "call_uuid",
6 "phone_number": "+919876543210",
7 "direction": "outbound",
8 "status": "completed",
9 "duration_seconds": 180,
10 "duration_minutes": 3.0,
11 "started_at": "2025-01-15T10:27:00Z",
12 "ended_at": "2025-01-15T10:30:00Z",
13
14 "agent_id": "agent_uuid",
15 "agent_type": "sales",
16
17 "sentiment": "positive",
18 "call_summary": "Customer was interested in the premium plan. Agreed to a follow-up call.",
19 "call_end_reason": "agent_ended",
20 "ended_by": "agent",
21
22 "details_collection": {
23 "status": "partial",
24 "score": 0.75,
25 "collected_details": ["full_name", "email"],
26 "collected_values": {
27 "full_name": "Rahul Sharma",
28 "email": "rahul@example.com"
29 }
30 },
31
32 "transcript": [
33 {"role": "agent", "content": "Hello! This is Sarah from Acme Corp.", "timestamp": "10:27:01"},
34 {"role": "user", "content": "Hi Sarah, yes tell me.", "timestamp": "10:27:05"},
35 {"role": "agent", "content": "I wanted to discuss our premium plan...", "timestamp": "10:27:08"}
36 ],
37
38 "recording_url": "https://storage.levrage.ai/recordings/call_uuid.wav",
39
40 "metadata": {
41 "customer_name": "Rahul",
42 "campaign_id": "campaign_uuid"
43 },
44
45 "ai_cost": 0.02,
46 "telephony_cost": 0.05,
47 "total_cost": 0.07
48 }
49}

Call Statuses

StatusDescription
completedCall connected and conversation happened
no_answerPhone rang but wasn’t answered
failedCall could not be connected
voicemailCall went to voicemail
busyLine was busy

Sentiment Values

SentimentDescription
positiveCustomer showed interest or satisfaction
neutralStandard interaction, no strong opinion
negativeCustomer expressed dissatisfaction

Verifying Webhooks

If you set a secret, verify the payload signature:

1import hmac
2import hashlib
3
4def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
5 expected = hmac.new(
6 secret.encode(),
7 payload,
8 hashlib.sha256
9 ).hexdigest()
10 return hmac.compare_digest(expected, signature)

The signature is sent in the X-Levrage-Signature header.

Delivery Policy

  • Timeout: 10 seconds per attempt
  • Retries: 3 attempts with exponential backoff
  • Format: POST with Content-Type: application/json
  • Idempotency: Use session_id as the idempotency key

Example: CRM Integration

1from flask import Flask, request
2
3app = Flask(__name__)
4
5@app.route("/webhook/levrage", methods=["POST"])
6def handle_webhook():
7 event = request.json
8
9 if event["event"] == "CALL_ENDED":
10 data = event["data"]
11
12 # Update CRM with call results
13 update_crm_contact(
14 phone=data["phone_number"],
15 status=data["status"],
16 sentiment=data["sentiment"],
17 summary=data["call_summary"],
18 collected=data.get("details_collection", {}).get("collected_values", {}),
19 recording=data.get("recording_url")
20 )
21
22 return {"status": "ok"}, 200