Calling
Inbound and outbound WhatsApp voice calling
Calling
WhatsApp Business Calling lets customers place a voice call to your business number from inside the WhatsApp chat. Zernio bridges the call to a destination you choose: a regular phone number, a SIP endpoint, or an AI voice agent (Vapi, Retell, or any WebSocket media server). Both inbound (customer calls you) and outbound (you call the customer) are supported.
Calling is available on the Usage plan only, so it requires usage-based billing to be active on your account. Zernio bills the carrier connection (plus an optional recording surcharge) at cost with zero markup; Meta bills its per-minute outbound rate directly to your WABA (see Pricing & Costs).
Outbound is restricted by country and messaging tier. Meta blocks business-initiated calls on numbers registered in the US, Canada, Egypt, Vietnam, and Nigeria. Inbound calls to those numbers still work. For outbound elsewhere, Meta's production guidance requires the number to be at the 2,000-recipient daily messaging tier (TIER_2K); below that, outbound may be rate-limited by Meta.
Get Calling Config
Read the current calling state for a connected number. Returns the phoneNumberDocId you need for the enable/update/disable calls, along with the forwarding destination and recording flag.
const { data } = await zernio.whatsappcalling.getWhatsAppCallingConfig({
query: { accountId: 'YOUR_ACCOUNT_ID' }
});
console.log(data.phoneNumberDocId, data.callingEnabled, data.forwardTo);response = client.whatsapp_calling.get_whats_app_calling_config(account_id='YOUR_ACCOUNT_ID')
print(response['phoneNumberDocId'], response['callingEnabled'], response['forwardTo'])curl "https://zernio.com/api/v1/whatsapp/calling?accountId=YOUR_ACCOUNT_ID" \
-H "Authorization: Bearer YOUR_API_KEY"Enable Calling
Turn calling on for a number and set the forwarding destination. The id in the path is the phoneNumberDocId from the config call above. forwardTo accepts tel:+E164 (phone), sip:... (SIP endpoint), or wss://... (WebSocket media server / AI agent).
const { data } = await zernio.whatsappcalling.enableWhatsAppCalling({
path: { id: 'PHONE_NUMBER_DOC_ID' },
body: {
accountId: 'YOUR_ACCOUNT_ID',
forwardTo: 'tel:+13105551234',
recordingEnabled: false,
}
});
console.log('Calling enabled:', data.callingEnabled);response = client.whatsapp_calling.enable_whats_app_calling(
id='PHONE_NUMBER_DOC_ID',
account_id='YOUR_ACCOUNT_ID',
forward_to='tel:+13105551234',
recording_enabled=False,
)
print('Calling enabled:', response['callingEnabled'])curl -X POST "https://zernio.com/api/v1/whatsapp/phone-numbers/PHONE_NUMBER_DOC_ID/calling" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"accountId": "YOUR_ACCOUNT_ID", "forwardTo": "tel:+13105551234", "recordingEnabled": false}'Recording is off by default. When recordingEnabled is true, a consent prompt plays before recording starts, and recording adds a small per-minute surcharge to what Zernio bills (the carrier connection).
To change the destination or recording flag later, use updateWhatsAppCalling (PATCH) with the same path id. To turn calling off, use disableWhatsAppCalling (DELETE) with the accountId query param; the forwarding destination is preserved so you can re-enable without reconfiguring.
Check Call Permission
Before placing an outbound call, confirm the consumer has granted call permission. WhatsApp requires the customer to opt in; the response tells you whether you can start a call now or must first request permission.
const { data } = await zernio.whatsappcalling.getWhatsAppCallPermissions({
query: { accountId: 'YOUR_ACCOUNT_ID', to: '+13105551234' }
});
console.log(data.permission.status); // 'permanent' | 'temporary' | 'no_permission'response = client.whatsapp_calling.get_whats_app_call_permissions(
account_id='YOUR_ACCOUNT_ID',
to='+13105551234',
)
print(response['permission']['status']) # 'permanent' | 'temporary' | 'no_permission'curl "https://zernio.com/api/v1/whatsapp/call-permissions?accountId=YOUR_ACCOUNT_ID&to=%2B13105551234" \
-H "Authorization: Bearer YOUR_API_KEY"Place an Outbound Call
Dial a consumer. The call bridges to the number's configured forwardTo destination unless you pass an override. Only accountId and to are required.
const { data } = await zernio.whatsappcalling.initiateWhatsAppCall({
body: { accountId: 'YOUR_ACCOUNT_ID', to: '+13105551234' }
});
console.log(data.callId, data.status); // '...', 'dialing'response = client.whatsapp_calling.initiate_whats_app_call(
account_id='YOUR_ACCOUNT_ID',
to='+13105551234',
)
print(response['callId'], response['status']) # '...', 'dialing'curl -X POST "https://zernio.com/api/v1/whatsapp/calls" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"accountId": "YOUR_ACCOUNT_ID", "to": "+13105551234"}'List Call History
Fetch past calls for a number, with optional filters by status, direction, and date range. Each call carries its duration, end reason, recording URL (if enabled), and a billing breakdown.
const { data } = await zernio.whatsappcalling.listWhatsAppCalls({
query: { accountId: 'YOUR_ACCOUNT_ID', direction: 'inbound', limit: 50 }
});
// billing.billableCostUSD is what Zernio charges (carrier connection +
// recording). Meta's per-minute outbound rate is billed by Meta directly to
// your WABA and is reported separately as billing.metaCostUSD (display only).
data.calls.forEach(c => console.log(c.direction, c.status, c.durationSeconds, c.billing?.billableCostUSD));response = client.whatsapp_calling.list_whats_app_calls(
account_id='YOUR_ACCOUNT_ID',
direction='inbound',
limit=50,
)
# billing.billableCostUSD is what Zernio charges (carrier connection +
# recording). Meta's per-minute outbound rate is billed by Meta directly to
# your WABA and is reported separately as billing.metaCostUSD (display only).
for c in response['calls']:
print(c['direction'], c['status'], c.get('durationSeconds'), c.get('billing', {}).get('billableCostUSD'))curl "https://zernio.com/api/v1/whatsapp/calls?accountId=YOUR_ACCOUNT_ID&direction=inbound&limit=50" \
-H "Authorization: Bearer YOUR_API_KEY"