How to Connect WhatsApp Business Cloud Voice Calling to Asterisk with PJSIP (Vanilla Asterisk) – Official WhatsApp Business Cloud API

How to Connect WhatsApp Business Cloud API For Voice Calling to Asterisk with PJSIP (Vanilla Asterisk) with WebRTC/DTLS/ICE

  • First release: 14 Aug 2025 – Initial working release

  • Updated: 16 Aug 2025 – Fixed hangup issue after 30 seconds

Introduction

Meta has officially enabled SIP integration for the WhatsApp Business Cloud API, opening a powerful new channel for customer communication. You can now route WhatsApp voice calls directly to your own Asterisk server.

This guide provides a complete, production-tested configuration for connecting WhatsApp to a “vanilla” Asterisk installation using PJSIP. We’ll focus on creating a stable connection and specifically address common frustrations, like the infamous 30-second call drop, especially for servers on a public IP (e.g., hosted on DigitalOcean, AWS, Vultr, etc.).

Want a quick demo? Add our test number +60327242555 to your contacts and call it from WhatsApp on your mobile. You’ll be connected to a simple IVR for testing purposes.

 

✅ Prerequisites

Before you start, make sure you have the following ready:

  • A WhatsApp Business Number with voice calling enabled via the Meta Cloud API.

  • An Asterisk server with a dedicated public IP address.

  • A valid, trusted TLS certificate (e.g., from Let’s Encrypt) installed on your server. Meta will reject self-signed certificates.

  • Your SIP credentials from the Meta for Developers portal:

    • SIP Username: Your WhatsApp Business Number (e.g., 15551234567).

    • SIP Password: The unique password generated by Meta.

    • SIP Server Hostname: The FQDN you provided to Meta (e.g., sbc.yourcompany.com).

Step 1: Configure Global Network Settings (sip.conf)

Even when using PJSIP for the trunk, you must correctly configure Asterisk’s global SIP settings. This step is crucial for NAT traversal and is the #1 reason calls fail with one-way audio or drop after 30 seconds.

In /etc/asterisk/sip.conf, add the following under the [general] section:

; /etc/asterisk/sip.conf

[general]
; This tells Asterisk its public-facing IP address.
externip = YOUR_SERVER_PUBLIC_IP

; This defines the server's local network.
localnet=127.0.0.1/32

Step 2: Create the Secure PJSIP Transport (pjsip.conf)

Meta requires a secure TLS connection for all SIP traffic. This transport defines the port and certificates Asterisk will use to listen for incoming WhatsApp calls.

Add this to /etc/asterisk/pjsip.conf:

; /etc/asterisk/pjsip.conf

; ====== TRANSPORT DEFINITION ======
[whatsapp-tls]
type=transport
protocol=tls
bind=0.0.0.0:5061
cert_file=/etc/asterisk/keys/fullchain.pem  ; ❗️Update with the correct path to your certificate
priv_key_file=/etc/asterisk/keys/privkey.pem ; ❗️Update with the correct path to your private key
method=tlsv1_2

Note: Ensure the paths to your cert_file and priv_key_file are correct.

 

Step 3: Configure the PJSIP Endpoint (pjsip.conf)

This is the heart of the configuration. We’ll define the authentication details, media handling, and the critical network settings needed to maintain a stable call with Meta’s infrastructure.

Append the following sections to your /etc/asterisk/pjsip.conf file. Remember to replace all placeholder values.

; ====== AUTHENTICATION (For Incoming Calls) ======
[YOUR_WHATSAPP_NUMBER-auth]
type=auth
auth_type=userpass
username=YOUR_WHATSAPP_NUMBER          ; Use number without the '+' sign
password=YOUR_META_GENERATED_PASSWORD

; ====== ADDRESS OF RECORD (AOR) ======
[YOUR_WHATSAPP_NUMBER]
type=aor
max_contacts=5

; ====== ENDPOINT (The Main Trunk Configuration) ======
[YOUR_WHATSAPP_NUMBER]
type=endpoint
transport=whatsapp-tls
context=from-whatsapp                 ; The dialplan context for incoming calls
disallow=all
allow=opus                            ; WhatsApp exclusively uses the Opus codec
aors=YOUR_WHATSAPP_NUMBER
auth=YOUR_WHATSAPP_NUMBER-auth

; --- Critical Media & Connection Settings (Recommended DTLS/WebRTC Setup) ---
; This setup is highly recommended for reliability with Meta's infrastructure.
media_encryption=dtls
dtls_verify=fingerprint
dtls_setup=actpass
webrtc=yes
ice_support=yes                       ; Essential for negotiating the audio path
rtcp_mux=yes                          ; Multiplex RTP and RTCP to save ports

