List all calls (unified history)
Unified call history across ALL of your numbers: both channels
(WhatsApp Business Calling + regular phone/PSTN), inbound and outbound,
newest first. Unlike GET /v1/voice/calls (PSTN-only) and
GET /v1/whatsapp/calls (one account at a time), this endpoint needs no
accountId and never requires fanning out one request per number.
Any row can be opened channel-agnostically via GET /v1/calls/{id} and
GET /v1/calls/{id}/recording; no branching on channel needed. When
the counterparty number matches a CRM contact, contactId and
contactName are set.
Cursor pagination: pass the returned nextCursor as before to fetch
the next page. nextCursor is null on the last page.
Authorization
bearerAuth API key authentication: send your Zernio API key in the Authorization header, prefixed with Bearer.
In: header
Query Parameters
Value in
- "whatsapp"
- "pstn"
Value in
- "ringing"
- "answered"
- "ended"
- "failed"
Value in
- "inbound"
- "outbound"
Exact filter: calls involving this number (typically one of YOUR numbers, to scope history to a single line). E.164, leading + optional.
Free-text match on the from/to numbers. Non-digits are stripped, so partial queries like 302 or +1 302 work.
Return calls with startedAt strictly before this instant (use the previous page's nextCursor).
date-time1 <= value <= 20050Response Body
application/json
application/json
import Zernio from '@zernio/node';const zernio = new Zernio({ apiKey: process.env.ZERNIO_API_KEY });const { data } = await zernio.calls.listCalls();console.log(data);{ "calls": [ { "_id": "string", "accountId": "string", "conversationId": "string", "contactId": "string", "channel": "whatsapp", "direction": "inbound", "from": "string", "to": "string", "forwardTo": "string", "greeting": "string", "status": "ringing", "isVoicemail": true, "amd": true, "answeredMachine": true, "forwardCallerId": "business", "recordingEnabled": true, "transcriptionEnabled": true, "transcriptionLanguage": "auto", "startedAt": "2019-08-24T14:15:22Z", "answeredAt": "2019-08-24T14:15:22Z", "endedAt": "2019-08-24T14:15:22Z", "transferredAt": "2019-08-24T14:15:22Z", "durationSeconds": 0, "endReason": "hangup", "hangupCause": "string", "sipHangupCause": "string", "callErrors": [ { "code": 0, "message": "string" } ], "recordingUrl": "string", "lastTranscriptSnippet": "string", "transcript": [ { "text": "string", "confidence": 0, "at": "2019-08-24T14:15:22Z" } ], "billing": { "metaMinutes": 0, "telnyxSeconds": 0, "transcriptionSeconds": 0, "transcriptionCostUSD": 0, "metaCostUSD": 0, "telnyxCostUSD": 0, "recordingCostUSD": 0, "billableCostUSD": 0, "totalCostUSD": 0, "currency": "string" }, "createdAt": "2019-08-24T14:15:22Z", "updatedAt": "2019-08-24T14:15:22Z", "contactName": "string" } ], "nextCursor": "2019-08-24T14:15:22Z"}Create a caller identity share link
Creates a single-use link (valid 7 days) where the end business fills in the caller identity itself, with no Zernio login: display name, logo, call reasons, the authorizer and the three references. What it submits lands under your team as `requested`, the same review as an API submission, and `branded_calling.identity.status_updated` fires. Scope the link with `identityId` (complete an identity that is `requested` or `changes_requested`), with `enterpriseId` (a new identity for a registered business), or with neither (the business registers itself and its first identity). The person opening the link can forward a fresh one to someone else, which retires theirs.
Get a call recording
Channel-agnostic recording fetch: resolves a fresh, playable MP3 URL for any call regardless of channel (provider-signed URLs expire ~10 minutes after signing, so this re-signs on demand). Default responds `302 Found` redirecting to the fresh URL; pass `as=json` to receive `{ url }` instead.