User-Initiated WhatsApp Calls

This guide explains how to receive and handle calls initiated by end-users through the WhatsApp app.

Overview

End-users can place calls to a business when:

  • Calling is enabled for the business phone number.

  • The user sees a call icon or presses a call CTA button.

Calls are initiated directly through the WhatsApp client and use VoIP (WebRTC). Businesses respond using the Cloud API:

Receiving a call

1

Connect Webhook

The webhook CONNECT 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

When user starts a call, the business gets a CONNECT webhook:

{
  "object": "whatsapp_business_account",
  "entry": [
    {
      "id": "366634483210360", // WhatsApp Business Account ID associated with the business phone number
      "changes": [
        {
          "value": {
            "messaging_product": "whatsapp",
            "metadata": { // ID and display number for the business phone number placing the call (caller)
              "phone_number_id": "436666719526789",
              "display_phone_number": "13175551399",
            },
            "calls": [
              {
                "id": "wacid.ABGGFjFVU2AfAgo6V-Hc5eCgK5Gh", // The WhatsApp call ID
                "to": "16315553601", // The WhatsApp user's phone number (callee)
                "from": "13175551399",
                "event": "connect",
                "timestamp": "1671644824",
                "session": {
                  "sdp_type": "offer",
                  "sdp": "<<RFC 8866 SDP>>"
                }
              }
            ]
          },
          "field": "calls"
        }
      ]
    }
  ]
}
2

To receive a call, business can establish an SDP answer.

  • Pre-accepting is recommended to optimize the setup process and allow media connection before it starts.

  • Media only starts flowing once a call is accepted.

  • Business have from 30 to 60 seconds to pre-accept a call, or accept with an API answer. Otherwise, the call will be terminated as “Not answered”.

The purpose is to pre-establish a WebRTC connection to prevent audio clipping.

Endpoint:

POST https://alpha-beta-onboarding.hub-production.360dialog.io/calling/calls/{phone_number_id} --header 'D360-API-KEY: ••••••'

{'
  "messaging_product": "whatsapp",
  "call_id": "wacid.XXX",
  "action": "pre_accept",
  "session": {
    "sdp_type": "answer",
    "sdp": "...RFC 4566 SDP..."
  }
}

Response:

{
  "success" : true
}
3

Accept the call

Businesses can accept a call using the following endpoint:

POST https://alpha-beta-onboarding.hub-production.360dialog.io/calling/calls/{phone_number_id}

--header 'D360-API-KEY: ••••••'

Request body:

{
  "messaging_product": "whatsapp",
  "call_id": "wacid.ABGGFjFVU2AfAgo6V-Hc5eCgK5Gh",
  "action": "accept",
  "session" : {
      "sdp_type" : "answer",
      "sdp" : "<<RFC 8866 SDP>>"
   }
}

This initiates media flow over the established WebRTC session.

Response:

{
  "messaging_product": "whatsapp", 
  "success" : true
}

Error:

{
"error": {
  "message": "<Error Message>", 
  "type": "<Exception Type>", 
  "code": <Exception Code>,
  } 
}

4

Reject or Hang Up

You can also:

  • Reject the call (before answering):

{
  "action": "reject"
}
  • Terminate the call (after connecting):

{
  "action": "terminate"
}
5

Call Terminated Webhook

This webhook is received when the call ends for any reason.

It includes metadata like duration, status (COMPLETED or FAILED), and biz_opaque_callback_data if provided:

{
  "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",
                    "biz_opaque_callback_data": "random_string",
                    "timestamp": "1671644824",
                    "status" : [FAILED | COMPLETED],
                    "start_time" : "1671644824",
                    "end_time" : "1671644944",
                    "duration" : 120
                }
              ],
              "errors": [
                {
                    "code": INT_CODE,
                    "message": "ERROR_TITLE",
                    "href": "ERROR_HREF",
                    "error_data": {
                        "details": "ERROR_DETAILS"
                    }
                }
              ]
          },
          "field": "calls"
        }
      ]
    }
  ]
}

1. Interactive Voice Call Button

  • Sent via interactive message or a template, 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:

Send interactive message with WhatsApp Call Button

Endpoint: POST https://waba-v2.360dialog.io/messages --header 'D360-API-KEY: ••••••'

Request body:

{
    "messaging_product": "whatsapp",
    "recipient_type": "individual",
    "to": "{{recipient-phone-number}}",
    "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 // Expected value is an Integer value between 1 and 43200 (30 days)
            }
        }
    }
}

