Zernio
Zernio
OverviewWebhooksPost webhooksInbox webhooksAutomation webhooksSupport run webhooksAccount webhooksAnalytics webhooksAds webhooksCall webhooksWhatsApp webhooksPhone number webhooksSMS registration webhooksBranded Calling webhooks
Dashboard
llms.txtOpenAPI
OverviewPlatformsAPI ReferenceResources
Webhooks

Call webhooks

Receive an event when a call rings, ends or fails on a phone or WhatsApp number, and when a WhatsApp user answers a call-permission request.


Call events cover every call on your numbers, regular phone (PSTN) and WhatsApp, from ring to hangup. Subscribe with POST /v1/webhooks/settings and the event names below (first event). Call events need inbox access: without it that call returns a 403 with code feature_not_available, so the subscription is refused rather than silently empty. Delivery, retries and signatures are the same for every event (how webhooks behave).

Events

EventDescription
call.receivedA call was set up: an inbound call (phone or WhatsApp) reaching one of your numbers, or an outbound WhatsApp call placed through the API.
call.endedA call (phone or WhatsApp) ended; carries duration, end reason and the cost breakdown.
call.failedA call (phone or WhatsApp) failed with a hard error before or during bridging.
call.permission_requestA WhatsApp user accepted or rejected your call-permission request.

How it behaves

Which events fire, in what order

Zernio ends every call with exactly one of call.ended or call.failed. call.permission_request sits outside these sequences: it reports a reply to a permission prompt, not a call. Whether a call.received precedes the ending event depends on the direction and channel:

CallSequence
Inbound, phone or WhatsAppcall.received at ring time, then call.ended or call.failed
Outbound WhatsApp (through the API)call.received with direction: "outbound" at origination, then call.ended or call.failed
Outbound phone (API or browser softphone)call.ended or call.failed only

call.received fires at ring time

Zernio sends call.received before anyone answers. A call nobody picks up still emits it, followed by call.ended with endReason: "no_answer".

Unanswered calls end with call.ended

Zernio reports no-answer, busy and rejected calls with call.ended; branch on endReason. call.failed is reserved for hard errors before or during bridging.

Permission requests are independent of any call

Zernio sends call.permission_request when a WhatsApp user responds to a call-permission request. It gates the outbound WhatsApp row above: Meta permits a business-initiated call only after the consumer taps Allow, and the accept can land days before the call.


call.received

A call was set up on one of your numbers: an inbound call, phone (PSTN) or WhatsApp, reaching the number and routed to its configured destination (an AI voice agent, a SIP endpoint or a phone number), or an outbound WhatsApp call placed through the API, in which case direction is "outbound". The payload carries the Zernio call id, the caller and business numbers, the destination snapshot (forwardTo), and contactId and conversationId links into the inbox, so you can message the caller during or after the call with the regular send endpoints.


Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Webhook payload for the call.received event. Fires for both inbound (UIC) and outbound (BIC) calls; branch on call.direction to tell them apart.

Response Body

Example Requests

Webhook payload for the call.received event. Fires for both inbound (UIC) and outbound (BIC) calls; branch on call.direction to tell them apart.

POST/call.received


call.ended

A call (phone or WhatsApp) ended. The payload carries durationSeconds, the endReason (hangup, no_answer, rejected, error) and a cost breakdown under call.billing. When recording is enabled it also carries recordingUrl, a signed URL that expires at recordingExpiresAt; for a fresh URL later, call GET /v1/calls/{id}/recording with call.id. A missed-call follow-up is one endReason: "no_answer" check, then a text to the caller over the linked conversationId.


Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Webhook payload for the call.ended event. Fires on call hangup with the duration and a zero-markup billing breakdown.

Response Body

Example Requests

Webhook payload for the call.ended event. Fires on call hangup with the duration and a zero-markup billing breakdown.

POST/call.ended


call.failed

A call (phone or WhatsApp) failed with a hard error before or during bridging, for example the destination rejected the SIP INVITE. The payload carries the platform error code and message.


Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Webhook payload for the call.failed event. Fired when a call setup or in-progress call fails.

Response Body

Example Requests

Webhook payload for the call.failed event. Fired when a call setup or in-progress call fails.

POST/call.failed


call.permission_request

A WhatsApp user responded to your call-permission request, which business-initiated calls require. The payload carries the user's number, their response (accept or reject), whether it is permanent, and the expiry when it is not.


Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Webhook payload for the call.permission_request event. Fires when a consumer accepts or rejects an interactive call_permission_request message.

Response Body

Example Requests

Webhook payload for the call.permission_request event. Fires when a consumer accepts or rejects an interactive call_permission_request message.

POST/call.permission_request

Related

  • Webhooks: create an endpoint, retries, signatures.
  • Voice history: calls and recordings on demand.
  • WhatsApp calling: call permissions and business-initiated calls.
  • Phone numbers: provision the numbers these calls land on.
Was this page helpful?

Ads webhooks

Receive an event when an ads account finishes its first sync, when an ad account stops or resumes syncing, when a Meta Lead Gen form gets a lead, and when an ad object changes status.

WhatsApp webhooks

Receive an event when Meta reviews a WhatsApp template or display name, changes a number's quality or messaging limit, restricts or alerts on the account, when a contact's WhatsApp identity changes, and when Meta detects a lead or purchase in a Click-to-WhatsApp conversation.

On this page

EventsHow it behavesWhich events fire, in what ordercall.received fires at ring timeUnanswered calls end with call.endedPermission requests are independent of any callcall.receivedcall.endedcall.failedcall.permission_requestRelated
id*string

Stable webhook event ID: the dedupe key, also sent as the X-Zernio-Event-Id header and identical on every retry and redelivery. It identifies the event only, never an account or other resource.

event*"call.received"

Value in

  • "call.received"
call*
account*

The account context included in inbox webhook payloads.

timestamp*string

UTC time at which Zernio generated this event (set once when the event payload is built, before delivery is queued). Retries and redeliveries keep the original value, so it reflects the event, not the delivery attempt.

Formatdate-time
id*string

Stable webhook event ID: the dedupe key, also sent as the X-Zernio-Event-Id header and identical on every retry and redelivery. It identifies the event only, never an account or other resource.

event*"call.ended"

Value in

  • "call.ended"
call*
account*

The account context included in inbox webhook payloads.

timestamp*string

UTC time at which Zernio generated this event (set once when the event payload is built, before delivery is queued). Retries and redeliveries keep the original value, so it reflects the event, not the delivery attempt.

Formatdate-time
id*string

Stable webhook event ID: the dedupe key, also sent as the X-Zernio-Event-Id header and identical on every retry and redelivery. It identifies the event only, never an account or other resource.

event*"call.failed"

Value in

  • "call.failed"
call*
account*

The account context included in inbox webhook payloads.

timestamp*string

UTC time at which Zernio generated this event (set once when the event payload is built, before delivery is queued). Retries and redeliveries keep the original value, so it reflects the event, not the delivery attempt.

Formatdate-time
id*string

Stable webhook event ID: the dedupe key, also sent as the X-Zernio-Event-Id header and identical on every retry and redelivery. It identifies the event only, never an account or other resource.

event*"call.permission_request"

Value in

  • "call.permission_request"
permission*
account*

The account context included in inbox webhook payloads.

timestamp*string

UTC time at which Zernio generated this event (set once when the event payload is built, before delivery is queued). Retries and redeliveries keep the original value, so it reflects the event, not the delivery attempt.

Formatdate-time