Skip to main content

Table of Contents

  1. What are Webhooks?
  2. Getting Started
  3. Webhook Events
  4. Setup & Configuration
  5. Event Payloads
  6. Best Practices
  7. Testing & Debugging
  8. Troubleshooting

What are Webhooks?

Webhooks are HTTP callbacks that allow CallIntel LiveKit to send real-time notifications to your application when specific events occur. Instead of constantly polling our API for updates, webhooks push data to your system instantly.

Key Benefits

  • Real-time Updates: Receive instant notifications about call events
  • Reduced Latency: No need for polling intervals
  • Efficient: Only receive data when events occur
  • Scalable: Handle high volumes of events asynchronously
  • Reliable: Automatic retry mechanism for failed deliveries

How Webhooks Work

1. Event occurs in CallIntel (call completed, transcript ready, etc.)

2. System triggers webhook event

3. HTTP POST request sent to your configured webhook URL

4. Your application receives and processes the data

5. Your application sends HTTP 200 response

6. Webhook delivery marked as successful

Getting Started

Prerequisites

  • CallIntel LiveKit account with organization
  • Public HTTPS URL for receiving webhooks
  • Basic understanding of HTTP and JSON

Quick Setup

  1. Navigate to Webhooks Settings
    • Go to Organization Dashboard → Settings → Webhooks
  2. Add Webhook URL
    • Enter your HTTPS endpoint URL
    • Example: https://your-domain.com/webhooks/callintel
  3. Select Events
    • Choose which events to subscribe to
    • Save configuration
  4. Test Connection
    • Click “Send Test Webhook”
    • Verify receipt and logging
  5. Start Receiving Events
    • Your system is now ready to receive real-time events

Webhook Events

CallIntel LiveKit supports the following webhook event types:

Call Events

call.initiated

A new call has been initiated (outbound only)

call.connected

Call has been successfully connected

call.in_progress

Call is currently in progress

call.completed

Call has been completed successfully

call.failed

Call failed to connect or was dropped

call.missed

Inbound call was not answered

Data Events

call.transcript_ready

Call transcript has been generated

call.recording_ready

Call recording is available for download

call.summary_ready

AI-generated call summary is ready

call.analysis_complete

Call analysis (sentiment, intent, etc.) is complete

Batch Events

batch.initiated

Batch call campaign has been initiated

batch.in_progress

Batch calls are currently being processed

batch.completed

All batch calls have been completed

batch.failed

Batch call campaign encountered errors

Setup & Configuration

Configure Webhook Endpoint

Your webhook endpoint must:
  • ✅ Be publicly accessible over HTTPS
  • ✅ Accept POST requests
  • ✅ Return HTTP 200 status code
  • ✅ Respond within 10 seconds
  • ✅ Handle duplicate events

Add Webhook URL

Via Dashboard

  1. Go to Organization SettingsWebhooks
  2. Click “Add Webhook”
  3. Enter webhook URL: https://your-domain.com/webhooks/callintel
  4. Select event types to subscribe
  5. Click “Save”

Via API

curl -X POST https://api.callintel.com/v1/webhooks \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-domain.com/webhooks/callintel",
    "events": [
      "call.completed",
      "call.transcript_ready",
      "batch.completed"
    ],
    "active": true
  }'

Webhook Settings

SettingDescriptionDefault
URLYour webhook endpointRequired
EventsEvent types to receiveAll
ActiveEnable/disable webhookEnabled
RetryAutomatic retry attempts3
TimeoutRequest timeout (seconds)10

Event Payloads

Call Status Changed Event

{
  "event_type": "call.completed",
  "timestamp": "2024-12-16T10:30:45Z",
  "webhook_id": "wh_1a2b3c4d5e",
  "data": {
    "id": "call_123456789",
    "call_from": "+1234567890",
    "call_to": "+0987654321",
    "agent_id": "agent_abc123",
    "agent_name": "Support Agent",
    "status": "completed",
    "direction": "outbound",
    "call_type": "voice",
    "start_time": "2024-12-16T10:25:00Z",
    "end_time": "2024-12-16T10:30:45Z",
    "duration_seconds": 345,
    "recording_url": "https://storage.callintel.com/recordings/call_123.mp3",
    "transcript_url": "https://storage.callintel.com/transcripts/call_123.txt",
    "custom_metadata": {
      "campaign_id": "camp_001",
      "customer_id": "cust_789"
    }
  }
}

Call Transcript Event