Send interactive message with WhatsApp Call Button
Create a template with WhatsApp Call Button
curl --location 'https://waba-v2.360dialog.io/v1/configs/templates' \
--header 'Content-Type: application/json' \
--header 'D360-API-KEY: {YOUR-D360-API-KEY}' \
--data '{
    "name": "calling_template",
    "category": "MARKETING",
    "language": "en_US",
    "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.360dialog.com/contact "
                }
            ]
        }
    ]
}'
Send a template message with WhatsApp Call Button
curl --location 'https://waba-v2.360dialog.io/messages'
--header 'Content-Type: application/json'
--header 'D360-API-KEY: {YOUR-D360-API-KEY}'
--data '{
"to": {{recipient-phone-number}},
"messaging_product": "whatsapp",
"type": "template",
"recipient_type": "individual",
"template": {
"name": "calling_template",
"language": {
"code": "en_US"
},
"components": [
{
"type": "button",
"sub_type": "voice_call",
"parameters": [
{
"type": "ttl_minutes",
"ttl_minutes": 100
}
]
}
]
}
}'

Send a template with WhatsApp Call Button
  • When clicked, the API initiates a WhatsApp call to the sending business number. 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.

https://wa.me/call/<phone_number>

DTMF Support (Optional)

WhatsApp Calling supports DTMF tones via the in-call dialpad:

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. Meta’s WebRTC stream conforms to RFC 4733 for the transfer of DTMF Digits via RTP Payload. Specifically there is no webhook for conveying DTMF digits.

Delivering DTMF digits on WebRTC connection

When a consumer presses a digit in the dialpad on the client, the equivalent DTMF is injected into the webrtc. Tones values are digits from 0 to 9, # and *. The Duration is 500ms and InterToneGap is 100ms for all the tones.

User-initiated Calls using SIP

The WhatsApp user calls business phone number and is unaware of whether the business is using SIP or Graph API. In other words, the user experience is identical to regular WhatsApp App calls.

  • If the business phone number is SIP enabled, Meta will send an SIP INVITE to the SIP server configured on the business phone number

    • Configure SIP settings on the business phone number below

  • You respond with SIP challenge (recommended) or SIP OK and pass in an SDP answer

For more detailed info, feel free to check Meta Official Documentation.

Common Issues

Error Code
Description
Possible solutions
Http Status Code

138000 Calling not enabled

Calling APIs are not enabled for this phone number

WhatsApp CloudAPI Calling APIs are currently only available to select WhatsApp Business platform partners. Reach out to the Whatsapp Business team to find out more.

401 Unauthorized

138002 Concurrent Calls limit

Limit reached for maximum concurrent calls for the given number

Try again later or reduce the frequency or amount of API calls the app is making.

429 Too many requests

138003 Duplicate call

A call is already ongoing with the receiver

Try again later when the current call ends.

400 Bad Request

138004 Connection error

Error while connecting the call

Try again later or investigate the connection params provided to the API

500

138005 Call rate limit exceeded

Limit reached for maximum calls that can be initiated by the business phone number

Try again later or reduce the frequency or amount of API calls the app is making.

429 Too many requests

131009

Interactive Message type, 'voice_call' not supported. Supported types ['button', 'list’]

Ensure the sender in one of the supported countries.

400 Bad Request

131044

An error webhook is sent on user initiated calls when there is no valid payment method attached

This is similar to the "Business eligibility payment issue" error in messaging.

400 Bad Request

138006 No approved call permission found

No approved call permission from the recipient

Ensure a call permission has been accepted by the consumer

401 Unauthorized

138007 Connect Timeout error

Call was unable to connect due to a timeout

Business did not apply the offer/answer SDP from Cloud API in time. Connect API was not invoked with the answer SDP in time

500

138009 Call Permission Request Limit Hit

Limit reached for call permission request sends for the given business and consumer pair

When a business sends more than the limit of call permission requests per time period, Call Permission Requests are rate limited. A connected call with a consumer will reset the limits.

400

138010 Business Initiated Calls Per Approved Permission Limit Hit

Limit reached for business initiated calls per approved permission request, for the given business and consumer pair

When business attempts more that the limit of calls per approved call permission request, we will rate limit the business initiated calls.

400

138011 Unable to send Call permission request

Unable to send a call permission request message

Attempt was made to send a call permission request message without an open customer service window

400 Bad Request

100 Invalid Parameter

The GraphAPI call you are making has an invalid parameter.

Exact error details will be listed in the error_data section of the response payload.

If its SDP Validation related error then the exact issue will be included in the details.

400 Bad Request

138012 Business Initiated Calls Limit Hit

Limit reached for maximum business initiated calls allowed in 24 hours. Currently 5 connected business initiated calls are allowed within 24 hours.

Exact error details will be listed in the error_data section of the response payload.

Details will include a timestamp when the next call is allowed.

400

Last updated

Was this helpful?