User-Initiated Calls

Receive inbound voice calls from WhatsApp users. Call Connect webhook with SDP offer, pre-accept for faster setup, accept/reject/terminate actions, DTMF dial pad, companion-device support.

Overview

User-initiated calls (UIC) let WhatsApp users place voice calls to your business. UIC is free for the business and available in every country where Cloud API is available — no permission required. You control when calls are accepted via call_hours and whether the call button is visible via call_icon_visibility.

Consumer Device Eligibility

UIC currently accepts calls only from iPhone and Android phones — including:

  • The user's primary device (their main account device)
  • Companion devices that are iPhone or Android phones

WhatsApp Web, Desktop, tablets, and smart-glass companions are not supported for UIC. If a user attempts to call from those, the call won't reach your endpoint.

callback_permission_status enabled does not work on companion devices yet — only the primary device flow honors it.

Prerequisites

  • Subscribe your app to the calls webhook field.
  • Calling enabled on the business phone number.
  • (Optional but recommended) call_hours configured if you have specific operating hours.
  • (Optional) callback_permission_status: ENABLED if you want auto-permission for callback calls.

The UIC Flow

  1. User taps call button on your business profile (or via Call Buttons & Deep Links).
  2. Call Connect webhook arrives at your endpoint with an SDP offer from Meta.
  3. Pre-accept (recommended): POST /calls action: pre_accept with your SDP answer. Establishes the WebRTC connection without yet flowing call media.
  4. Accept: once your WebRTC stack is ready, POST /calls action: accept. Wait for the 200 OK before sending media.
  5. Terminate: either party hangs up. You receive a Call Terminate webhook.

You have about 30–60 seconds after the Call Connect webhook to accept. If you don't, the call ends on the user's side with "Not Answered" and you receive a Terminate webhook.

Pre-accepting establishes the media connection ahead of time, avoiding the audio clipping that happens when media flows before the WebRTC channel is ready (caller misses the first few words).

POST /<PHONE_NUMBER_ID>/calls
{
  "messaging_product": "whatsapp",
  "call_id": "wacid.HBgLMTIxODU1NTI4MjgVAgARGCAyODRQIAFRoA",
  "action": "pre_accept",
  "session": {
    "sdp_type": "answer",
    "sdp": "<<RFC 8866 SDP>>"
  }
}

Success response:

{ "success": true }

After pre-accept, your WebRTC stack should be initiating ICE connectivity checks. Don't send media yet — wait until you've called accept and received the 200 OK.

Note: if your SDP answer in accept doesn't match the one you sent in pre_accept (same call_id), you'll get an error. Send the same SDP both times.

If you can't control when your media starts flowing (e.g. some IVR systems start playing immediately on connect), skip pre-accept and go straight to accept. Pre-accept's whole point is to frontload connection setup, but it requires you to control media timing.

Accept the Call

{
  "messaging_product": "whatsapp",
  "call_id": "wacid.HBgLMTIxODU1NTI4MjgVAgARGCAyODRQIAFRoA",
  "action": "accept",
  "session": {
    "sdp_type": "answer",
    "sdp": "<<RFC 8866 SDP>>"
  },
  "biz_opaque_callback_data": "0fS5cePMok"
}

Wait for the 200 OK before transmitting call media. If pre-accept was used, the WebRTC connection is already up — media flows immediately. Otherwise, give the connection time to negotiate before pushing audio.

biz_opaque_callback_data is optional. Cloud API doesn't process it; it's echoed back in the subsequent Terminate webhook for your own correlation. Up to 512 chars.

Reject the Call

{
  "messaging_product": "whatsapp",
  "call_id": "wacid.HBgLMTIxODU1NTI4MjgVAgARGCAyODRQIAFRoA",
  "action": "reject"
}

A reject also triggers the Call Terminate webhook with direction: USER_INITIATED and status: COMPLETED or FAILED.

Terminate

{
  "messaging_product": "whatsapp",
  "call_id": "wacid.HBgLMTIxODU1NTI4MjgVAgARGCAyODRQIAFRoA",
  "action": "terminate"
}

Always call terminate even if you sent an RTCP BYE — Meta uses this for accurate billing. You don't need to call it when the user hangs up; you'll just receive the Call Terminate webhook.