{
  "event_type": "call.transcript_ready",
  "timestamp": "2024-12-16T10:31:00Z",
  "webhook_id": "wh_1a2b3c4d5e",
  "data": {
    "id": "call_123456789",
    "call_id": "call_123456789",
    "transcript": "Agent: Hello, how can I help you today? Customer: I'd like to check my order status...",
    "summary": "Customer inquired about order #12345. Agent confirmed order is in transit and will arrive by Dec 20.",
    "sentiment": "positive",
    "intent": "order_tracking",
    "actionable_items": [
      "Send customer tracking link",
      "Follow up if not delivered by Dec 20"
    ],
    "keywords": ["order", "tracking", "delivery"],
    "confidence_score": 0.95
  }
}

Batch Call Event

{
  "event_type": "batch.completed",
  "timestamp": "2024-12-16T11:45:00Z",
  "webhook_id": "wh_1a2b3c4d5e",
  "data": {
    "id": "batch_987654321",
    "batch_name": "Q4 Customer Survey",
    "agent_id": "agent_abc123",
    "agent_name": "Survey Agent",
    "status": "completed",
    "total_numbers": 1000,
    "successfully_called": 856,
    "failed_calls": 144,
    "avg_duration_seconds": 287,
    "start_time": "2024-12-16T10:00:00Z",
    "end_time": "2024-12-16T11:45:00Z",
    "success_rate": 0.856,
    "cost_usd": 45.20,
    "custom_metadata": {
      "campaign_type": "survey",
      "department": "customer_success"
    }
  }
}

Best Practices

1. Verify Webhook Authenticity

Always verify that webhooks are legitimate CallIntel requests:
import hmac
import hashlib
from flask import Flask, request

app = Flask(__name__)
WEBHOOK_SECRET = "your_webhook_secret"

@app.route('/webhooks/callintel', methods=['POST'])
def handle_webhook():
    # Get signature from headers
    signature = request.headers.get('X-Callintel-Signature')
    
    # Calculate expected signature
    payload = request.get_data(as_text=True)
    expected_signature = hmac.new(
        WEBHOOK_SECRET.encode(),
        payload.encode(),
        hashlib.sha256
    ).hexdigest()
    
    # Verify signature
    if not hmac.compare_digest(signature, expected_signature):
        return {'error': 'Invalid signature'}, 401
    
    # Process webhook
    data = request.get_json()
    process_event(data)
    
    return {'status': 'success'}, 200

2. Handle Duplicate Events

Events may be delivered multiple times. Use idempotency keys:
def process_event(event):
    webhook_id = event.get('webhook_id')
    
    # Check if already processed
    if WebhookLog.query.filter_by(webhook_id=webhook_id).exists():
        return  # Already processed
    
    # Process event
    event_data = event.get('data')
    # ... your logic here ...
    
    # Log webhook
    log = WebhookLog(webhook_id=webhook_id, processed_at=datetime.now())
    db.session.add(log)
    db.session.commit()

3. Implement Retry Logic

Handle temporary failures gracefully:
def handle_webhook(event):
    try:
        # Process event
        result = process_event(event)
        return {'status': 'success'}, 200
    except TemporaryError as e:
        # Return 5xx for CallIntel to retry
        return {'error': 'Temporary error'}, 503
    except PermanentError as e:
        # Log error and return 200 to prevent retries
        logger.error(f"Permanent error: {e}")
        return {'status': 'error', 'logged': True}, 200

4. Respond Quickly

Your endpoint should respond as quickly as possible:
@app.route('/webhooks/callintel', methods=['POST'])
def handle_webhook():
    event = request.get_json()
    
    # Acknowledge immediately
    result = {'status': 'received'}
    
    # Process asynchronously
    process_event_async.delay(event)
    
    return result, 202  # Accepted

5. Log All Webhooks

Maintain a log of all webhook deliveries:
def log_webhook(event, status, response):
    log = WebhookLog(
        webhook_id=event.get('webhook_id'),
        event_type=event.get('event_type'),
        status=status,
        response=response,
        received_at=datetime.now()
    )
    db.session.add(log)
    db.session.commit()

Testing & Debugging

Test Webhook from Dashboard

  1. Navigate to Organization SettingsWebhooks
  2. Select your webhook
  3. Click “Send Test Event”
  4. Choose event type to test
  5. View response status and logs

Manual Testing with curl

# Send test webhook
curl -X POST https://your-domain.com/webhooks/callintel \
  -H "Content-Type: application/json" \
  -H "X-Callintel-Signature: test_signature" \
  -d '{
    "event_type": "call.completed",
    "timestamp": "2024-12-16T10:30:45Z",
    "webhook_id": "wh_test_123",
    "data": {
      "id": "call_test_123",
      "status": "completed",
      "duration_seconds": 300
    }
  }'

Monitor Webhook Logs

Via Dashboard

  1. Go to Organization SettingsWebhooks
  2. Click “View Logs”
  3. Filter by:
    • Date range
    • Event type
    • Status (Success/Failed/Pending)
    • Response code