; --- THE 30-SECOND CALL DROP FIX (For Public IP Servers) ---
rewrite_contact=no                    ; ❗️Crucial: Prevents Asterisk from rewriting headers
rtp_symmetric=no                      ; Works in tandem with rewrite_contact=no

; --- Other Required Settings ---
direct_media=no
trust_id_inbound=yes
send_connected_line=no
identify_by=auth_username

; ====== IDENTIFY (Match Incoming Traffic) ======
; This tells Asterisk to associate traffic from WhatsApp's SBC with the endpoint above.
[YOUR_WHATSAPP_NUMBER]
type=identify
endpoint=YOUR_WHATSAPP_NUMBER
match=wa.meta.vc                ; The hostname sent by META (optional)

Why These Settings Matter

  • allow=opus: WhatsApp voice calls use the high-quality Opus codec. No other codecs are needed.

  • webrtc=yes / ice_support=yes: These enable the modern media negotiation techniques (ICE) that WhatsApp’s backend relies on to establish a stable audio path through firewalls and NAT.

  • rewrite_contact=no: This is the magic fix for the 30-second call drop. On a server with a public IP, this setting allows Asterisk to correctly honor the Record-Route headers from Meta’s proxies. This ensures the final ACK message is routed correctly, keeping the call alive beyond the 32-second transaction timeout.


Step 4: Create the Inbound Dialplan (extensions.conf)

Now, we need to tell Asterisk what to do with the call when it arrives. In /etc/asterisk/extensions.conf, create the context you referenced in the PJSIP endpoint (from-whatsapp).

; /etc/asterisk/extensions.conf

[from-whatsapp]
; This context handles all calls from the WhatsApp trunk
; Meta sends the caller ID with a '+' prefix, so we match on _+X.
exten => _+X.,1,NoOp(Incoming WhatsApp call from ${CALLERID(num)} to ${EXTEN})
 same => n,Log(NOTICE, "Routing WhatsApp call to main inbound dialplan")
 same => n,Goto(from-pstn,${EXTEN},1) ; ❗️ IMPORTANT: Change this to your main call-handling context!
 same => n,Hangup()

Be sure to change from-pstn to the actual context where you handle your inbound calls (e.g., an IVR, queue, or ring group).

 

Step 5: Configure Your Firewall

Your server’s firewall must be configured to accept connections from Meta’s servers.

If you are using UFW on Linux, run the following commands:

Bash
# Allow your PJSIP TLS port (defined in Step 2)
sudo ufw allow 5061/tcp

# Allow the standard Asterisk RTP port range for audio
sudo ufw allow 10000:20000/udp

# Reload the firewall to apply changes
sudo ufw reload

Step 6: Reload and Test 🚀

Finally, apply the configuration and watch for your first test call.

  1. From the server’s command line, reload the Asterisk dialplan and PJSIP modules:

    Bash
    asterisk -rx "core reload"
    
  2. Open the Asterisk verbose console to watch the call in real-time:

    Bash
    asterisk -rvvvvv
    
  3. Using your personal WhatsApp account, place a voice call to your WhatsApp Business Number. You should see the call details appear in the console and be routed to the dialplan context you specified.

 

Quick Troubleshooting

  • Problem: Call drops at exactly 32 seconds.

    • Solution: This is almost always a NAT or signaling issue where the final ACK is lost. Double-check that externip is set correctly in sip.conf and that rewrite_contact is set to no in your pjsip.conf endpoint.

  • Problem: Connection fails with 401/403 Unauthorized errors.

    • Solution: Verify your username and password in the [auth] section of pjsip.conf. The username must be your number without the + sign.

  • Problem: No audio or one-way audio.

    • Solution: This is a firewall or media path issue. Ensure your firewall is allowing the RTP port range (e.g., 10000-20000/udp). Also, confirm that ice_support=yes is enabled in the endpoint configuration.

  • Problem: Connection Refused or TLS Handshake Errors.

    • Solution: Check that your TLS certificate is valid, trusted, and not expired. Confirm that the cert_file and priv_key_file paths in the [transport] section are 100% correct.

  • Problem: The first one or two calls fail with “No Answer”.

    • Solution: This can be caused by latency between your server and Meta’s servers (located primarily in the US). During the initial authentication, Meta may improperly reuse an old security key, causing Asterisk to reject it. Moving your server or a proxy closer to the US/Europe (e.g., New York or London) often resolves this timing-sensitive issue.