Call Connect Webhook (SDP Offer)

{
  "object": "whatsapp_business_account",
  "entry": [
    {
      "id": "102290129340398",
      "changes": [
        {
          "field": "calls",
          "value": {
            "messaging_product": "whatsapp",
            "metadata": {
              "display_phone_number": "15550001234",
              "phone_number_id": "123456789012345"
            },
            "contacts": [
              {
                "profile": { "name": "Pablo Morales" },
                "wa_id": "12015550123"
              }
            ],
            "calls": [
              {
                "id": "wacid.HBgLMTIxODU1NTI4MjgVAgARGCAyODRQIAFRoA",
                "to": "15550001234",
                "from": "12015550123",
                "event": "connect",
                "direction": "USER_INITIATED",
                "timestamp": "1671644824",
                "deeplink_payload": "campaign_id_42",
                "cta_payload": "support_button_v2",
                "session": {
                  "sdp_type": "offer",
                  "sdp": "<<RFC 8866 SDP>>"
                }
              }
            ]
          }
        }
      ]
    }
  ]
}

Apply the SDP offer to your WebRTC stack to generate your SDP answer, then pre_accept or accept with that answer.

Call Terminate Webhook

Same envelope as BIC's terminate webhook but with direction: USER_INITIATED. See Business-Initiated → Call Terminate Webhook for the field reference. UIC terminates can also include deeplink_payload and cta_payload if the call originated from a deep link or CTA button.

Two arbitrary payload strings come through on UIC webhooks when the call originated from a Dualhook-instrumented entry point:

FieldSourceSet on
cta_payloadpayload field on a voice_call interactive message or template buttonWhen user taps the call button on a message you sent
deeplink_payloadbiz_payload query parameter on wa.me/call/<num>?biz_payload=...When user clicks your deep link

Both are echoed back in both the Call Connect webhook and the Call Terminate webhook. Use them to correlate the call with the campaign / page / button that drove it. Available on WhatsApp client version 2.25.27+.

DTMF (Dial Pad) Support

WhatsApp client apps include a dial pad during calls with Cloud API business numbers. Users press tone buttons; the DTMF tones are injected into the WebRTC RTP stream per RFC 4733.

PropertyValue
Clock rate8,000 Hz only (48,000 not supported)
Payload type126 (default if absent in your SDP)
Timestamp / sequence baseSame as regular audio packets
Webhook for DTMF digitsNone — DTMF is in-band only

For BIC, your SDP offer should include 8000 clock rate. For UIC, Meta's SDP offer already has it. The dial pad supports IVR-style flows but doesn't support consumer-to-consumer calls or initiating new calls / messages.

Common Errors

CodeMeaningFix
138000Calling not enabledConfigure call settings (Calling Configuration)
138019Call setup failed (sent in terminate webhook)Retry; check media path
138020Relay connection failed (sent in terminate webhook)Retry; check network
138021Media receive timeout (no media for ~20–30s)Confirm your media server is sending RTP packets
138022Media transmit timeoutVerify outbound media path
138023Call accepted but terminated with no media signalsInvestigate WebRTC setup
131044No valid payment method on user-initiated callAttach a payment method
131055Graph API call attempted on a SIP-enabled numberUse SIP signaling instead

Full error reference on Calling Troubleshooting.

Related

  • Cloud API CallingVoice calling on WhatsApp Business Cloud API: VoIP via WebRTC or SIP, business-initiated and user-initiated calls, prerequisites, availability, and integration patterns.
  • Calling ConfigurationEnable calling on a business phone number, configure call hours and holidays, restrict the call icon by country, set callback permissions, choose audio codecs, listen for settings webhooks.
  • Call Buttons & Deep LinksDrive WhatsApp calls from messages and links: voice_call interactive messages, voice_call template buttons, wa.me/call/<number> deep links with biz_payload tracking.
  • Calling TroubleshootingWhatsApp Calling errors and fixes: full error code table (138000-138023), SIP-specific status codes, media-flow timeouts, audio clipping causes and mitigations (SDES, pre-accept), quick triage guide.
Browse more docsStart Free Trial