Call Webhooks: Inbound and Outbound Calls
Receive call-event notifications for inbound and outbound calls. Learn to configure the Calls webhook, handle call.inbound, call.outbound and call.completed, and log calls after they finish using the completed-call payload.
The simple way: set it in the portal
You do not need to call the API to register a call webhook. It can be set from the portal directly.
- Log in to your Zonitel Office Portal.
- In the left sidebar, expand Settings and click Private Integrations.
- Open the Webhooks tab.
- Under Calls webhook, paste your Webhook URL.
- Click Save.
Zonitel sends notifications when an inbound call reaches the system, when an extension places an outbound call, and after a call finishes. Completed-call notifications cover inbound and outbound calls. The URL has to be valid and answer with HTTP 200 to be saved — if it does not respond correctly it is not stored, so bring your endpoint up first. To remove it later, clear the field and save again.
One URL for call events: inbound, outbound and completed-call notifications use the same Calls webhook URL. There is no separate outbound webhook field or outbound switch in Office.
The rest of this article covers the API method, for setting webhooks programmatically.
Advanced: method and receiver authentication
- Open Advanced under the webhook URL and enable Use a custom method or authentication.
- Choose the HTTP method and Authentication your receiving service requires. Methods: POST, PUT, PATCH or GET. Authentication: None, Bearer token, API key, Basic (user + password) or Custom header.
- Complete the fields shown for that choice and save the webhook. The receiving URL must respond with HTTP 200 for the portal to accept it.
POST with no authentication is the default. GET has no request body; the event travels as query parameters. For API key, select where to send it and enter the header or parameter name required by your receiver.
The optional receiver credentials belong to the service receiving the webhook. They are separate from the Zonitel API token and X-Client-Id used when your software calls our API. Only provide credentials intended for that receiver.
The API registration example below configures the URL. Use the portal for the Advanced options shown here.
How It Works
- Register a Calls webhook URL for your client account through the portal or API.
- Zonitel sends call-event notifications to that URL. The Calls webhook covers inbound and outbound calls; see the available events below.
- Your endpoint must respond with HTTP 200 OK within 5 seconds to acknowledge each notification. POST is the default method; use Advanced in the portal if your receiver requires another supported method or authentication.
Important: The webhook URL must use HTTPS and be publicly accessible.
Available call events
call.inbound— Sent when an inbound call reaches the system. Use it to show the caller or start a record while the call is in progress.call.outbound— Sent when an extension places a call that the phone system classifies as outbound, when the call is placed and before it is answered. This includes external numbers and the cross-domain or forwarding cases described below. Use it to open or pre-fill a record while the call is in progress. It does not confirm that the call was answered; completion details arrive later incall.completed.call.completed— Sent after a call has finished. This event covers inbound and outbound calls; thedirectionfield identifies the direction. Completed-call notifications may also identifylocalcalls.
Log calls only after they finish
To create or update your CRM call log after completion, have your receiving integration process notifications where event_type is call.completed. Acknowledge the other notifications with HTTP 200, but do not use them to create a completed-call log. This filtering is handled in your receiving integration.
Use the completed-call id to correlate or update the record, and use the timestamps, duration and call flags from that notification. For call history, recordings and transcriptions, follow Sync Your Calls with the API.
call.inbound and call.outbound report that a call started, even if it is never answered. Do not use them to create a completed-call log.
Timing: call.outbound is generated when the number is dialed. call.completed is generated when the call detail record (CDR) is imported, which may be some time after hangup. Do not expect both events to arrive immediately one after the other.
When call.outbound is sent
- A user's desk phone, softphone or mobile app dials an external number.
- The start event is generated once per call, including when routing retries a backup carrier. This is not an exactly-once delivery guarantee; design your receiver to handle retries safely.
- Unanswered and cancelled calls are included because the event is generated when the call is placed.
- Emergency calls (911) also generate the event. Never place an emergency call to test a webhook.
When call.outbound is not sent
- Direct internal calls between extensions in the same account/domain. These are classified as
localand do not generatecall.outbound. If the called extension forwards to a cell phone, see the exception below. - Inbound calls forwarded to an external number, including call forwarding, follow me and ring groups that ring a cell phone. Their outbound legs can still generate
call.completedwithdirectionset tooutbound. - Faxes sent from the portal.
Cross-domain extensions and cell-phone forwarding
- Extensions in different domains: a call between extensions in separate accounts/domains can generate
call.outboundwhen its route is classified as outbound, even if both domains belong to the same organization. In this case,destination_numbercan be a short extension such as401or102, rather than a public phone number. - An extension forwards to a cell phone: calling an extension that forwards to a cell phone can also generate
call.outboundfor the outbound routing. Do not assume that every call initially dialed to an extension is excluded.
These distinctions describe call.outbound only. They do not establish whether call.completed is sent for the same call. Do not infer completed-event behavior from the outbound start-event filter.
Outbound start-event availability depends on your account's phone-system deployment. If you receive completed events but no outbound start events, contact Zonitel Support to confirm availability.
Register a Webhook URL
Endpoint:
Request Body (JSON):
Notes:
-
URL must be HTTPS and reachable from the public internet.
-
Must respond with HTTP 200 OK within 5 seconds.
Success Response (200 OK):
Retrieve Registered Webhook
Endpoint:
Example Response (200 OK):
Webhook payload examples
These are notifications received by your endpoint, not the body used to register the webhook. The examples below show the default POST delivery.
Inbound call starts: call.inbound
{
"event_type": "call.inbound",
"caller_id_name": "John Smith",
"caller_id_number": "13055550123",
"destination_number": "13055550999",
"direction": "inbound"
}
Outbound call starts: call.outbound
{
"event_type": "call.outbound",
"caller_id_name": "Example Company",
"caller_id_number": "13055550999",
"destination_number": "3055550123",
"direction": "outbound"
}
The current outbound notification does not include id or extension. Do not rely on a shared identifier to join it to call.completed. Use the completed-call id for the final call record.
Call finishes: call.completed
This example is an outbound call. An inbound completed call uses the same event type with direction set to inbound.
{
"event_type": "call.completed",
"id": "a3c24a95-8e47-4ce7-a7a5-f46197b185bd",
"caller_id_name": "Example Company",
"caller_id_number": "13055550999",
"destination_number": "3055550123",
"destination_name": "John Smith",
"duration": "42",
"is_missed_call": false,
"has_voicemail": false,
"start_stamp": {
"date": "2026-10-13 18:30:00.000000",
"timezone_type": 1,
"timezone": "+00:00"
},
"answer_stamp": {
"date": "2026-10-13 18:30:04.000000",
"timezone_type": 1,
"timezone": "+00:00"
},
"end_stamp": {
"date": "2026-10-13 18:30:46.000000",
"timezone_type": 1,
"timezone": "+00:00"
},
"direction": "outbound"
}
Payload fields
event_type: Identifies the notification:call.inbound,call.outboundorcall.completed.id: Call identifier incall.completed; it is not included in the currentcall.outboundnotification.caller_id_nameandcaller_id_number: Caller identification. Incall.outbound, these are the caller ID sent to the carrier (the company caller ID), not the extension number.destination_numberanddestination_name: Destination number and name, when supplied. Incall.outbound,destination_numberis the number as dialed; its format may vary (for example, 10 digits, 11 digits or an international number with 011). It can also be a short extension for cross-domain calls classified as outbound. Preserve it as a string; do not assume a fixed length or a public phone number.direction: Call direction; completed calls may beinbound,outboundorlocal.duration: Reported call duration in seconds.is_missed_callandhas_voicemail: Indicate a missed call and voicemail.start_stamp,answer_stampandend_stamp: Call timestamps, including their timezone information when supplied.
Common Error Responses
-
401 Unauthorized
-
403 Forbidden
-
404 Not Found
-
500 Internal Server Error
Best Practices
-
Always use HTTPS for your webhook URLs.
-
Respond with HTTP 200 OK within 5 seconds to acknowledge the call event.
-
Keep your Bearer token secure.
-
Ensure your webhook endpoint can handle multiple concurrent calls.
Remove a Registered Webhook
Send DELETE to the same address to stop receiving events. Clearing the Calls field on the Webhooks tab of Settings > Private Integrations does the same thing.
DELETE https://api.zonitel.com/api/v3/integrations/calls/webhooks
Going further
Registering the webhook is one half of a call integration. Pulling call history, downloading recordings and transcriptions, and placing calls from your own app are covered in Sync Your Calls with the API.
Need help?
Call/Text/WhatsApp: (833) 966-4835
Email: info@zonitel.com