Cloud API Calling GraphAPI Spec Beta V0.97
Cloud API Calling GraphAPI Spec Beta V0.97
Context
WhatsApp Business Calling aims to bring the VoIP communication channel in addition to text messaging between WhatsApp consumers and
Business on WhatsApp. The consumers would use the WhatsApp consumer app in a manner similar to the current Consumer to Consumer
Calling product. Businesses would however interface with WhatsApp via GraphAPI interface for the initial call signaling and connection.
Disclaimer
These APIs are for reference only. The shipped APIs can differ drastically from the ones in this doc.
Architecture Overview
Internet Internet
Meta Partner
Signaling Graph APIs, Signaling
Webhooks
Infra HTTPS
Infra
Enable reuse of
Partner VoIP
existing systems System
Authorization
The Calling APIs utilize the same Authorization tokens as the rest of Cloud API and reuses existing permissions
whatsapp_business_messaging and whatsapp_business_management. More details can be found here.
Request Body {
"calling": {
"status": "ENABLED",
"call_icon_visibility": "DEFAULT",
"callback_permission_status": "ENABLED"
}
}
Response {
"success": true
}
Error Response {
"error": {
"message": "<Error Message>",
"type": "<Exception Type>",
"code": <Exception Code>,
"fbtrace_id": "<Trace ID>"
}
}
Endpoint Params ● Phone-number-id: This is an ID for each phone number registered to whatsapp business
platform. More details here
Calling Status: When a business sets the calling status as enabled, WhatsApp clients will render the
call icon in business conversations and business chat profile. The call icon will be hidden when calling
status is set to disabled. Call icon updates in existing chats will be near real time when the business
phone number is in the user's contacts. Otherwise updates are real time for a limited number of users in
conversation with the business, and eventual (up to a few days) for the rest. See instructions to force
display of the call icon.
Calling Eligibility: To enable calling, the business must have a messaging limit of 1000 business-
initiated conversations in a rolling 24-hour period (or higher) on any of their phone numbers. See
instructions on how to check this.
The business numbers that were previously onboarded using Google form are automatically set to
calling status enabled. You don’t have to take any action for those numbers. We’ll soon deprecate
Google form in favor of this self service API
Call Icon Visibility: When calling status is enabled, you can further control the display of the call icon
via the "call_icon_visibility" parameter. The behavior for supported options is as follows:
● DEFAULT
○ Call icon is displayed is in all calling entry points (chat menu and business info)
● DISABLE_ALL
○ Deprecates HIDE_IN_CHAT.
○ Call icon is hidden in the chat menu and business info window accessed through the
chat.
○ All other entry points external to the chat are also disabled - consumers cannot make
unsolicited calls to the business. Note: This relies on the most recent WhatsApp client
version released on November 18, so it will take a few months before we reach 100%
client coverage of the feature.
○ When you choose DISABLE_ALL, you can still send interactive message or template
message with Call CTA button, which will continue to work
Callback Permissions: a business initiated call on WhatsApp Cloud API requires explicit permissions
from the user before a business can call the user. The account can be set to automatically trigger the
call permission UI in the user’s WhatsApp client on an unanswered user initiated call. The user may
change their selection at any time. More details here.
[Planned Change - ETA June 2025] Proactive callback permissions: We plan to update this feature
such that the WhatsApp client app will automatically send an approved call permission when a user
initiates a call to the business regardless of the outcome of the user initiated call. The user may change
this selection at any time. This change should be completely transparent from the API integration pov.
[Planned Feature] Support for providing your webrtc endpoint IP address blocks is coming in the near
future. Cloud API will only use these IPs to optimize server selection to improve call quality.
Response {
"calling": {
"status": "ENABLED",
"call_icon_visibility": "DEFAULT",
"callback_permission_status": "ENABLED"
},
<Other non-calling feature configuration...>
}
Error Response {
"error": {
"message": "<Error Message>",
"type": "<Exception Type>",
"code": <Exception Code>,
"fbtrace_id": "<Trace ID>"
}
}
Endpoint Params ● Phone-number-id This is an ID for each phone number registered to whatsapp business
platform. More details here
Response Details ● calling: Calling related feature settings the business previously set
○ status: [ENABLED, DISABLED]
○ call_icon_visibility (optional): [DEFAULT, HIDE_IN_CHAT, DISABLE_ALL]
○ [Planned Feature - ETA Apr 2025] callback_permission_status: [ENABLED |
DISABLED | NOT_SET],
○ [Planned Feature] ip_addresses (optional)
■ default: List of IP address blocks representing business voice call servers (IPv4
or IPv6). Cloud API will use this as default for the business to optimize call quality
This API will also return other feature settings (ex. Local Storage) if configured
Details Businesses call this API to check their calling feature settings.
This API can return information for other Cloud API feature settings.
To access it:
1. Click on WhatsApp Accounts
2. Select your WhatsApp Account
3. Click on Phone Numbers
4. Click the gear icon next to the phone number you are using for calling
5. Click the "More" dropdown, then select "Calls"
[Planned Feature-Apr 2025] You can control your callback permissions settings via the WhatsApp Manager interface.
Consumer Initiated Calls
Pre-accepting an user initiated call
Description Respond to an user initiated call by pre-accepting the call. Pre-accept facilitates
faster call setup and avoids audio clipping problems
Request Body {
"messaging_product": "whatsapp",
"call_id": "wacid.ABGGFjFVU2AfAgo6V-Hc5eCgK5Gh",
"action": "pre_accept",
// connection is to be deprecated, use session instead
"connection" : {
"webrtc": {
"sdp" : "<<SDP INFO>>"
}
},
"session" : {
"sdp_type" : "answer",
"sdp" : "<<RFC 4566 SDP>>"
}
}
}
Response {
"messaging_product": "whatsapp",
"success" : true
}
Error Response {
"error": {
"message": "<Error Message>",
"type": "<Exception Type>",
"code": <Exception Code>,
}
}
Options ● call_id: Id of the call, from the webhook you previously received for this call
● action: [pre_accept, accept, reject, terminate]
● connection (Only required when Action = pre_accept or accept). The field
‘sdp’ is a json serialized string with following 2 keys†
○ sdp: SDP info of the device on the other end of the call. Example
structure in appendix.
○ type: "answer" - to indicate sdp answer
○ connection is to be deprecated, use session instead
● session: Indicates connection information/event pertaining to this call
session. It need two parameters
○ sdp: SDP info of the device on the other end of the call. Example
structure in appendix. Sdp must be compliant with RFC 4566.
○ sdp_type: "answer" - to indicate sdp answer
Details Businesses call this API to initiate the call setup process by providing an SDP
answer. Pre-accepting is optional but highly recommended to optimize the call
setup process and allow media connection to be pre-established before call
acceptance, but with no media. Once the call is accepted, media starts flowing
immediately as the connection is already in place.
Request Body {
"messaging_product": "whatsapp",
"call_id": "wacid.ABGGFjFVU2AfAgo6V-Hc5eCgK5Gh",
"action": "accept",
// connection is to be deprecated, use session instead
"connection" : {
"webrtc": {
"sdp" : "<<SDP INFO>>"
}
},
"session" : {
"sdp_type" : "answer",
"sdp" : "<<RFC 4566 SDP>>"
},
"biz_opaque_callback_data": "random data",
}
}
Response {
"messaging_product": "whatsapp",
"success" : true
}
Error Response {
"error": {
"message": "<Error Message>",
"type": "<Exception Type>",
"code": <Exception Code>,
}
}
Options ● call_id: Id of the call, from the webhook you previously received for this call
● action: [pre_accept, accept, reject, terminate]
● connection (Only required when Action = pre_accept or accept). The field
‘sdp’ is a json serialized string with following 2 keys
○ sdp: SDP info of the device on the other end of the call. Example
structure in appendix.
○ type: "answer" - to indicate sdp answer
○ connection is to be deprecated, use session instead
● session: Indicates connection information/event pertaining to this call
session. It need two parameters
○ sdp: SDP info of the device on the other end of the call. Example
structure in appendix. Sdp must be compliant with RFC 4566.
○ sdp_type: "answer" - to indicate sdp answer
● biz_opaque_callback_data [Optional]:
○ An arbitrary string, useful for tracking.
○ Any app subscribed to the calls webhook field on the WhatsApp
Business Account can get this string, as it is included in the “calls”
object within the subsequent Terminate Webhook payload.
○ Cloud API does not process this field, it just returns it as part of
Terminate Webhook
○ Maximum 512 characters.
Details Businesses call this API to connect to a call by providing an agent's SDP.
The business has some amount of time to respond to the user initiated call (30 -
60s) incoming webhook with the pre-accept or accept API call. If the business
does not respond the call is terminated on consumer side with "Not Answered"
and a Terminate webhook is delivered to the business
Request Body {
"messaging_product": "whatsapp",
"call_id": "wacid.ABGGFjFVU2AfAgo6V-Hc5eCgK5Gh",
"action": "reject"
}
Response {
"messaging_product": "whatsapp",
"success" : true
}
Error Response {
"error": {
"message": "<Error Message>",
"type": "<Exception Type>",
"code": <Exception Code>,
}
}
Options ● call_id: Id of the call, from the webhook you previously received for this call
● action: [accept, reject, terminate]
Typically the business has some amount of time to respond to the user initiated
call (30 - 60s) incoming webhook with the reject API call. If the business does not
respond then the call will be terminated on consumer side with "Not Answered"
and a Terminate webhook is delivered to the business
Request Body {
"messaging_product": "whatsapp",
"call_id": "wacid.ABGGFjFVU2AfAgo6V-Hc5eCgK5Gh",
"action" : "terminate"
}
Response {
"messaging_product": "whatsapp",
"success" : true
}
Error Response {
"error": {
"message": "<Error Message>",
"type": "<Exception Type>",
"code": <Exception Code>,
}
}
Details Business must call this API to end a call. This must be done even if there is an
RTCP BYE packet in the media path. Doing so helps with more accurate pricing.
When a consumer terminates the call, you don’t have to invoke this API.
Terminate webhook will be sent following successful processing of this API.
Calling Webhooks
The structure of webhooks is similar to the structure of webhooks used for Messaging in Cloud API. Detailed documentation of the
webhooks can be found here.
A "calls" section in the "value" section of the webhook contains calls related fields.
Connect: Receive notification about an user initiated call ready for pickup
This webhook is sent in near real-time, when the business receives an user initiated call. Webhook also includes the info to
establish a connection via WebRTC.
- This webhook is sent to signal the business to establish the call WebRTC connection by utilizing the /calls action=connect
- This webhook contains the new SDP information to help with establishing WebRTC connection
{
"object": "whatsapp_business_account",
"entry": [
{
"id": "whatsapp-business-account-id",
"changes": [
{
"value": {
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "16315553601",
"phone_number_id": "phone-number-id",
},
"contacts": [{
"profile": {
"name": "callee name"
},
"wa_id": "16315553602"
}],
"calls": [
{
"id": "wacid.ABGGFjFVU2AfAgo6V-Hc5eCgK5Gh",
"to": "16315553601",
"from": "16315553602",
"event": "connect",
"timestamp": "1671644824",
"direction": "[BUSINESS_INITIATED|USER_INITIATED]",
// connection to be deprecated, use session
"connection": {
"webrtc": {
"sdp": {..<<SDP data>>..}
}
},
"session": {
"sdp_type": "offer"
"sdp": "<<RFC 4566 SDP>>"
}
}
]
},
"field": "calls"
}
]
}
]
}
connection Structure that contains information that is used for the voice connection for the call
Field connection is to be deprecated, use session instead
webrtc Information related to webrtc connect. At this time only WebRTC connections are
supported
sdp Session Description Protocol data for the device on the other end of the call. This
is a json serialized string with following 2 keys
● sdp: SDP info of the device on the other end of the call. Example structure
in appendix.
● type: "offer" - to indicate sdp offer
session Indicates connection information/event pertaining to this call session. It will have
the below two parameters
sdp Session Description Protocol data for the device on the other end of the call.
Example structure in appendix. Sdp must be compliant with RFC 4566
sdp_type Type of the sdp can be "offer" or "answer" depending on whether the call is
business initiated or consumer initiated respectively.
contacts Profile information of the callee. Contains their WhatsApp profile name and
WhatsApp ID.
start_time [Optional] Start time of the call. Only present when the call was picked up by the
other party.
end_time [Optional] End time of the call. Only present when the call was picked up by the
other party.
duration [Optional] Duration of the call in seconds. Only present when the call was picked
up by the other party.
errors This field exists if status is failed and includes more details about the error
biz_opaque_callb [Optional] Will only be available if provided through New Call API Requests or
ack_data Accept Call Requests
Consumer to Business Call Sequence Diagram
1) Consumer Calls business from the whatsapp consumer app, the call results in the below webhook event being delivered to the business
{
"object": "whatsapp_business_account",
"entry": [
{
"id": "whatsapp-business-account-id",
"changes": [
{
"value": {
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "16315553601",
"phone_number_id": "phone-number-id",
},
"calls": [
{
"id": "wacid.ABGGFjFVU2AfAgo6V-Hc5eCgK5Gh",
"to": "16315553601",
"from": "16315553602",
"event": "connect",
"timestamp": "1671644824",
"connection": {
"webrtc": {
"sdp": {..<<SDP offer data>>..}
}
},
"session": {
"sdp_type": "offer"
"sdp": "<<RFC 4566 SDP>>"
}
}
]
},
"field": "calls"
}
]
}
]
}
2) Business responds to the webhook by pre-accepting the call using the /calls api with the below Request body. This step is optional. See
audio clipping section for more context.
POST {phone-number-id}/calls
{
"messaging_product": "whatsapp",
"call_id": "wacid.ABGGFjFVU2AfAgo6V-Hc5eCgK5Gh",
"action": "pre_accept",
"connection" : {
"webrtc": {
"sdp" : "<<SDP answer data>>"
}
},
"session": {
"sdp_type": "answer"
"sdp": "<<RFC 4566 SDP>>"
}
}
4) Business waits for webrtc/ice connection and accepts the call using the /calls api with the below Request body
POST {phone-number-id}/calls
{
"messaging_product": "whatsapp",
"call_id": "wacid.ABGGFjFVU2AfAgo6V-Hc5eCgK5Gh",
"action": "accept",
"connection" : {
"webrtc": {
"sdp" : "<<SDP answer data>>"
}
},
"session": {
"sdp_type": "answer"
"sdp": "<<RFC 4566 SDP>>"
}
}
5) If the Business wants to terminates the call, they would call the /calls api with the below Request body
POST {phone-number-id}/calls
{
"messaging_product": "whatsapp",
"call_id": "wacid.ABGGFjFVU2AfAgo6V-Hc5eCgK5Gh",
"action" : "terminate"
}
6) The Business would receive the below response confirming the action
{
"success" : true
}
7) The Business would eventually receive the terminate webhook once the call has been disconnected across the stack or if the call was
disconnected by the whatsapp consumer
{
"object": "whatsapp_business_account",
"entry": [
{
"id": "whatsapp-business-account-id",
"changes": [
{
"value": {
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "16505553602",
"phone_number_id": "phone-number-id",
},
"calls": [
{
"id": "wacid.ABGGFjFVU2AfAgo6V-Hc5eCgK5Gh",
"to": "16315553601",
"from": "16315553602",
"event": "terminate"
"direction": "[BUSINESS_INITIATED|USER_INITIATED]",
"timestamp": "1671644824",
"status" : [Failed | Completed],
"start_time" : "1671644824",
"end_time" : "1671644944",
"duration" : 120
}
]
},
"field": "calls"
}
]
}
]
Messages with Call CTA
Send interactive message with WhatsApp Call Button
Description Send an interactive message with WhatsApp Call Button
Request {
Body "messaging_product": "whatsapp",
"recipient_type": "individual",
"to": "14085551234",
"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,
}
}
}
}
Error {
Response "error": {
"message": "<Error Message>",
"type": "<Exception Type>",
"code": <Exception Code>,
}
}
Details Business calls this API to send a message to consumers to raise awareness of the calling
support using an inline button embedded within the message. When a consumer clicks that
button, it initiates a WhatsApp call to the business number that sent this message. This
behavior is the same as a consumer clicking the phone/call icon in the chat title bar. There
is no support for the button to WhatsApp call a different phone number
Limitations ● Sending this message to users on older app versions will result in error webhook
with error code 131026
Request {
Body "name": "<NAME>",
"category": "<CATEGORY>",
"language": "<LANGUAGE>",
"components": [
{
"type": "BODY",
"text": "You can call us on WhatsApp now for faster service!"
},
{
"type": "BUTTONS",
"buttons": [
{
"type": "VOICE_CALL",
"text": "Call Now"
},
{
"type": "URL",
"text": "Contact Support",
"url": "https://www.luckyshrub.com/support"
}
]
}
]
}
Error {
Response "error": {
"message": "<Error Message>",
"type": "<Exception Type>",
"code": <Exception Code>,
}
}
Endpoint ● The only field supported for VOICE_CALL button type is "text" which indicates the
Params label of the button rendered on WhatsApp consumer client apps
Details Business calls this API to send a template message to consumer to raise awareness of the
calling support using an inline button embedded within the message
Options See public documentation for more details
Request {
Body "to": "14085551234",
"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
}
]
}
]
}
}
Error {
Response "error": {
"message": "<Error Message>",
"type": "<Exception Type>",
"code": <Exception Code>,
}
}
Details Business calls this API to send a message to consumers to raise awareness of the calling
support using an inline button embedded within the message. When a consumer clicks that
button, it initiates a WhatsApp call to the business number that sent this message. This
behavior is the same as a consumer clicking the phone/call icon in the chat title bar. There
is no support for the button to WhatsApp call a different phone number
Limitations ● Sending this message to users on older app versions will result in error webhook
with error code 131026
2. Businesses can send Call deep links on WhatsApp: With Call deep links, businesses now have more control over calls. Call deep
links allow businesses and agents to link to another number and prompt users to contact a different phone number with voice enabled.
The wa.me/call/<phone number> format is easy to replicate and copy and paste, and does not require having to set up a template in
Business Manager.
138000 Calling APIs are not enabled for this phone WhatsApp CloudAPI Calling APIs are 401
Calling not enabled number currently only available to select WhatsApp Unauthorized
Business platform partners.
Reach out to the Whatsapp Business team
to find out more.
Code Description Possible Solutions HTTP Status Code
138001 Receiver is unable to receive calls Confirm with the recipient that they agree to 400
be contacted by you over WhatsApp and
Receiver Uncallable Reasons can include: are using the latest version of WhatsApp. Bad Request
138002 Limit reached for maximum concurrent calls for the Try again later or reduce the frequency or 429
Concurrent Calls limit given number amount of API calls the app is making. Too many requests
138003 A call is already ongoing with the receiver Try again later when the current call ends. 400
Duplicate call Bad Request
138004 Error while connecting the call Try again later or investigate the connection 500
Connection error params provided to the API
138005 Limit reached for maximum calls that can be Try again later or reduce the frequency or 429
Call rate limit exceeded initiated by the business phone number amount of API calls the app is making. Too many requests
131009 Interactive Message type, 'voice_call' not Ensure the sender in one of the supported 400
supported. Supported types ['button', 'list’] countries. Bad Request
131044 An error webhook is sent on user initiated calls This is similar to the "Business eligibility 400
when there is no valid payment method attached payment issue" error in messaging. Bad Request
138006 No approved call permission from the recipient Ensure a call permission has been 401
No approved call accepted by the consumer Unauthorized
permission found
138007 Call was unable to connect due to a timeout Business did not apply the offer/answer 500
Connect Timeout error SDP from Cloud API in time.
Connect API was not invoked with the
answer SDP in time
138009 Limit reached for call permission request sends for When a business sends more than the limit 400
Call Permission the given business and consumer pair of call permission requests per time period,
Request Limit Hit Call Permission Requests are rate limited.
A connected call with a consumer will reset
the limits.
138010 Limit reached for business initiated calls per When business attempts more that the limit 400
Business Initiated Calls approved permission request, for the given of calls per approved call permission
Per Approved business and consumer pair request, we will rate limit the business
initiated calls.
Permission Limit Hit
138011 Unable to send a call permission request message Attempt was made to send a call 400
Unable to send Call permission request message without an Bad Request
permission request open customer service window
100 The GraphAPI call you are making has an invalid Exact error details will be listed in the 400
Invalid Parameter parameter. error_data section of the response payload. Bad Request
138012 Limit reached for maximum business initiated calls Exact error details will be listed in the 400
Business Initiated Calls allowed in 24 hours. Currently 5 connected error_data section of the response payload.
Limit Hit business initiated calls are allowed within 24
hours. Details will include a timestamp when the
next call is allowed.
DTMF Support
The CloudAPI Calling supports DTMF tones. The intention is for the BSP applications to be able to support IVR based systems for the
participating businesses.
The consumers can press the buttons on the client app and the DTMF tones are injected into the WebRTC RTP stream established as a part of
the VoIP connection. Our WebRTC stream conforms to RFC 4733 for the transfer of DTMF Digits via RTP Payload. Specifically there is no
webhook for conveying DTMF digits.
NOTE: This dialpad only supports DTMF use cases. It is not shown for consumer to consumer calls and does not change any other calling
behaviors. For example the dialpad cannot be used to dial a number and initiate a call or message on WhatsApp.
When granted by the consumer, a call permission allows the business to call the user subject to following constraints (per business + consumer
pair) to protect WhatsApp users from unwanted calls
Description Limits
Time period the business has to call the user from 7 days
the time user approves the call permission
Permission Duration
Number of connected calls a business can make 5 connected calls per 24 hours for a possible total
to the user. of 35 calls across 7 days
Call limits Failed calls are not counted towards this limit.
A consumer may approve, decline or not respond to a call permission request. A user may also change their response (i.e. decline a granted
permission request or grant a declined permission request) at any time before the call permission request expires.
The call permission request expires when any of the following occurs:
● When the consumer interacts with a subsequent new call permission request to the business
● 7 days after the permission was accepted or declined by the consumer
● 7 days after the permission was delivered if the consumer does not respond to the request
To ensure optimal user experience around business initiated calling, the following limits are enforced
1. Sending a call permission request message is subject to the following restrictions:
a. A business can send a maximum of 1 permission request in 24h and 2 permission requests in 7 days. This limit resets when a
connected call takes place between the business and consumer (call can be either user initiated or business initiated).
2. Unanswered business initiated calls i.e. calls either missed or rejected by the user, trigger following behaviour in the WhatsApp user
application
a. 2 consecutive unanswered calls (UX) result in system message to reconsider an approved permission
b. 4 consecutive unanswered calls (UX) result in an approved permission being automatically revoked. The user may again update
this if they so choose.
This feature is disabled by default and needs to be explicitly enabled for a business phone number via the call settings api. More details on
enabling/disabling this feature is in the Call Settings API section.
Request Body {
"messaging_product": "whatsapp",
"recipient_type": "individual",
"to": "<phone number> or <wa_id>",
"type": "interactive",
"interactive": {
"type": "call_permission_request",
"action": {
"name": "call_permission_request"
},
"body": {
"text": "We would like to call you to help
support your query on Order No: ON-12345."
}
}
}
Response {
"messaging_product": "whatsapp",
"contacts": [{
"input": "+1-408-555-1234",
"wa_id": "14085551234",
}]
"messages": [{
"id": "wamid.gBGGFlaCmZ9plHrf2Mh-o",
}]
}
Error Response {
"error": {
"message": "<Error Message>",
"type": "<Exception Type>",
"code": <Exception Code>,
}
}
Options
● to: Number to which the voice call is being made. Country codes are
required. More info about accepted formats here.
● type: This will be a new type of interactive message, more details on
interactive messages here
● interactive: For call permissions request messages only the type
param needs to be specified. See mocks above for how this will be
rendered on WhatsApp client device.
● body: optional param to provider users context for the call. Will be
available
Response Details ● As per the normal send message api response. Details here
Details Businesses will call this API to send a call request permission message to a
WhatsApp consumer account. This message will need an open conversation
with the consumer account. More details on opening conversations here.
Note: The message contents cannot be edited by the businesses for the call
permission request interactive message.
Endpoint POST/{whatsapp-business-account-id}/message_templates
Request Body {
"name": "sample_cpr_template",
"language": "en",
"category": "[MARKETING|UTILITY]",
"components": [
{
"type": "HEADER",
"text": "Support of Order No: {{1}}",
"example": {
"body_text": [
[
"ON-12345"
]
]
}
},
{
"type": "BODY",
"text": "We would like to call you to help support your
query on Order No: {{1}} for the item {{2}}.",
"example": {
"body_text": [
[
"ON-12345",
"Avocados"
]
]
}
},
{
"type": "FOOTER",
"text": "Talk to you soon!"
},
{
"type": "call_permission_request"
}
]
}
Response {
"id": "<ID>",
"status": "<STATUS>",
"category": "<CATEGORY>"
}
Error Response {
"error": {
"message": "<Error Message>",
"type": "<Exception Type>",
"code": <Exception Code>,
"error_subcode": <Error subcode>,
"is_transient": false,
"error_user_title": "<Error Title>",
"error_user_msg": "<Error Message>"
}
}
Details Businesses may call this API to create a call permission request message template.
More details on how to create/manage templates can be found here. Media is not
supported for this template.
Request Body {
"messaging_product": "whatsapp",
"recipient_type": "individual",
"to": "{user number}",
"type": "template",
"template": {
"name": "sample_cpr_template",
"language": {
"policy": "deterministic",
"code": "en_US"
},
"components": [
{
"type": "header",
"parameters": [
{
"type": "text",
"text": "ON-12345"
}
]
},
{
"type": "body",
"parameters": [
{
"type": "text",
"text": "ON-12345"
},
{
"type": "text",
"text": "Avocados"
}
]
}
]
}
}
Response {
"messaging_product": "whatsapp",
"contacts": [{
"input": "+1-408-555-1234",
"wa_id": "+1-408-555-1234",
}]
"messages": [{
"id": "wamid.gBGGFlaCmZ9plHrf2Mh-o",
}]
}
Error Response {
"error": {
"message": "<Error Message>",
"type": "<Exception Type>",
"code": <Exception Code>,
}
}
Options
For more details on how to send template messages check the docs
here. Components can vary based on the params set on the template
creation.
Response Details ● As per the normal send message api response. Details here
Details Businesses will call this API to send a call request permission message
to a WhatsApp consumer account. This message will be charged as per
the assigned template category.
Note: The contents of the call permission component cannot be edited
by the businesses.
interactive Structure that contains the details of the whatsapp consumer account’s response
for the call permissions request message.
response Consumer’s response to the call permission request message
expiration_time Time in seconds when this call permission expires if the consumer approved it
response_source Source of this permission, possible values for accepted call permissions are
● user_action: User approved or rejected the permission
● [From June] automatic: automatic approval due to user initiated call
context Context is included for a message when a user “replies to” or interacts with one of
your messages. The ID in the context section will be based on the use case.
When the user responds to a Call Permission Request message sent by the
business, the message id of the call permission request message sent by the
business is included in the context section of the webhook
interactive Structure that contains the details of the whatsapp consumer account’s response
for the call permissions request message.
response_source Source of this permission, possible values for rejected call permissions
● user_action: User approved or rejected the permission
● automatic: automatic rejection due to unanswered call limits
context Context is included for a message when a user “replies to” or interacts with one of
your messages. The ID in the context section will be based on the use case.
When the user responds to a Call Permission Request message sent by the
business, the message id of the call permission request message sent by the
business is included in the context section of the webhook
expiration_time Time in seconds when this call permission expires if the consumer approved it
context Context is included for a message when a user “replies to” or interacts with one of
your messages. The ID in the context section will be based on the use case.
When the user provides a permission after a missed consumer initiated call, the call
id of the user initiated call missed by the business is included in the context
section.
The business will receive the usual call webhooks for this call when the call
happens.
Calling APIs
Request Body {
"messaging_product": "whatsapp",
"to":"14085551234",
"action": "connect",
"session" : {
"sdp_type" : "offer",
"sdp" : "<<RFC 4566 SDP>>"
},
"biz_opaque_callback_data": "random data"
}
Response {
"messaging_product": "whatsapp",
"calls" : [{
"id" : "wacid.ABGGFjFVU2AfAgo6V",
}]
}
Error Response {
"error": {
"message": "<Error Message>",
"type": "<Exception Type>",
"code": <Exception Code>,
}
}
Endpoint Params ● Phone-number-id This is an ID for each phone number registered to whatsapp
business platform. More details here
Request Body
Params ● to: Number to which the voice call is being made. Country codes are required. More
info about accepted formats here.
● session: Indicates connection information/event pertaining to this call session. It need
two parameters
○ sdp: SDP info of the device on the other end of the call. Example structure in
appendix. Sdp must be compliant with RFC 4566.
○ sdp_type: "offer" - to indicate sdp offer
● biz_opaque_callback_data [Optional]:
○ An arbitrary string, useful for tracking.
○ Any app subscribed to the calls webhook field on the WhatsApp Business
Account can get this string. It is included within the subsequent webhook
payloads: “calls” object within Connect Webhook payload, “statuses” object
within Status Webhook payload and “calls” object within Terminate Webhook
payload
○ Cloud API does not process this field, it just returns it as part of webhooks
○ Maximum 512 characters.
Details Businesses will call this API to start a call by providing a call receiver’s number and a webrtc
call offer.
Calling Webhooks
The structure of webhooks is similar to the structure of the webhooks used for Messaging in Cloud API. Detailed documentation of
the webhooks can be found here.
A "calls" section in the "value" section of the webhook contains calls related fields.
Connect: Receive answer SDP from Cloud API to initiate media connection
This webhook is sent in response to a new call request received from the business.
- This webhook is sent to signal the business to establish the call WebRTC connection by invoking the API /calls
action=connect
- This webhook contains the answer SDP information to establish WebRTC connection
{
"object": "whatsapp_business_account",
"entry": [
{
"id": "whatsapp-business-account-id",
"changes": [
{
"value": {
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "16315553601",
"phone_number_id": "phone-number-id",
},
"calls": [
{
"id": "wacid.ABGGFjFVU2AfAgo6V",
"to": "16315553601",
"from": "16315553602",
"event": "connect",
"timestamp": "1671644824",
"direction": "BUSINESS_INITIATED",
// connection is to be deprecated, use session
"connection": {
"webrtc": {
"sdp": {..<<SDP data>>..}
}
},
"session": {
"sdp_type": "answer"
"sdp": "<<RFC 4566 SDP>>"
},
"biz_opaque_callback_data": "random data",
}
]
},
"field": "calls"
}
]
}
]
}
session Indicates connection information/event pertaining to this call session. It will have
the below two parameters
sdp Session Description Protocol data for the device on the other end of the call.
Example structure in appendix. Sdp must be compliant with RFC 4566
sdp_type Type of the sdp can be "offer" or "answer" depending on whether the call is
business initiated or consumer initiated respectively.
biz_opaque_callb [Optional] Will only be available if provided through New Call API Requests
ack_data
Call Status Webhooks: Receive notification on events for a business initiated call
This webhook is sent on certain events for a business initiated call. More specifically the status webhook will be sent on the following events.
1. Ringing: When the business initiated call begins Ringing on the WhatsApp consumer’s device
2. Accepted: When the WhatsApp consumer accepts the business initiated call
3. Rejected: When the business initiated call is Rejected by the WhatsApp consumer
The Webhook structure here is similar to the Status webhooks used for the Cloud API messages. More details on the current status
webhook structure here.
{
"object": "whatsapp_business_account",
"entry": [
{
"id": "whatsapp-business-account-id",
"changes": [
{
"value": {
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "16315553601",
"phone_number_id": "phone-number-id",
},
"statuses": [{
"id": "wacid.ABGGFjFVU2AfAgo6V",
"timestamp": "1671644824",
"type": "call"
"status": "[RINGING|ACCEPTED|REJECTED]",
"recipient_id": "16315553601",
"biz_opaque_callback_data": "random data",
]
},
"field": "calls"
}
]
}
]
}
Field Name Description
type The type this status webhook is for. Another possible value here is "message".
recipient_id The phone number for the WhatsApp consumer this call is to
biz_opaque_callb [Optional] Will only be available if provided through New Call API Requests
ack_data
Note: Accepted webhook will usually always arrive after the call has been established. It is primarily sent for call event auditing purposes.
5) Business initiates a new call with the /calls api with the below Request body
POST {phone-number-id}/calls
{
"messaging_product": "whatsapp",
"to":"{c-phone-number}",
"action":"connect",
"session" : {
"sdp_type" : "offer",
"sdp" : "<<RFC 4566 SDP>>"
}
}
6) Business gets the below response with a call-id from Cloud API. Response with error code 138006 indicates lack of a call
request permission for this number by the consumer account.
{
"messaging_product": "whatsapp",
"calls" : [
"id" : "wacid.ABGGFjFVU2AfAgo6V",
]
}
7) Business receives a webhook with the sdp answer from Cloud API
{
"entry":
[
{
"changes":
[
{
"field": "calls",
"value":
{
"calls":
[
{
"from": "{phone-number}",
"session": {
"sdp": "RFC 4566 SDP",
"sdp_type": "answer"
},
"connection": {
"webrtc": {
"sdp": {..<<SDP data>>..}
}
},
"id": "wacid.ABGGFjFVU2AfAgo6V",
"to": "{c-phone-number}",
"event": "connect",
"timestamp": "1716496634",
"direction": "BUSINESS_INITIATED"
}
],
"metadata":
{
"phone_number_id": "{phone-number-id}",
"display_phone_number": "{phone-number}"
},
"messaging_product": "whatsapp"
}
}
],
"id": "{phone-number-id}"
}
],
"object": "whatsapp_business_account"
}
9) The business may terminate the call by invoking the /calls api with the below Request body
POST {phone-number-id}/calls
{
"messaging_product": "whatsapp",
"call_id": "wacid.ABGGFjFVU2AfAgo6V",
"action" : "terminate"
}
10) The Business would receive the below response confirming the action
{
"success" : true
}
11) The Business would eventually receive the terminate webhook once the call has been disconnected or if the call was disconnected by
the whatsapp consumer
{
"object": "whatsapp_business_account",
"entry": [
{
"id": "{phone-number-id}",
"changes": [
{
"value": {
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "{phone-number}",
"phone_number_id": "{phone-number-id}",
},
"calls": [
{
"id": "wacid.ABGGFjFVU2AfAgo6V-Hc5eCgK5Gh",
"to": "{c-phone-number}",
"from": "{phone-number}",
"event": "terminate"
"direction"s: "BUSINESS_INITIATED",
"timestamp": "1671644824",
"status" : [Failed | Completed],
"start_time" : "1671644824",
"end_time" : "1671644944",
"duration" : 120
}
]
},
"field": "calls"
}
]
}
]
}
v=0
o=- 3626166318745852955 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0
a=extmap-allow-mixed
a=msid-semantic: WMS d8b26053-4474-4eb7-b3c3-c93d6c8c9b2e
m=audio 9 UDP/TLS/RTP/SAVPF 111 63 9 0 8 110 126
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:4g1c
a=ice-pwd:qY/Bb+jQzg5ICn6X4fhJQetk
a=ice-options:trickle
a=fingerprint:sha-256
35:47:24:24:9F:93:C4:3E:DB:37:7F:BB:ED:F8:20:B5:AD:AC:DC:35:C2:7D:67:EE:6C:35:54:DF:A6:00:5C:4A
a=setup:actpass
a=mid:0
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
a=sendrecv
a=msid:d8b26053-4474-4eb7-b3c3-c93d6c8c9b2e 5b4d3d96-ea9b-44a8-87e6-11a1ad21a3bc
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1
a=rtpmap:63 red/48000/2
a=fmtp:63 111/111
a=rtpmap:9 G722/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:110 telephone-event/48000
a=rtpmap:126 telephone-event/8000
a=ssrc:2220762577 cname:w/zwpg3jXNiTFTdZ
a=ssrc:2220762577 msid:d8b26053-4474-4eb7-b3c3-c93d6c8c9b2e 5b4d3d96-ea9b-44a8-87e6-11a1ad21a3bc
v=0
o=- 741807839102053725 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0
a=extmap-allow-mixed
a=msid-semantic: WMS 798a9670-c0d6-47a8-925e-5f082ef4d8a0
a=ice-lite
m=audio 3482 UDP/TLS/RTP/SAVPF 111 9 0 8 110 126
c=IN IP4 31.13.65.130
a=rtcp:9 IN IP4 0.0.0.0
a=candidate:2754936280 1 udp 2113937151 31.13.65.130 3482 typ host generation 0 network-cost 50
ufrag JHqAXFH4HcAY/8
a=candidate:1581496399 1 udp 2113939711 2a03:2880:f211:d1:face:b00c:0:699c 3482 typ host generation
0 network-cost 50 ufrag JHqAXFH4HcAY/8
a=ice-ufrag:JHqAXFH4HcAY/8
a=ice-pwd:dNNMmR8wUcGezvfBZOO0Qgcwl2m86GP/
a=ice-options:trickle
a=fingerprint:sha-256
9C:97:5C:4C:A9:BE:9E:2F:06:94:F5:BB:38:2C:A1:29:B5:69:B8:FA:94:10:56:1D:0B:5D:80:28:C1:FD:F0:F6
a=setup:active
a=mid:0
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=sendrecv
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1
a=rtpmap:9 G722/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:110 telephone-event/48000
a=rtpmap:126 telephone-event/8000
a=ssrc:3407645770 cname:bg8KQDoIk2UJa6sf
a=ssrc:3407645770 msid:798a9670-c0d6-47a8-925e-5f082ef4d8a0 audio#nuxVMf9EAJX
a=ssrc:3407645770 mslabel:798a9670-c0d6-47a8-925e-5f082ef4d8a0
a=ssrc:3407645770 label:audio#nuxVMf9EAJX
Open Issues
When developers add the WhatsApp product to their app for the first time, Meta automatically creates the following test resources (per Step 1:
Add The WhatsApp Product To Your App):
● Test WhatsApp Business Account (with the same name)
● Test Phone Number (1-555-xxx-xxx)
These resources are intended for testing only and allow a limited number of messages, calls and recipients.
If you don’t already have a test number, request one on this page (See ‘Get new test number’ in the From dropdown):
Follow the UI prompts to configure the allowed phone number recipients. For detailed instructions and restrictions see developer docs.
Webhook direction change [ETA: Sep, 2024]
As part of Graph API v21 release, the direction field in the webhooks will change from “INCOMING” to “USER_INITIATED” and “OUTGOING”
to “BUSINESS_INITIATED”.
Previous values (INCOMING/OUTGOING) will continue to be used in v20 and below until Jan 2 2025.
After Jan 2 2025, ALL API versions will use “USER_INITIATED” and “BUSINESS_INITIATED”.
Appendix
Sample Meta SDP Offer Structure
This is an example SDP Offer structure.
v=0
o=- 7602563789789945080 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio
a=msid-semantic: WMS 6932bc1c-db1a-4abe-b437-0c4168be8a13
a=ice-lite
m=audio 40012 UDP/TLS/RTP/SAVPF 111 126
c=IN IP4 31.13.65.60
a=rtcp:9 IN IP4 0.0.0.0
a=candidate:1972637320 1 udp 2113937151 31.13.65.60 40012 typ host generation 0 network-cost 50 ufrag 6k2qP1R6kBfI/2
a=candidate:1652262791 1 udp 2113939711 2a03:2880:f211:cf:face:b00c:0:6443 40012 typ host generation 0 network-cost 50 ufrag
6k2qP1R6kBfI/2
a=ice-ufrag:6k2qP1R6kBfI/2
a=ice-pwd:UApvJw3NcwFRDvIMKdM0vWCdlXah25E9
a=fingerprint:sha-256 1B:B6:6B:40:A5:0B:8C:75:0D:8C:CB:90:2F:99:74:1E:26:45:AE:AF:45:C1:51:60:8F:73:C9:2D:10:6D:8A:88
a=setup:actpass
a=mid:audio
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=sendrecv
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1
a=rtpmap:126 telephone-event/8000
a=ssrc:4208138518 cname:gAXq2V9TKltrnapv
a=ssrc:4208138518 msid:6932bc1c-db1a-4abe-b437-0c4168be8a13 audio#R5wfXFcdmT6
a=ssrc:4208138518 mslabel:6932bc1c-db1a-4abe-b437-0c4168be8a13
a=ssrc:4208138518 label:audio#R5wfXFcdmT6
v=0
o=- 2822644248144643933 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio
a=msid-semantic: WMS eb909cf0-87f0-4358-a4c9-7861680d9431
m=audio 9 UDP/TLS/RTP/SAVPF 111 126
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:X1ho
a=ice-pwd:7fJSbV2N5qWiA5QiDKwK3vuh
a=fingerprint:sha-256 2E:35:9F:21:9E:63:72:E5:42:74:76:2D:B3:70:F7:CB:24:14:9B:14:52:71:05:48:DA:4D:67:31:09:58:2A:ED
a=setup:active
a=mid:audio
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=sendrecv
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1
a=rtpmap:126 telephone-event/8000
a=ssrc:330833028 cname:EDc1JutBl8rwHQc2
a=ssrc:330833028 msid:eb909cf0-87f0-4358-a4c9-7861680d9431 ea478c16-d9f7-493c-8cec-19bfac750a36