Via API

curl -X GET "https://api.callintel.com/v1/webhooks/logs?limit=50" \
  -H "Authorization: Bearer YOUR_API_KEY"

Debug Webhook Issues

Use these tools to debug webhook problems:

Troubleshooting

Common Issues

Webhook Not Being Delivered

Check:
  • ✅ Webhook URL is publicly accessible
  • ✅ URL uses HTTPS (HTTP will be rejected)
  • ✅ Endpoint accepts POST requests
  • ✅ Firewall allows incoming connections
  • ✅ Webhook is enabled in settings
# Test URL accessibility
curl -X POST https://your-domain.com/webhooks/callintel \
  -H "Content-Type: application/json" \
  -d '{"test": true}'

Webhook Timeout

Issue: Webhook endpoint takes too long to respond Solution:
  • Process events asynchronously
  • Respond with 202 Accepted
  • Use background job queue
# ✗ WRONG - Will timeout
@app.route('/webhooks/callintel', methods=['POST'])
def handle_webhook():
    event = request.get_json()
    process_long_task(event)  # Takes 30 seconds
    return {'status': 'success'}, 200

# ✓ CORRECT - Responds quickly
@app.route('/webhooks/callintel', methods=['POST'])
def handle_webhook():
    event = request.get_json()
    queue.enqueue(process_long_task, event)
    return {'status': 'accepted'}, 202

Duplicate Event Processing

Issue: Same event processed multiple times Solution: Implement idempotency
def process_event(event):
    webhook_id = event['webhook_id']
    
    # Use atomic operation to prevent duplicates
    created = WebhookLog.create_if_not_exists(webhook_id)
    
    if not created:
        return  # Already processed
    
    # Process event...

Invalid Signature

Issue: Webhook signature verification fails Check:
  • ✅ Using correct webhook secret
  • ✅ Signature header present
  • ✅ Not modifying request body
  • ✅ Using correct hash algorithm (SHA-256)

Error Response Codes

CodeMeaningAction
200SuccessEvent processed
201CreatedResource created
202AcceptedWill process asynchronously
400Bad RequestInvalid payload format
401UnauthorizedInvalid signature
403ForbiddenAccess denied
404Not FoundEndpoint doesn’t exist
500-599Server ErrorWill retry automatically

Get Support

If you’re experiencing webhook issues:
  1. Check Logs - Review webhook delivery logs in dashboard
  2. Test Webhook - Send test event to verify endpoint
  3. Monitor Status - Check Organization Health page
  4. Contact Support - Email: callintel01@gmail.com

Advanced Configuration

Webhook Filters

Filter events to reduce noise:
curl -X POST https://api.callintel.com/v1/webhooks \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-domain.com/webhooks",
    "events": ["call.completed"],
    "filters": {
      "direction": "outbound",
      "status": "completed",
      "min_duration": 60
    }
  }'

Multiple Webhooks

Register multiple endpoints for different purposes:
# Production webhook
curl -X POST https://api.callintel.com/v1/webhooks \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "url": "https://prod.example.com/webhooks",
    "events": ["call.completed", "batch.completed"]
  }'

# Analytics webhook
curl -X POST https://api.callintel.com/v1/webhooks \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "url": "https://analytics.example.com/webhooks",
    "events": ["call.completed"]
  }'

# Backup webhook
curl -X POST https://api.callintel.com/v1/webhooks \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "url": "https://backup.example.com/webhooks",
    "events": ["call.completed", "call.transcript_ready"]
  }'

Webhook Retry Policy

Configure retry behavior:
curl -X PUT https://api.callintel.com/v1/webhooks/wh_123 \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "retry_policy": {
      "max_attempts": 5,
      "backoff_multiplier": 2,
      "initial_delay_seconds": 60,
      "max_delay_seconds": 3600
    }
  }'

FAQ

Webhooks are retried up to 3 times with exponential backoff. First retry at 60 seconds, then 300 seconds, then 900 seconds.
No, webhooks must use HTTPS for security. HTTP endpoints will be rejected.
CallIntel will retry the webhook delivery multiple times. Once all retries are exhausted, the webhook delivery is marked as failed and logged.
Each webhook includes an X-Callintel-Signature header containing an HMAC-SHA256 signature. Verify this against your webhook secret.
Yes, when registering a webhook, you can select specific event types or use filters for more granular control.
Webhook payloads are limited to 10 MB. Larger payloads will be truncated or rejected.
Use ngrok to expose your local server: ngrok http 8000, then use the generated URL as your webhook endpoint.
Yes, toggle the “Active” switch in webhook settings to disable without deleting it.

See Also


Happy Building! 🚀 For support or questions about webhooks, contact us at callintel01@gmail.com