Why Webhooks Matter
Webhooks enable real-time communication between CallPayMin and your application. When events occur (calls start, end, billing processed), we POST the event data to your configured endpoint.
Available Webhook Events
| Event | Description |
|---|---|
call.created | A new call has been created |
call.started | A call has started (first participant joined) |
call.ended | A call has ended |
call.billing.charged | Billing has been processed for a call |
user.balance_low | User balance below threshold |
summary.ready | AI summary is available |
Security: Verify Signatures
Always verify webhook signatures to ensure requests are from CallPayMin. We sign every webhook with your webhook secret.
Never process webhooks without verifying the signature. Attackers can forge requests to your endpoint.
import crypto from 'crypto';
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// In your webhook handler
app.post('/webhooks/callpaymin', (req, res) => {
const signature = req.headers['x-callpaymin-signature'];
const isValid = verifyWebhookSignature(
JSON.stringify(req.body),
signature,
process.env.WEBHOOK_SECRET
);
if (!isValid) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process the webhook...
res.status(200).json({ received: true });
});Handle Retries Gracefully
CallPayMin retries failed webhooks (5xx errors or timeouts) with exponential backoff. Make your handlers idempotent to handle duplicate deliveries.
// Store processed event IDs to prevent duplicates
const processedEvents = new Set();
app.post('/webhooks/callpaymin', async (req, res) => {
const eventId = req.body.id;
// Check if already processed
if (processedEvents.has(eventId)) {
return res.status(200).json({ received: true, duplicate: true });
}
// Process the event
await handleEvent(req.body);
// Mark as processed
processedEvents.add(eventId);
res.status(200).json({ received: true });
});Best Practices Checklist
- Always verify signatures - Never skip signature verification
- Return 200 quickly - Acknowledge receipt before processing
- Use a queue - Process events asynchronously for reliability
- Make handlers idempotent - Handle duplicate deliveries gracefully
- Use HTTPS only - We only send webhooks to HTTPS endpoints
- Log everything - Keep audit logs for debugging
Configure Webhooks
Set up your webhook endpoint in the Webhooks Dashboard. You can configure which events to receive and test your endpoint before going live.