Webhooks
Receive real-time event notifications via webhooks.
Webhooks let your application receive real-time HTTP notifications when events happen in ErzyCall — such as a call ending, a contact being created, or a call failing.
How It Works
- You register a webhook endpoint URL in ErzyCall (via the API or dashboard).
- When a subscribed event occurs, ErzyCall sends a
POSTrequest to your URL with the event payload. - Your server verifies the signature and processes the event.
Available Events
| Event | Trigger |
|---|---|
call.started | An outbound call was initiated |
call.ended | A call completed (status: "ended") |
call.failed | A call ended on a provider or pipeline error (status: "error") |
call.scheduled | A call was scheduled for later |
call.cancelled | A scheduled call was cancelled |
contact.created | A new contact was created |
contact.updated | A contact was modified |
contact.deleted | A contact was deleted |
Every call fires exactly one of call.ended or call.failed when it finishes,
never both — subscribe to both events if you want to hear about every outcome.
Test calls placed from the dashboard fire neither.
Webhook Payload
Each delivery is a POST request with a JSON body:
{
"event": "call.ended",
"timestamp": "2025-01-15T10:30:00.000Z",
"data": {
"id": "abc123",
"status": "ended",
"direction": "inbound",
"callTo": "+14155551234",
"callFrom": "+14155559999",
"endedReason": "customer-ended-call",
"durationSeconds": 45,
"recordingUrl": "https://...",
"createdAt": "2025-01-15T10:29:15.000Z",
"updatedAt": "2025-01-15T10:30:00.000Z"
}
}data is the same call object returned by GET /api/v1/calls/:id, minus the
transcript field — see Calls for every field, and
fetch that endpoint when you need the conversation.
Signature Verification
Every webhook delivery is signed with your endpoint's secret using HMAC-SHA256. Always verify the signature before processing the payload.
The signature is sent in the X-Webhook-Signature header, alongside the unix
timestamp it was computed with:
X-Webhook-Signature: t=1736937000,v1=<hex-encoded HMAC>The signed string is <timestamp>.<raw request body>.
Verification Example (Node.js)
import crypto from "crypto";
function verifyWebhookSignature(payload, signature, secret) {
const [t, v1] = signature.split(",").map((part) => part.split("=")[1]);
const expected = crypto
.createHmac("sha256", secret)
.update(`${t}.${payload}`)
.digest("hex");
return crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
}
// In your webhook handler:
app.post("/webhook", (req, res) => {
const signature = req.headers["x-webhook-signature"];
const payload = JSON.stringify(req.body);
if (!verifyWebhookSignature(payload, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send("Invalid signature");
}
// Process the event
const { event, data } = req.body;
console.log(`Received ${event}:`, data);
res.status(200).send("OK");
});Managing Endpoints
Via the API
# Create a webhook endpoint
curl -X POST "https://app.erzycall.com/api/v1/webhooks" \
-H "X-API-Key: ek_live_abc123" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhook",
"events": ["call.ended", "contact.created"],
"description": "My production webhook"
}'The response includes a secret field — save this for signature verification:
{
"data": {
"id": "wh_abc123",
"url": "https://your-app.com/webhook",
"events": ["call.ended", "contact.created"],
"secret": "whsec_...",
"isActive": true,
"description": "My production webhook"
}
}Via the Dashboard
Navigate to Settings > API Keys > Webhooks tab to create and manage webhook endpoints through the UI.
Retry Behavior
If your endpoint returns a non-2xx status code or times out, ErzyCall retries the delivery up to 3 times with exponential backoff (delays of approximately 10s, 60s, and 300s).
Auto-Disable
If an endpoint fails 10 consecutive deliveries, it is automatically disabled. You can re-enable it from the dashboard or by updating the endpoint via the API:
curl -X PATCH "https://app.erzycall.com/api/v1/webhooks/{id}" \
-H "X-API-Key: ek_live_abc123" \
-H "Content-Type: application/json" \
-d '{"isActive": true}'Rotating Secrets
To rotate the signing secret for an endpoint:
curl -X POST "https://app.erzycall.com/api/v1/webhooks/{id}/rotate-secret" \
-H "X-API-Key: ek_live_abc123"The response contains the new secret. Update your verification code immediately — the old secret stops working right away.
Limits
- Maximum 5 webhook endpoints per organization.
- Maximum 10 events per endpoint.
- Webhook URLs must use HTTPS.
Best Practices
- Always verify signatures to ensure the payload came from ErzyCall.
- Respond quickly with a
200status. Process the event asynchronously if needed. - Handle duplicate deliveries — use the event data to deduplicate (e.g., by call ID).
- Monitor your endpoint — if deliveries start failing, check your logs before the endpoint gets auto-disabled.