Subscribe to call lifecycle events instead of polling. We POST signed JSON to your endpoint for each event. Each event is sent once with a 5-second timeout and is not retried, so poll the call logs API to reconcile anything you miss. When a signing secret is set, every request carries an X-Edesy-Signature HMAC SHA-256 header for verification.
Configure your webhook endpoint URL on the portal.
Events#
| Event | Description |
|---|---|
session.created |
A masking session pairing two parties was created. |
call.incoming |
A call arrived on a masked number. |
call.connected |
The two parties are connected. |
call.ended |
The call ended. Includes duration. |
call.missed |
The call was not answered. |
session.expired |
The session reached its expiry or call limit. |
There is one event endpoint per account. Click-to-call results and recordings are read from the call logs and recording APIs.
Sample payload (call.ended)#
{
"event": "call.ended",
"call_sid": "d28be7cd-9840-4b23-9627-199f1ef81fc6",
"data": {
"caller_number": "917969002802",
"target_number": "9876543210",
"masked_number": "917969002802",
"direction": "click_to_call",
"status": "completed",
"started_at": "2026-05-11T08:30:00Z",
"answered_at": "2026-05-11T08:30:08Z",
"ended_at": "2026-05-11T08:31:42Z",
"duration_sec": 94,
"bill_duration_sec": 120,
"price": 3.0,
"recording_url": "recordings/2026/05/11/d28be7cd.wav"
}
}
Verifying signatures#
Each request includes an X-Edesy-Signature header: an HMAC SHA-256 of the raw request body using your webhook signing secret (from the portal). Recompute the HMAC on your side and compare it to the signature header before trusting the payload. Always respond with a 2xx status quickly; do any heavy processing asynchronously, because a delivery that times out is not sent again.