Sync Your Calls with the API
Your own software can follow every call: a webhook that fires as calls happen, a paged call history for backfilling and reconciling, recordings and transcriptions fetched by call identifier, and click-to-call from your CRM. Endpoints, headers, curl examples and a sync pattern that survives an outage.
What you can do
The Private Integrations API lets your own software work with your Zonitel calls: receive an event as calls happen, pull call history on a schedule, fetch the recording and the transcription of a call, and place a call from a button in your CRM. Every request in this guide runs against https://api.zonitel.com/api/v3.
If you have not created an access credential yet, start with the Private Integrations guide and come back here.
Before you start
Every request carries two values from the Credentials tab in Settings > Private Integrations: your token and your Client identifier. They travel as headers.
Authorization: Bearer YOUR_TOKEN
X-Client-Id: YOUR_CLIENT_ID
Accept: application/json
Full parameter and response details for every endpoint are in the interactive API reference, and a ready-made Postman collection is linked from the Overview tab of the same screen.
Two ways to get calls into your system
Webhook: pushed to you, in real time
You register one URL and we post an event to it as calls happen. The documented payload carries the caller name, the caller number and the number that was dialled, which is enough to pop a screen or look the caller up before anyone picks up. Your server has five seconds to answer HTTP 200, and the address has to be HTTPS and reachable from the internet. Incoming Call Webhooks sets out the payload and the error responses in detail.
Call history: pulled by you, on demand
A paged, date-filtered list of past calls. The webhook tells you a call is starting; history is where the finished picture lives, and where you find the identifier a recording or a transcription is addressed by. Use it to backfill when you first connect and to reconcile afterwards: if your endpoint was unreachable for an hour, history is how you recover what you missed. Most integrations run both.
There is no endpoint that lists calls currently in progress. Anything real time reaches your own system through the webhook. If what you actually want is a live view for your staff rather than data in your software, that already exists in the portal and is covered in Active Panel-Calls.
Register your calls webhook
From the portal
Go to Settings > Private Integrations and open the Webhooks tab. Paste your address in the Calls field and save. Your URL has to be live before you save it: we test it, and if it does not answer with HTTP 200 the save is rejected. To stop receiving events, clear the field and save again.
From the API
curl --request PUT \
--url https://api.zonitel.com/api/v3/integrations/calls/webhooks \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'X-Client-Id: YOUR_CLIENT_ID' \
--header 'Content-Type: application/json' \
--data '{"url": "https://yoursite.com/webhook/calls"}'
The same path answers GET, which returns the URL currently registered, and DELETE, which removes it.
What your endpoint has to do
- Answer HTTP 200 within five seconds. Acknowledge the event first and do your processing afterwards in a queue.
- Tolerate repeats. Key each event on the call identifier and ignore one you have already stored.
- Stay reachable over HTTPS at a public address.
The fields you receive and the error responses we expect back are set out in Incoming Call Webhooks. If you want to watch one arrive, point the webhook at a request-logging URL for a few minutes and place a test call.
Pull call history
Call history is paged and filtered by date. The date format is YYYY-MM-DD HH:MM:SS.
curl --get \
--url 'https://api.zonitel.com/api/v3/integrations/calls' \
--data-urlencode 'page=1' \
--data-urlencode 'limit=25' \
--data-urlencode 'fromDate=2026-08-01 00:00:00' \
--data-urlencode 'toDate=2026-08-20 23:59:59' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'X-Client-Id: YOUR_CLIENT_ID' \
--header 'Accept: application/json'
Use URL encoding for date values containing spaces. The history response includes totalItemCount, currentPage, itemNumberPerPage and items. Store each row’s xmlCdrUuid for follow-up requests. Optional filters include direction, status, extensionUuid and recording; see the API reference for allowed values.
A sync pattern that survives an outage
- On first connection, walk the pages from your chosen start date until a page comes back short. Raise
limitto move faster, and keep each window to a period you can retry cheaply. - After the backfill, let the webhook carry the day-to-day traffic.
- Once a night, re-pull the last twenty-four to forty-eight hours anyway and discard what you already have. The overlap costs almost nothing and closes any gap left by a webhook your server refused.
- Store each call identifier. Recordings and transcriptions are addressed by it, and it is what makes the deduplication above work.
Fetch a recording or a transcription
Both are addressed by the call identifier, named xmlCdrUuid in the API. You get it from a webhook event or from a history row.
curl --request GET \
--url https://api.zonitel.com/api/v3/integrations/calls/CALL_UUID/stream \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'X-Client-Id: YOUR_CLIENT_ID' \
--output call.wav
The transcription endpoint returns a JSON object containing the text and its processing state.
curl --request GET \
--url https://api.zonitel.com/api/v3/integrations/calls/CALL_UUID/transcription \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'X-Client-Id: YOUR_CLIENT_ID' \
--header 'Accept: application/json'
Check status and isReady before using the transcript. A call still being processed can return HTTP 200 with status: "processing" and an empty segments list. When ready, use text, textWithRoles, or the structured segments with role, content, beginOffsetMillis and endOffsetMillis.
HTTP 403 means transcription is not enabled for the account. Enabling it applies to calls from that point forward; it does not create transcripts for earlier calls. HTTP 404 can mean the call was not found or has no transcription.
Both depend on the call having been captured in the first place. Audio exists only for extensions set to record, and a transcription exists only where transcription is switched on for your account, which is covered in Call Transcription Insights. Expect a transcription to appear a short while after the call ends rather than instantly.
Place a call from your own app
This is what a click-to-call button in a CRM is built on. The request triggers a call between one of your extensions and a destination, which can be an outside number or another extension.
curl --request POST \
--url https://api.zonitel.com/api/v3/integrations/calls/initiate \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'X-Client-Id: YOUR_CLIENT_ID' \
--header 'Content-Type: application/json' \
--data '{"originExtension": "101", "destinationNumber": "13055550123", "destinationName": "Acme Dental"}'
originExtension is the extension that places the call, destinationNumber is the number or extension being reached, and destinationName is the label that travels with it. Put an extension number in destinationNumber and you have an internal call instead.
Supporting lookups
Three read-only endpoints help you map your records to ours: /integrations/extensions lists the extensions on your account, /integrations/extensions/report returns a summary for them, and /integrations/numbers lists your phone numbers. Fetch these once, cache them, and refresh when your account changes.
Good practice
- Issue a separate credential for each system you connect. When one has to be revoked you disable a single integration instead of all of them.
- Keep tokens out of repositories and out of front-end code. If one is exposed, revoke it from the Credentials tab and issue another.
- Retry failed requests with a growing delay rather than in a tight loop.
- Log the call identifier alongside your own record identifier. Every follow-up request depends on it.
Messaging has its own guide: Send and Receive SMS with the API.
Need help?
Call/Text/WhatsApp: (833) 966-4835
Email: info@zonitel.com