What are Webhooks?
Webhooks are HTTP callbacks that Dialgen sends to your server when specific events occur. Instead of polling for updates, your application receives instant notifications.
Available Webhooks
onBatchComplete
Triggered when all calls in the batch are finished.
{
"event": "batch.completed",
"batchId": "batch_123",
"agentId": "agent_456",
"userId": "user_789",
"statistics": {
"total": 1000,
"processed": 1000,
"succeeded": 850,
"failed": 150,
"percentComplete": 100,
"successRate": 85
},
"timestamps": {
"createdAt": "2025-11-15T14:00:00.000Z",
"startedAt": "2025-11-15T14:05:00.000Z",
"completedAt": "2025-11-15T16:30:00.000Z"
}
}
onCallComplete
Triggered after each individual call completes. Includes full call data:
{
"success": true,
"callData": {
"id": "call_123",
"contactId": "contact_456",
"agentId": "agent_789",
"batchId": "batch_abc",
"status": "COMPLETED",
"startTime": "2025-11-15T14:30:00.000Z",
"endTime": "2025-11-15T14:33:00.000Z",
"duration": 180,
"phoneNumber": "+1234567890",
"contactName": "John Doe",
"transcription": [...],
"recordingUrl": "https://...",
"summary": "Call summary text...",
"metricJson": {
"intent": "SALES_INQUIRY",
"sentiment": "positive",
"confidence": 0.95
}
},
"metricSchema": {...}
}
onBatchFailed
Triggered if the batch fails to process:
{
"event": "batch.failed",
"batchId": "batch_123",
"agentId": "agent_456",
"error": "Insufficient call minutes",
"code": "INSUFFICIENT_CREDITS",
"timestamp": "2025-11-15T14:05:00.000Z"
}
Configuring Webhooks
Add webhook URLs when creating your batch:
{
"agentId": "agent_123",
"userId": "user_456",
"contacts": [...],
"options": {
"webhooks": {
"onBatchComplete": "https://api.yourcompany.com/webhooks/batch-complete",
"onCallComplete": "https://api.yourcompany.com/webhooks/call-complete",
"onBatchFailed": "https://api.yourcompany.com/webhooks/batch-failed"
}
}
}
Implementing Webhook Endpoints
Node.js Example
const express = require('express');
const app = express();
app.use(express.json());
// Handle call completion
app.post('/webhooks/call-complete', (req, res) => {
const { callData } = req.body;
console.log(`Call ${callData.id} completed`);
console.log(`Duration: ${callData.duration}s`);
console.log(`Summary: ${callData.summary}`);
// Process call data
// - Update CRM
// - Send notifications
// - Trigger workflows
res.status(200).json({ received: true });
});
// Handle batch completion
app.post('/webhooks/batch-complete', (req, res) => {
const { batchId, statistics } = req.body;
console.log(`Batch ${batchId} completed`);
console.log(`Success rate: ${statistics.successRate}%`);
// Process batch completion
// - Generate reports
// - Send summary email
// - Archive batch data
res.status(200).json({ received: true });
});
app.listen(3000);
Python Example
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/webhooks/call-complete', methods=['POST'])
def call_complete():
data = request.json
call_data = data['callData']
print(f"Call {call_data['id']} completed")
print(f"Duration: {call_data['duration']}s")
print(f"Summary: {call_data['summary']}")
# Process call data
# - Update CRM
# - Send notifications
# - Trigger workflows
return jsonify({'received': True}), 200
@app.route('/webhooks/batch-complete', methods=['POST'])
def batch_complete():
data = request.json
batch_id = data['batchId']
statistics = data['statistics']
print(f"Batch {batch_id} completed")
print(f"Success rate: {statistics['successRate']}%")
# Process batch completion
# - Generate reports
# - Send summary email
# - Archive batch data
return jsonify({'received': True}), 200
if __name__ == '__main__':
app.run(port=3000)
Best Practices
Respond Quickly
- Respond within 5 seconds to avoid retries
- Return a 2xx status code immediately
- Process data asynchronously if needed
app.post('/webhooks/call-complete', async (req, res) => {
// Respond immediately
res.status(200).json({ received: true });
// Process asynchronously
processCallData(req.body).catch(console.error);
});
Handle Idempotency
Webhooks may be delivered multiple times. Use idempotency keys:
const processedWebhooks = new Set();
app.post('/webhooks/call-complete', (req, res) => {
const callId = req.body.callData.id;
if (processedWebhooks.has(callId)) {
return res.status(200).json({ received: true, duplicate: true });
}
processedWebhooks.add(callId);
// Process webhook
processCallData(req.body);
res.status(200).json({ received: true });
});
Secure Your Endpoints
Verify webhook authenticity:
const crypto = require('crypto');
function verifyWebhook(req, secret) {
const signature = req.headers['x-dialgen-signature'];
const payload = JSON.stringify(req.body);
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return signature === expectedSignature;
}
app.post('/webhooks/call-complete', (req, res) => {
if (!verifyWebhook(req, process.env.WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process webhook
res.status(200).json({ received: true });
});
Log Everything
Keep detailed logs for debugging:
app.post('/webhooks/call-complete', (req, res) => {
console.log('Webhook received:', {
timestamp: new Date().toISOString(),
callId: req.body.callData?.id,
status: req.body.callData?.status,
headers: req.headers
});
// Process webhook
res.status(200).json({ received: true });
});
Handle Errors Gracefully
app.post('/webhooks/call-complete', async (req, res) => {
try {
await processCallData(req.body);
res.status(200).json({ received: true });
} catch (error) {
console.error('Webhook processing error:', error);
// Still return 200 to prevent retries for application errors
res.status(200).json({ received: true, error: error.message });
}
});
Retry Logic
If your endpoint fails, Dialgen will retry:
- Retry Attempts: Up to 3 times
- Retry Delay: Exponential backoff (1s, 5s, 25s)
- Timeout: 30 seconds per attempt
If all retries fail, the webhook is dropped. Implement proper error handling and logging.
Testing Webhooks
Use ngrok for Local Testing
# Start ngrok
ngrok http 3000
# Use the ngrok URL in your webhook configuration
https://abc123.ngrok.io/webhooks/call-complete
Test with curl
curl -X POST https://your-server.com/webhooks/call-complete \
-H "Content-Type: application/json" \
-d '{
"success": true,
"callData": {
"id": "call_test_123",
"status": "COMPLETED",
"duration": 180
}
}'
Common Use Cases
Update CRM
app.post('/webhooks/call-complete', async (req, res) => {
const { callData } = req.body;
await crm.updateContact({
id: callData.contactId,
lastCallDate: callData.startTime,
callSummary: callData.summary,
sentiment: callData.metricJson.sentiment
});
res.status(200).json({ received: true });
});
Send Notifications
app.post('/webhooks/batch-complete', async (req, res) => {
const { batchId, statistics } = req.body;
await sendEmail({
to: 'team@company.com',
subject: `Batch ${batchId} Completed`,
body: `
Total Calls: ${statistics.total}
Success Rate: ${statistics.successRate}%
Succeeded: ${statistics.succeeded}
Failed: ${statistics.failed}
`
});
res.status(200).json({ received: true });
});
Trigger Workflows
app.post('/webhooks/call-complete', async (req, res) => {
const { callData } = req.body;
if (callData.metricJson.intent === 'INTERESTED') {
await workflow.trigger('send-follow-up-email', {
contactId: callData.contactId,
summary: callData.summary
});
}
res.status(200).json({ received: true });
});
Next Steps