What This Page Covers
Three ways to surface WhatsApp calling to your customers:
- Interactive
voice_callmessage — free-form message during an open CSW with a "Call on WhatsApp" button. voice_calltemplate button — same UX, but as a template button so you can send outside an open CSW.wa.me/call/<BUSINESS_PHONE_NUMBER>deep link — shareable link you embed on your website, app, QR code, or in WhatsApp messages themselves.
All three trigger a user-initiated call when tapped, so your endpoint receives a Call Connect webhook with direction: USER_INITIATED. The button/link can also carry a payload string that's echoed back on the call webhooks (cta_payload for buttons, deeplink_payload for deep links).
Interactive voice_call Message (Free-Form)
Send during an open CSW (or any open conversation window). Standard message-status webhook fires.
POST /<PHONE_NUMBER_ID>/messages
{
"messaging_product": "whatsapp",
"recipient_type": "individual",
"to": "12015550123",
"type": "interactive",
"interactive": {
"type": "voice_call",
"body": {
"text": "You can call us on WhatsApp now for faster service!"
},
"action": {
"name": "voice_call",
"parameters": {
"display_text": "Call on WhatsApp",
"ttl_minutes": 100,
"payload": "support_v2_button"
}
}
}
}
| Field | Default | Notes |
|---|---|---|
display_text | "Call Now" | Max 20 chars |
ttl_minutes | 10080 (7 days) | 1 to 43200 (30 days) — button stops working after this |
payload | — | Up to 512 chars. Echoed back on call webhooks as cta_payload. Cloud API doesn't process it. |
Sending to users on older app versions returns error 131026.
voice_call Template Button
Use a template if you want to send outside a CSW or want the message reusable. The button can sit alongside other template buttons (URL, etc.).
Create the template:
POST /<WABA_ID>/message_templates
{
"name": "wa_voice_call",
"category": "MARKETING",
"language": "en",
"components": [
{
"type": "BODY",
"text": "You can call us on WhatsApp now for faster service!"
},
{
"type": "BUTTONS",
"buttons": [
{
"type": "voice_call",
"text": "Call Now",
"ttl_minutes": 1440
},
{
"type": "URL",
"text": "Contact Support",
"url": "https://example.com/support"
}
]
}
]
}
Template button-level ttl_minutes ranges from 1440 (1 day) to 43200 (30 days). The free-form message TTL minimum is 1 minute — templates require a higher floor.
The send-time TTL can override the template-level value.
Send the Template
POST /<PHONE_NUMBER_ID>/messages
{
"to": "12015550123",
"messaging_product": "whatsapp",
"type": "template",
"recipient_type": "individual",
"template": {
"name": "wa_voice_call",
"language": { "code": "en" },
"components": [
{
"type": "button",
"sub_type": "voice_call",
"parameters": [
{ "type": "ttl_minutes", "ttl_minutes": 100 },
{ "type": "payload", "payload": "campaign_q4_winback" }
]
}
]
}
}
Per-send ttl_minutes ranges from 1 to 43200 (default 10080). payload (max 512 chars) is echoed as cta_payload on call webhooks.
Calling Deep Links (wa.me/call)
Deep links route a click directly into a WhatsApp call to your business. Format:
wa.me/call/<BUSINESS_PHONE_NUMBER>
Example: wa.me/call/15550783881
Use them anywhere a clickable URL fits — your website, in-app links, email signatures, QR codes for printed materials. Since they're per-business-phone-number, you can send a deep link inside a WhatsApp message to point users at a different business phone number than the one they're chatting with.
Note: Deep links are not supported on WhatsApp Desktop clients. They work on Android and iOS WhatsApp apps.
Deep Link Payloads (biz_payload)
Append a biz_payload query string to attach an arbitrary tracking string:
wa.me/call/15550783881?biz_payload=campaign_winter_2026
The payload comes back as deeplink_payload on the Call Connect and Terminate webhooks. Cloud API doesn't process it.
Available on WhatsApp client version 2.25.27 or later.
Where Payloads Arrive in Webhooks
Both cta_payload (from buttons) and deeplink_payload (from deep links) appear on the calls[] object in:
- The Call Connect webhook for the user-initiated call
- The Call Terminate webhook for the same call
Use them to attribute calls back to the campaign / page / button / template that drove them.
"calls": [
{
"id": "wacid.HBgL...",
"direction": "USER_INITIATED",
"event": "connect",
"cta_payload": "support_v2_button",
"deeplink_payload": "campaign_winter_2026"
}
]
If a call originated from a button: cta_payload set, deeplink_payload absent. Deep link: vice versa. Native call (call icon, contact-app dial): both absent.
For SIP setups, the same payloads come through as custom SIP headers x-wa-meta-cta-payload and x-wa-meta-deeplink-payload on the INVITE.
Client Version Requirements
| Feature | Min WhatsApp client version |
|---|---|
voice_call button | Android 2.24.1+ |
| Call icon visibility setting | Android & iOS 2.24.10.8+ |
payload on voice_call button (interactive + template) | 2.25.27+ |
biz_payload on wa.me/call/<num> deep link | 2.25.27+ |
| Permission requests + business-initiated calling | Android & iOS 2.24.14+ |
Sending a voice_call button to a user on an older client falls back to either no button or a different render — handle gracefully and offer a chat fallback.