Conversation API supports the following WhatsApp messaging entry points for voice calling:
- Sending call permission requests
- Sending call buttons
- Receiving related event callbacks
SIP (Session Initiation Protocol) is a standard way for systems to set up, manage, and end voice calls over IP networks. In practice, SIP connects platforms, including WhatsApp Calling, to your telephony stack (for example, PBX or contact center) so voice sessions can be routed to your business environment.
With this model, you can support both:
- Business-initiated calls, where your business starts the call (typically after required user permission has been obtained).
- User-initiated calls, where the user starts the call from WhatsApp (for example, by tapping a call button).
For the current alpha strategy, the supported architecture is customer-owned SIP. This is the only model we can document and support in this phase. The customer owns the SIP infrastructure, provides the SIP endpoint details during onboarding, and Meta connects directly to that SIP environment for signaling and media.
Sinch handles onboarding/configuration and forwards the relevant WhatsApp call lifecycle and permission-reply events to the customer webhook platform.
For more background on WhatsApp Calling and SIP onboarding, see Meta's documentation for Cloud API Calling.
The details of the current scope of the alpha architecture are below:
- Customer owns and operates the SIP infrastructure and telephony platform.
- Customer provides SIP server details (hostname, port, TLS, credentials, and related configuration) during Sinch-supported onboarding.
- Meta connection is configured with the customer SIP endpoint and establishes the SIP session and media path directly with the customer's SIP environment.
- Sinch handles onboarding/configuration support and forwards the relevant call lifecycle and permission-reply events to the customer webhook platform.
- Sinch does not own or proxy the media path in this phase.
The configuration process is illustrated below:
The webhook event flow is illustrated below:
The call flow is illustrated below:
With the WhatsApp channel, you can use Conversation API to:
- Send a template call permission request;
- Send a free form call permission request;
- Send a template call button message;
- Send a free form call button message;
- Optionally receive permission reply, call connect, and call terminate events on your
EVENTwebhook.
- A call permission request is used when your business wants to place a business-initiated call to the user.
- A call button message is used when you want the user to place a user-initiated call to your business from WhatsApp.
- Outside the WhatsApp customer service window, you must use an approved WhatsApp template.
To send a template-based call permission request, use a Conversation API template_message and reference an approved WhatsApp template whose interaction type in Meta is call_permission_request.
Below is an example payload:
{
"app_id": "01KX1DEK870THTWCNENESBW5DP",
"recipient": {
"identified_by": {
"channel_identities": [
{
"channel": "WHATSAPP",
"identity": "555XXXXXXXXX"
}
]
}
},
"message": {
"template_message": {
"channel_template": {
"WHATSAPP": {
"template_id": "calls_permission_request_test",
"language_code": "en"
}
}
}
}
}The actual header, body, footer, and call permission interaction are defined in the approved Meta template. If your template contains variables, populate them the same way as other WhatsApp templates. See our documentation on template messages for more information.
To send a free form call permission request during an open customer service window, use a channel_specific_message with message_type set to call_permission_request.
Below is an example payload:
{
"app_id": "01KX1DEK870THTWCNENESBW5DP",
"recipient": {
"identified_by": {
"channel_identities": [
{
"channel": "WHATSAPP",
"identity": "555XXXXXXXXX"
}
]
}
},
"message": {
"channel_specific_message": {
"WHATSAPP": {
"message_type": "call_permission_request",
"message": {
"body": {
"text": "test"
}
}
}
}
}
}The body text is optional, but Meta recommends including context so the recipient understands why your business wants permission to call.
To send a template-based call button, use template_message and reference an approved WhatsApp template whose button type in Meta is voice_call.
Below is an example payload:
{
"app_id": "01KX1DEK870THTWCNENESBW5DP",
"recipient": {
"identified_by": {
"channel_identities": [
{
"channel": "WHATSAPP",
"identity": "555XXXXXXXXX"
}
]
}
},
"message": {
"template_message": {
"channel_template": {
"WHATSAPP": {
"template_id": "call_button_test",
"language_code": "en_US"
}
}
}
}
}This message invites the user to start a voice call to your business from WhatsApp. As with other WhatsApp templates, the button definition itself is managed in Meta when the template is created and approved. See our documentation on template messages for more information.
To send a free form call button during an open customer service window, send a channel_specific_message with message_type set to voice_call.
Below is an example payload:
{
"app_id": "01KX1DEK870THTWCNENESBW5DP",
"recipient": {
"identified_by": {
"channel_identities": [
{
"channel": "WHATSAPP",
"identity": "555XXXXXXXXX"
}
]
}
},
"message": {
"channel_specific_message": {
"WHATSAPP": {
"message_type": "voice_call",
"message": {
"body": {
"text": "test"
},
"ttl_minutes": 100,
"display_text": "Voice Call",
"payload": "test"
}
}
}
}
}Use the message fields as follows:
| Field | Description |
|---|---|
body.text | Required text shown together with the call button. |
ttl_minutes | Time-to-live for the call button CTA. Defaults to 10080 (7 days). |
display_text | The text shown on the WhatsApp call button. Defaults to Call now. |
payload | Optional tracking value returned in calling events as cta_payload. |
Conversation API can transcode the relevant WhatsApp calling callbacks and deliver them to your EVENT webhook as contact_event.channel_specific_event.
In the current customer-owned SIP model, webhooks are optional and informational. They can be used for permission, connection, and termination tracking. They are not required to establish the SIP call. The actual SIP signaling and RTP media path is established directly between Meta and the customer's SIP infrastructure, not via a Sinch-managed media bridge.
When a user accepts or rejects a call permission request, you receive a whatsapp_call_permission_reply_event.
| Field | Description |
|---|---|
response | The user's decision. Expected values are accept or reject. |
is_permanent | true if the user granted permanent permission, false for temporary permission. |
expiration_timestamp | Expiration timestamp for temporary permission. Omitted for permanent permission. |
Below is an example with temporary permission:
{
"app_id": "01KX1DEK870THTWCNENESBW5DP",
"event_time": "2026-08-28T14:05:28Z",
"project_id": "2cb92b1b-2faf-40be-9380-accec4f24f46",
"event": {
"direction": "TO_APP",
"contact_event": {
"channel_specific_event": {
"whatsapp_call_permission_reply_event": {
"response": "accept",
"is_permanent": false,
"expiration_timestamp": "2026-09-04T14:05:28Z"
}
}
},
"id": "01M14B18KSPNDA9VX89J6G5D6R",
"conversation_id": "",
"contact_id": "",
"channel_identity": {
"channel": "WHATSAPP",
"identity": "555XXXXXXXXX",
"app_id": ""
},
"accept_time": "2026-08-28T14:05:30.729904748Z",
"processing_mode": "DISPATCH"
},
"message_metadata": "",
"correlation_id": "",
"channel_metadata": {
"whatsapp": {
"message_type": "interactive",
"interactive_message_type": "call_permission_reply",
"profile_names": {
"555XXXXXXXXX": "John"
},
"sender_phone_number": "SENDER_phone_number",
"user_profile": {
"display_name": "John",
"username": "john_user",
"country_code": "BR",
"phone_number": "SENDER_phone_number",
"user_id": "BR.3234965106801957"
}
}
}
}Below is an example with permanent permission:
{
"app_id": "01KX1DEK870THTWCNENESBW5DP",
"event_time": "2026-08-28T13:54:59Z",
"project_id": "2cb92b1b-2faf-40be-9380-accec4f24f46",
"event": {
"direction": "TO_APP",
"contact_event": {
"channel_specific_event": {
"whatsapp_call_permission_reply_event": {
"response": "accept",
"is_permanent": true
}
}
},
"id": "01M14AE3DAA8QA0XGC4C7XNXEJ",
"conversation_id": "",
"contact_id": "",
"channel_identity": {
"channel": "WHATSAPP",
"identity": "555XXXXXXXXX",
"app_id": ""
},
"accept_time": "2026-08-28T13:55:02.791959571Z",
"processing_mode": "DISPATCH"
},
"message_metadata": "",
"correlation_id": "",
"channel_metadata": {
"whatsapp": {
"message_type": "interactive",
"interactive_message_type": "call_permission_reply",
"profile_names": {
"555XXXXXXXXX": "John"
},
"sender_phone_number": "SENDER_phone_number",
"user_profile": {
"display_name": "John",
"username": "john_user",
"country_code": "BR",
"phone_number": "555XXXXXXXXX",
"user_id": "BR.3234965106801957"
}
}
}
}When the user starts a WhatsApp voice call to your business (for example, if they used a call button), you receive a whatsapp_call_connect_event.
| Field | Description |
|---|---|
direction | The call direction. For example, USER_INITIATED. |
deeplink_payload | Payload received from a call deep link, when used. |
cta_payload | Payload received from a call button message, when used. |
sdp_type | Optional SDP type associated with the call session. |
sdp | Optional SDP content associated with the call session. |
{
"app_id": "01KX1DEK870THTWCNENESBW5DP",
"event_time": "2026-08-28T14:17:45.812211426Z",
"project_id": "2cb92b1b-2faf-40be-9380-accec4f24f46",
"event": {
"direction": "TO_APP",
"contact_event": {
"channel_specific_event": {
"whatsapp_call_connect_event": {
"direction": "USER_INITIATED",
"deeplink_payload": "",
"cta_payload": "test",
"sdp_type": "",
"sdp": ""
}
}
},
"id": "01M14BQPMMA37HYBWA2EGARM6A",
"conversation_id": "",
"contact_id": "",
"channel_identity": {
"channel": "WHATSAPP",
"identity": "555XXXXXXXXX",
"app_id": ""
},
"accept_time": "2026-08-28T14:17:46.218428897Z",
"processing_mode": "DISPATCH"
},
"message_metadata": "",
"correlation_id": "",
"channel_metadata": {
"whatsapp": {
"profile_names": {
"555XXXXXXXXX": "John"
},
"sender_phone_number": "",
"user_profile": {
"display_name": "John",
"username": "john_user",
"country_code": "BR",
"phone_number": "555XXXXXXXXX",
"user_id": "BR.3234965106801957"
}
}
}
}When the call ends, you receive a whatsapp_call_terminate_event.
| Field | Description |
|---|---|
direction | The call direction. For example, USER_INITIATED. |
deeplink_payload | Payload received from a call deep link, when used. |
cta_payload | Payload received from a call button message. |
status | Call result, for example COMPLETED. |
start_time | Call start time. |
end_time | Call end time. |
duration | Call duration. |
{
"app_id": "01KX1DEK870THTWCNENESBW5DP",
"event_time": "2026-08-28T14:19:04.302983983Z",
"project_id": "2cb92b1b-2faf-40be-9380-accec4f24f46",
"event": {
"direction": "TO_APP",
"contact_event": {
"channel_specific_event": {
"whatsapp_call_terminate_event": {
"direction": "USER_INITIATED",
"deeplink_payload": "",
"cta_payload": "test",
"status": "COMPLETED",
"start_time": "1787926665",
"end_time": "1787926743",
"duration": 78
}
}
},
"id": "01M14BT39CASHZJB0Q74ZW3FFT",
"conversation_id": "",
"contact_id": "",
"channel_identity": {
"channel": "WHATSAPP",
"identity": "555XXXXXXXXX",
"app_id": ""
},
"accept_time": "2026-08-28T14:19:04.464874671Z",
"processing_mode": "DISPATCH"
},
"message_metadata": "",
"correlation_id": "",
"channel_metadata": {
"whatsapp": {
"profile_names": {
"555XXXXXXXXX": "John"
},
"sender_phone_number": "",
"user_profile": {
"display_name": "John",
"username": "john_user",
"country_code": "BR",
"phone_number": "555XXXXXXXXX",
"user_id": "BR.3234965106801957"
}
}
}
}For the call transport and calling lifecycle that happen outside Conversation API message sends, see Meta's documentation for:



