Skip to main content

What Are Webhooks?

Webhooks are HTTP callbacks that TopCalls sends to your server when events occur. They’re the best way to integrate TopCalls with your existing systems.

Real-Time Updates

Get notified instantly when calls complete, fail, or campaigns update. No polling required.

Complete Data

Receive full call details, transcripts, recordings, and analysis in a single webhook payload.

Reliable Delivery

Built-in retry logic ensures webhooks are delivered even if your server is temporarily unavailable.

Secure

Optional signature verification ensures webhooks are authentic and haven’t been tampered with.

Setting Up Webhooks

Per-Call Webhooks

Configure webhooks when creating a call:
{
  "phone_number": "+14155551234",
  "task": "Confirm appointment...",
  "webhook_url": "https://your-app.com/webhooks/call-complete",
  "webhook_events": ["call.completed", "call.failed"]
}

Campaign Webhooks

Configure webhooks when creating a campaign:
{
  "name": "Sales Outreach",
  "webhook_url": "https://your-app.com/webhooks/campaign",
  "webhook_events": ["campaign.started", "campaign.completed", "call.completed"]
}

Webhook Payload

Here’s a complete call.completed webhook payload:
{
  "call_id": "564d4fd4-03bc-400a-abe0-05540fbeff88",
  "phone_number": "+14155551234",
  "from_phone_number": "+18005551234",
  "status": "completed",
  "call_status": "completed",
  "duration": 2.5,
  "transcript": [
    {
      "id": 1,
      "user": "assistant",
      "text": "Hi, this is Sarah from TopView Dental...",
      "created_at": "2025-12-22T10:30:05Z"
    },
    {
      "id": 2,
      "user": "user",
      "text": "Yes, hi...",
      "created_at": "2025-12-22T10:30:08Z"
    }
  ],
  "recording_url": "https://api.topcalls.ai/recordings/.../2025/12/22/mp3",
  "call_summary": "Successfully confirmed appointment...",
  "answered_by": "human",
  "campaign_id": "camp_abc123",
  "lead_id": "lead_xyz789",
  "created_at": "2025-12-22T10:30:00Z",
  "started_at": "2025-12-22T10:30:05Z",
  "end_at": "2025-12-22T10:32:35Z",
  "metadata": {
    "patient_id": "pat_123",
    "source": "reminder_system"
  }
}

Webhook Timing

Successful Calls

Webhooks are sent ~15 seconds after call ends to ensure:
  • Recording URL is available
  • Transcript is complete
  • Call summary is generated (if configured)

Failed Calls

Webhooks are sent immediately when the call fails (no recording to wait for).

Handling Webhooks

Express.js Example

app.post('/webhooks/call-complete', async (req, res) => {
  // Always return 200 quickly
  res.status(200).json({ received: true });
  
  // Process asynchronously
  const call = req.body;
  
  // Update CRM
  await updateCRM(call);
  
  // Send notification
  await sendNotification(call);
  
  // Update analytics
  await updateAnalytics(call);
});

Signature Verification

import crypto from 'crypto';

function verifyWebhookSignature(payload, signature, secret) {
  const hmac = crypto.createHmac('sha256', secret);
  const digest = hmac.update(JSON.stringify(payload)).digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(digest)
  );
}

app.post('/webhooks/call-complete', (req, res) => {
  const signature = req.headers['x-topcalls-signature'];
  
  if (!verifyWebhookSignature(req.body, signature, WEBHOOK_SECRET)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }
  
  // Process webhook...
});

Webhook Retries

TopCalls automatically retries failed webhook deliveries:
  • Initial: Immediate
  • Retry 1: After 1 minute
  • Retry 2: After 5 minutes
  • Retry 3: After 15 minutes
  • Retry 4: After 1 hour
After 4 retries, the webhook is marked as failed. You can still retrieve call data via the API.

Best Practices

✅ Do This

  • Return 200 quickly: Acknowledge receipt within 1 second
  • Process asynchronously: Don’t block the webhook response
  • Idempotency: Handle duplicate webhooks gracefully
  • Log everything: Keep logs for debugging
  • Verify signatures: Use signature verification in production
  • Handle errors: Don’t let webhook processing crash your server

❌ Don’t Do This

  • Long processing: Don’t process synchronously in the webhook handler
  • Ignore duplicates: Webhooks may be delivered multiple times
  • Skip verification: Always verify signatures in production
  • Block on external APIs: Don’t wait for slow external services

Testing Webhooks

Use ngrok or webhook.site to test locally:
# Start ngrok tunnel
ngrok http 3000

# Use the ngrok URL
{
  "webhook_url": "https://abc123.ngrok.io/webhooks/call-complete"
}

Next Steps