# Integration Examples | Developer Documentation

<div id="bkmrk-integration-examples">## Integration Examples

<div><span>Updated: Feb 25, 2026</span></div><div>This guide explains integration of common VoIP platforms with WhatsApp Business Calling API.</div><div><span></span><div>This guide is for information purposes only with no support or warranties of any kind from Meta or any vendor. There are many ways to integrate and the guide explains just one way exclusively for illustrative purposes.</div></div><div id="bkmrk-asterisk-using-sip"><div id="bkmrk-asterisk-using-sip-1"><div>### Asterisk using SIP

</div></div></div><div id="bkmrk-overview"><div id="bkmrk-overview-1"><div>#### Overview

</div></div></div><div>This guide explains how to set up [WhatsApp Business Calling API](/books/meta-whatsapp/page/cloud-api-calling-developer-documentation) using SIP signaling with [Asterisk<span>⁠</span>](https://l.facebook.com/l.php?u=https%3A%2F%2Fwww.asterisk.org%2F&h=AT4Se4Z9JKJ_RQKHLUeLTw9ppBfyr2A-7HBX-JfTqYdGUa_A--Vzc7GDfjf3KHaiJhDKOXMqHde_aCljQXrPQ8J7e_7QekpvVbzUNRQXtWWXZKWYXf1kYJg95rkVpZMijB5IKPOe_Hk9REOhQX7P2g), an open-source PBX (Private Branch Exchange). You’ll learn how to configure your Asterisk server, connect SIP phones, and handle both incoming and outgoing WhatsApp calls.</div><div id="bkmrk-user-initiated-calls"><div id="bkmrk-user-initiated-calls-1"><div>##### User-initiated calls

</div></div></div>
<span>The WhatsApp user dials the business number.</span><span>The call is received by Asterisk and routed through an IVR, prompting the user to enter an extension, registered to the same Asterisk server.</span><span>The call is then connected to the specified extension.</span><div id="bkmrk-business-initiated-c"><div id="bkmrk-business-initiated-c-1"><div>##### Business-initiated calls

</div></div></div>
<span>The business agent/user registers with Asterisk using SIP credentials (see “[Configuring a VoIP Phone](#bkmrk-configuring-a-voip-p-1)” section).</span><span>The business user dials the b2c-sip (business to consumer) extension, which is handled by an IVR. The IVR prompts for the WhatsApp number to call.</span><span>The call is then connected to the WhatsApp user.</span><div>The WA to Asterisk leg uses SDES for media encryption key exchange and opus for audio codec</div><div>The Asterisk to SIP UA leg uses SDES for media encryption key exchange and opus or G711 for audio codec</div><div id="bkmrk-prerequisites"><div id="bkmrk-prerequisites-1"><div>#### Prerequisites

</div></div></div>
<span>Asterisk Deployment: Asterisk is deployed (for example, on a public cloud instance)</span><span>Operating System: Any OS compatible for Asterisk. For example, CentOS 9</span><span>Domain: Asterisk server is reachable via a public domain with valid certificate</span><span>WhatsApp Business API: A WhatsApp business phone number is registered and calling is enabled.</span><span>SIP Support: [SIP is enabled](/books/meta-whatsapp/page/sip-configuration-guide-whatsapp-business-calling-developer-documentation) on the WhatsApp Business Number</span><span>SDES: [SDES is enabled](/books/meta-whatsapp/page/sip-configuration-guide-whatsapp-business-calling-developer-documentation) on the WhatsApp Business Number</span><div id="bkmrk-building-and-install"><div id="bkmrk-building-and-install-1"><div>#### Building and installing Asterisk

</div></div></div><div>Refer to [https://docs.asterisk.org/Getting-Started/Installing-Asterisk/Installing-Asterisk-From-Source/Building-and-Installing-Asterisk/<span>⁠</span>](https://l.facebook.com/l.php?u=https%3A%2F%2Fdocs.asterisk.org%2FGetting-Started%2FInstalling-Asterisk%2FInstalling-Asterisk-From-Source%2FBuilding-and-Installing-Asterisk%2F&h=AT4Se4Z9JKJ_RQKHLUeLTw9ppBfyr2A-7HBX-JfTqYdGUa_A--Vzc7GDfjf3KHaiJhDKOXMqHde_aCljQXrPQ8J7e_7QekpvVbzUNRQXtWWXZKWYXf1kYJg95rkVpZMijB5IKPOe_Hk9REOhQX7P2g)</div><div>This guide was tested using Asterisk version 22.5.2</div><div id="bkmrk-asterisk-configurati"><div id="bkmrk-asterisk-configurati-1"><div>#### Asterisk configuration

</div></div></div><div>These configuration files are placed under /etc/asterisk/</div><div id="bkmrk-extensions.conf"><div id="bkmrk-extensions.conf-1"><div>##### extensions.conf

</div></div></div><div>Replace the following placeholders with actual values</div>
<span>{wa-business-phone-number}: WhatsApp Business Phone Number</span><span>{asterisk-sip-server-dns}: DNS name of your Asterisk SIP server</span><span>incoming\_welcome: incoming\_welcome.wav (not provided) place this file under /var/lib/asterisk/sounds</span><span>outgoing\_welcome: outgoing\_welcome.wav (not provided) place this file under /var/lib/asterisk/sounds</span><div>```
<span>[</span><span>c2b</span><span>-</span><span>sub</span><span>-</span><span>dial</span><span>]</span><span>
exten </span><span>=></span><span> s</span><span>,</span><span>1</span><span>,</span><span>NoOp</span><span>()</span><span>
  same </span><span>=></span><span> n</span><span>,</span><span>Read</span><span>(</span><span>Digits</span><span>,</span><span>incoming_welcome</span><span>,</span><span>0</span><span>,,</span><span>5</span><span>,</span><span>500</span><span>)</span><span>
  same </span><span>=></span><span> n</span><span>,</span><span>Dial</span><span>(</span><span>PJSIP</span><span>/</span><span>$</span><span>{</span><span>Digits</span><span>})</span><span>
  same </span><span>=></span><span> n</span><span>,</span><span>Hangup</span><span>()</span><span>[</span><span>whatsapp</span><span>]</span><span>
exten </span><span>=></span><span> _10XX</span><span>,</span><span>1</span><span>,</span><span>NoOp</span><span>()</span><span>
  same </span><span>=></span><span> n</span><span>,</span><span>Dial</span><span>(</span><span>PJSIP</span><span>/</span><span>$</span><span>{</span><span>EXTEN</span><span>})</span><span>
  same </span><span>=></span><span> n</span><span>,</span><span>Hangup</span><span>()</span><span>;</span><span>Extension</span><span>for</span><span> B2C business call through </span><span>Meta</span><span> SIP gateway
exten </span><span>=></span><span> b2c</span><span>-</span><span>sip</span><span>,</span><span>1</span><span>,</span><span>NoOp</span><span>()</span><span>
  same </span><span>=></span><span> n</span><span>,</span><span>Read</span><span>(</span><span>Digits</span><span>,</span><span>outgoing_welcome</span><span>,</span><span>0</span><span>,,</span><span>5</span><span>,</span><span>500</span><span>)</span><span>
  same </span><span>=></span><span> n</span><span>,</span><span>Dial</span><span>(</span><span>PJSIP</span><span>/</span><span>whatsapp</span><span>/</span><span>sip</span><span>:</span><span>$</span><span>{</span><span>Digits</span><span>}</span><span>@wa</span><span>.</span><span>meta</span><span>.</span><span>vc</span><span>)</span><span>;</span><span>Extension</span><span> to handle incoming invite requests </span><span>from</span><span>Meta</span><span> SIP gateway to </span><span><</span><span>wa</span><span>-</span><span>business</span><span>-</span><span>phone</span><span>-</span><span>number</span><span>>@<</span><span>asterisk</span><span>-</span><span>sip</span><span>-</span><span>server</span><span>-</span><span>dns</span><span>></span><span>
exten </span><span>=></span><span> _</span><span>+<</span><span>wa</span><span>-</span><span>business</span><span>-</span><span>phone</span><span>-</span><span>number</span><span>>,</span><span>1</span><span>,</span><span>Goto</span><span>(</span><span>c2b</span><span>-</span><span>sub</span><span>-</span><span>dial</span><span>,</span><span>s</span><span>,</span><span>1</span><span>)</span>
```

</div><div id="bkmrk-pjsip.conf"><div id="bkmrk-pjsip.conf-1"><div>##### Pjsip.conf

</div></div></div><div>Replace the following placeholders with actual values</div>
<span>{wa-business-phone-number} : the business phone number</span><span>{local-net}: local network of the Asterisk server</span><span>{external-media-address}: Public IP of the Asterisk server media</span><span>{external-signaling-address}: Public IP of the Asterisk server signaling</span><span>{sip-ua-password}: Chosen SIP User Agent password</span><span>{domain-name}: domain name assigned to the Asterisk server</span><div>Certificate files should be placed under /var/lib/asterisk/certs/fullchain.cer /var/lib/asterisk/certs/cer.key</div><div>```
<span>[</span><span>transport</span><span>-</span><span>tls</span><span>]</span><span>
type</span><span>=</span><span>transport
protocol</span><span>=</span><span>tls
bind</span><span>=</span><span>0.0</span><span>.</span><span>0.0</span><span>:</span><span>5061</span><span>
cert_file</span><span>=</span><span>/var/</span><span>lib</span><span>/</span><span>asterisk</span><span>/</span><span>certs</span><span>/</span><span>fullchain</span><span>.</span><span>cer
priv_key_file</span><span>=</span><span>/var/</span><span>lib</span><span>/</span><span>asterisk</span><span>/</span><span>certs</span><span>/</span><span>cer</span><span>.</span><span>key
method</span><span>=</span><span>sslv23
allow_wildcard_certs</span><span>=</span><span>yes
external_media_address</span><span>={</span><span>external</span><span>-</span><span>media</span><span>-</span><span>address</span><span>}</span><span>;</span><span>External</span><span> address </span><span>for</span><span> SIP signalling
external_signaling_address</span><span>={</span><span>external</span><span>-</span><span>signaling</span><span>-</span><span>address</span><span>}</span><span>;</span><span>Network</span><span> to consider </span><span>local</span><span> used </span><span>for</span><span> NAT purposes
local_net</span><span>={</span><span>local</span><span>-</span><span>net</span><span>}</span><span>[</span><span>sdes_endpointtemplate</span><span>](!)</span><span>
type</span><span>=</span><span>endpoint
context</span><span>=</span><span>whatsapp
disallow</span><span>=</span><span>all
allow</span><span>=</span><span>OPUS
direct_media</span><span>=</span><span>no</span><span>
rtp_symmetric</span><span>=</span><span>yes
force_rport</span><span>=</span><span>yes
rewrite_contact</span><span>=</span><span>no</span><span>
media_use_received_transport</span><span>=</span><span>yes
media_encryption</span><span>=</span><span>sdes

</span><span>[</span><span>authtemplate</span><span>](!)</span><span>
type</span><span>=</span><span>auth
auth_type</span><span>=</span><span>userpass
password</span><span>={</span><span>sip</span><span>-</span><span>ua</span><span>-</span><span>password</span><span>}</span><span>[</span><span>aortemplate</span><span>](!)</span><span>
type</span><span>=</span><span>aor
max_contacts</span><span>=</span><span>1</span><span>
remove_existing</span><span>=</span><span>yes

</span><span>[</span><span>aoridentitytemplate</span><span>](!)</span><span>
type</span><span>=</span><span>identify
match_header</span><span>=</span><span>X</span><span>-</span><span>FB</span><span>-</span><span>External</span><span>-</span><span>Domain</span><span>:</span><span> wa</span><span>.</span><span>meta</span><span>.</span><span>vc

</span><span>;</span><span>SDES users
</span><span>[</span><span>1000</span><span>](</span><span>sdes_endpointtemplate</span><span>)</span><span>
auth</span><span>=</span><span>1000</span><span>_auth
aors</span><span>=</span><span>1000</span><span>[</span><span>1000</span><span>_auth</span><span>](</span><span>authtemplate</span><span>)</span><span>
username</span><span>=</span><span>1000</span><span>[</span><span>1000</span><span>](</span><span>aortemplate</span><span>)</span><span>[</span><span>1000</span><span>](</span><span>aoridentitytemplate</span><span>)</span><span>
endpoint</span><span>=</span><span>1000</span><span>[</span><span>1001</span><span>](</span><span>sdes_endpointtemplate</span><span>)</span><span>
auth</span><span>=</span><span>1001</span><span>_auth
aors</span><span>=</span><span>1001</span><span>[</span><span>1001</span><span>_auth</span><span>](</span><span>authtemplate</span><span>)</span><span>
username</span><span>=</span><span>1001</span><span>[</span><span>1001</span><span>](</span><span>aortemplate</span><span>)</span><span>[</span><span>1001</span><span>](</span><span>aoridentitytemplate</span><span>)</span><span>
endpoint</span><span>=</span><span>1001</span><span>[</span><span>1002</span><span>](</span><span>sdes_endpointtemplate</span><span>)</span><span>
auth</span><span>=</span><span>1002</span><span>_auth
aors</span><span>=</span><span>1002</span><span>[</span><span>1002</span><span>_auth</span><span>](</span><span>authtemplate</span><span>)</span><span>
username</span><span>=</span><span>1002</span><span>[</span><span>1002</span><span>](</span><span>aortemplate</span><span>)</span><span>[</span><span>1002</span><span>](</span><span>aoridentitytemplate</span><span>)</span><span>
endpoint</span><span>=</span><span>1002</span><span>[</span><span>1003</span><span>](</span><span>sdes_endpointtemplate</span><span>)</span><span>
auth</span><span>=</span><span>1003</span><span>_auth
aors</span><span>=</span><span>1003</span><span>[</span><span>1003</span><span>_auth</span><span>](</span><span>authtemplate</span><span>)</span><span>
username</span><span>=</span><span>1003</span><span>[</span><span>1003</span><span>](</span><span>aortemplate</span><span>)</span><span>[</span><span>1003</span><span>](</span><span>aoridentitytemplate</span><span>)</span><span>
endpoint</span><span>=</span><span>1003</span><span>[</span><span>1004</span><span>](</span><span>sdes_endpointtemplate</span><span>)</span><span>
auth</span><span>=</span><span>1004</span><span>_auth
aors</span><span>=</span><span>1004</span><span>[</span><span>1004</span><span>_auth</span><span>](</span><span>authtemplate</span><span>)</span><span>
username</span><span>=</span><span>1004</span><span>[</span><span>1004</span><span>](</span><span>aortemplate</span><span>)</span><span>[</span><span>1004</span><span>](</span><span>aoridentitytemplate</span><span>)</span><span>
endpoint</span><span>=</span><span>1004</span><span>[</span><span>1005</span><span>](</span><span>sdes_endpointtemplate</span><span>)</span><span>
auth</span><span>=</span><span>1005</span><span>_auth
aors</span><span>=</span><span>1005</span><span>[</span><span>1005</span><span>_auth</span><span>](</span><span>authtemplate</span><span>)</span><span>
username</span><span>=</span><span>1005</span><span>[</span><span>1005</span><span>](</span><span>aortemplate</span><span>)</span><span>[</span><span>1005</span><span>](</span><span>aoridentitytemplate</span><span>)</span><span>
endpoint</span><span>=</span><span>1005</span><span>;</span><span>This</span><span> endpoint maps to an IVR </span><span>for</span><span> C2B calls
</span><span>[</span><span>c2b</span><span>-</span><span>sip</span><span>](</span><span>sdes_endpointtemplate</span><span>)</span><span>[</span><span>c2b</span><span>-</span><span>sip</span><span>](</span><span>aortemplate</span><span>)</span><span>[</span><span>c2b</span><span>-</span><span>sip</span><span>]</span><span>
type</span><span>=</span><span>identify
endpoint</span><span>=</span><span>c2b</span><span>-</span><span>sip
match_header</span><span>=</span><span>X</span><span>-</span><span>FB</span><span>-</span><span>External</span><span>-</span><span>Domain</span><span>:</span><span> wa</span><span>.</span><span>meta</span><span>.</span><span>vc

</span><span>;</span><span>special endpoint </span><span>for</span><span>Meta</span><span> SIP </span><span>Gateway</span><span> integration
</span><span>;</span><span>This</span><span> endpoint maps to an IVR </span><span>for</span><span> B2C calls
</span><span>[</span><span>b2c</span><span>-</span><span>sip</span><span>](</span><span>sdes_endpointtemplate</span><span>)</span><span>[</span><span>b2c</span><span>-</span><span>sip</span><span>](</span><span>aortemplate</span><span>)</span><span>[</span><span>whatsapp</span><span>](</span><span>sdes_endpointtemplate</span><span>)</span><span>
type</span><span>=</span><span>endpoint
transport</span><span>=</span><span>transport</span><span>-</span><span>tls
disallow</span><span>=</span><span>all
allow</span><span>=</span><span>opus</span><span>,</span><span>ulaw</span><span>,</span><span>alaw
aors</span><span>=</span><span>whatsapp
from_user</span><span>={</span><span>wa</span><span>-</span><span>business</span><span>-</span><span>phone</span><span>-</span><span>number</span><span>}</span><span>
from_domain</span><span>={</span><span>domain</span><span>-</span><span>name</span><span>}</span><span>
outbound_auth</span><span>=</span><span>whatsapp

</span><span>[</span><span>whatsapp</span><span>]</span><span>
type</span><span>=</span><span>aor
contact</span><span>=</span><span>sip</span><span>:</span><span>wa</span><span>.</span><span>meta</span><span>.</span><span>vc

</span><span>[</span><span>whatsapp</span><span>]</span><span>
type</span><span>=</span><span>identify
endpoint</span><span>=</span><span>whatsapp

</span><span>[</span><span>whatsapp</span><span>]</span><span>
type</span><span>=</span><span>auth
auth_type</span><span>=</span><span>digest
password</span><span>={</span><span>meta</span><span>-</span><span>sip</span><span>-</span><span>user</span><span>-</span><span>password</span><span>}</span><span>
username</span><span>={</span><span>wa</span><span>-</span><span>business</span><span>-</span><span>phone</span><span>-</span><span>number</span><span>}</span><span>
realm</span><span>=*</span>
```

</div><div id="bkmrk-rtp.conf"><div id="bkmrk-rtp.conf-1"><div>##### rtp.conf

</div></div></div><div>```
<span>[</span><span>general</span><span>]</span><span>;</span><span>Hostname</span><span>or</span><span> address </span><span>for</span><span> the STUN server used </span><span>for</span><span> determining the external
</span><span>;</span><span> IP address </span><span>and</span><span> port an RTP session can be reached at</span><span>.</span><span>The</span><span> port number </span><span>is</span><span>;</span><span> optional</span><span>.</span><span>If</span><span> omitted </span><span>default</span><span> value of </span><span>3478</span><span> will be used</span><span>.</span><span>This</span><span> option </span><span>is</span><span>;</span><span> disabled </span><span>by</span><span>default</span><span>.</span><span>Name</span><span> resolution occurs at load time</span><span>,</span><span>and</span><span>if</span><span> DNS </span><span>is</span><span>;</span><span> used</span><span>,</span><span> name resolution will occur repeatedly after the TTL expires</span><span>.</span><span>;</span><span>;</span><span>for</span><span> example stundaddr</span><span>=</span><span>mystun</span><span>.</span><span>server</span><span>.</span><span>com</span><span>:</span><span>3478</span><span>;</span><span>
stunaddr</span><span>=</span><span>stun</span><span>.</span><span>l</span><span>.</span><span>google</span><span>.</span><span>com</span><span>:</span><span>19302</span><span>

rtpstart</span><span>=</span><span>10000</span><span>
rtpend</span><span>=</span><span>60000</span>
```

</div><div id="bkmrk-configuring-a-voip-p"><div id="bkmrk-configuring-a-voip-p-1"><div>#### Configuring a VoIP phone

</div></div></div><div>Download and install a softphone client (for example, [Linphone<span>⁠</span>](https://l.facebook.com/l.php?u=https%3A%2F%2Fwww.linphone.org%2Fen%2Fdownload&h=AT4Se4Z9JKJ_RQKHLUeLTw9ppBfyr2A-7HBX-JfTqYdGUa_A--Vzc7GDfjf3KHaiJhDKOXMqHde_aCljQXrPQ8J7e_7QekpvVbzUNRQXtWWXZKWYXf1kYJg95rkVpZMijB5IKPOe_Hk9REOhQX7P2g)) for testing both business-initiated and user-initiated calls.</div><div id="bkmrk-account-setup"><div id="bkmrk-account-setup-1"><div>##### Account setup

</div></div></div>
<span>Select an extension to register as a SIP UA (extensions 1001–1005).</span><span>Open Preferences.</span><span>Under “SIP Accounts,” click “Add account.”</span><span>Enter the following details: </span>
<span>SIP Address: for example, sip:1001@{asterisk-sip-server-dns}</span><span>SIP Server Address: for example, sip:{asterisk-sip-server-dns};transport=tls</span><span>Transport: TLS</span><span>Disable ICE</span><span>Enable AVPF</span><span>Disable “Publish presence information”</span><span>Confirm and save the account.</span><span>Enter the password when prompted (viz. {sip-ua-password})</span><span>Once connected, return to Preferences and select the “Audio” tab. Enable all audio codecs.</span><span>In the “Calls and Chat” tab: </span>
<span>Select “Encryption”</span><span>Choose “SRTP-SDES”</span><span>Enable “Encryption is mandatory”</span><span>Confirm settings</span><div id="bkmrk-final-checklist"><div id="bkmrk-final-checklist-1"><div>#### Final checklist

</div></div></div>
<span>Double-check all configuration files for correct numbers, passwords, and domain names.</span><span>Make sure your firewall allows SIP (5061/TLS) and RTP (10000-20000) ports.</span><span>For more details on SIP password setup, see the [WhatsApp Cloud API documentation](/books/meta-whatsapp/page/sip-configuration-guide-whatsapp-business-calling-developer-documentation).</span><div id="bkmrk-troubleshooting"><div id="bkmrk-troubleshooting-1"><div>#### Troubleshooting

</div></div></div><div id="bkmrk-cannot-register-sip-"><div id="bkmrk-cannot-register-sip--1"><div>##### Cannot register SIP UA

</div></div></div><div>Confirm that the SIP URL is correct and the domain is pointing to the Asterisk server. Run host {domain-name} to verify that the IP address points to the Asterisk server.</div><div id="bkmrk-not-receiving-ack-fr"><div id="bkmrk-not-receiving-ack-fr-1"><div>##### Not receiving ACK from Meta OR Business audio stops around 30s OR Meta returns 404 response to BYE

</div></div></div><div>For a user initiated call, Meta sends a `SIP INVITE` to your SIP server which then responds with `200 OK`. Meta acks your `200 OK` with an `ACK` but you never receive this ACK. So your SIP server keeps resending the `200 OK` and ultimately the SIP dialog is terminated due to ACK timeout (typically 32s).</div><div>The most likely cause for this problem is incorrect `Record-Route` headers in your `200 OK` to Meta. The `200 OK` response is supposed to not modify the `Record-Route` headers included in the original Meta’s `INVITE`. Your SIP server can add new `Record-Route` headers but cannot modify those present in our `INVITE`</div><div>The solution to this problem is to change `rewrite_contact=yes` to `rewrite_contact=no` on the WhatsApp endpoint configuration in pjsip.conf file. After this make sure your `200 OK` has following headers as the last 2 in the list of `Record-Route` headers</div><div>This problem is hard to detect or diagnose. Even with this bug, the call will get connected and media will flow both sides but around 32s later, your SIP server will terminate the call which won’t be propagated to WhatsApp client because your BYE request has incorrect `Route` headers. So WA user stops hearing business audio around 32s.</div><div>```
<span>Record</span><span>-</span><span>Route</span><span>:</span><span><</span><span>sip</span><span>:</span><span>wa</span><span>.</span><span>meta</span><span>.</span><span>vc</span><span>;</span><span>transport</span><span>=</span><span>tls</span><span>;</span><span>lr</span><span>></span><span>Record</span><span>-</span><span>Route</span><span>:</span><span><</span><span>sip</span><span>:</span><span>onevc</span><span>-</span><span>sip</span><span>-</span><span>proxy</span><span>.</span><span>fbinfra</span><span>.</span><span>net</span><span>:</span><span>8191</span><span>;</span><span>transport</span><span>=</span><span>tls</span><span>;</span><span>lr</span><span>></span>
```

</div><div id="bkmrk-freeswitch-using-sip"><div id="bkmrk-freeswitch-using-sip-1"><div>### FreeSWITCH using SIP

</div></div></div><div id="bkmrk-overview-3"><div id="bkmrk-overview-4"><div>#### Overview

</div></div></div><div>This guide explains how to set up [WhatsApp Business Calling API](/books/meta-whatsapp/page/cloud-api-calling-developer-documentation) using SIP signaling with [FreeSWITCH<span>⁠</span>](https://l.facebook.com/l.php?u=https%3A%2F%2Fsignalwire.com%2Ffreeswitch&h=AT4Se4Z9JKJ_RQKHLUeLTw9ppBfyr2A-7HBX-JfTqYdGUa_A--Vzc7GDfjf3KHaiJhDKOXMqHde_aCljQXrPQ8J7e_7QekpvVbzUNRQXtWWXZKWYXf1kYJg95rkVpZMijB5IKPOe_Hk9REOhQX7P2g), an open-source communication framework. You’ll learn how to configure your FreeSWITCH server, connect SIP phones, and handle both user-initiated and business-initiated WhatsApp calls.</div><div id="bkmrk-user-initiated-calls-3"><div id="bkmrk-user-initiated-calls-4"><div>##### User-initiated calls

</div></div></div>
<span>The WhatsApp user dials the business number.</span><span>The call is received by FreeSWITCH and routed through an IVR, which prompts the user to enter an agent’s extension registered on the same FreeSWITCH server.</span><span>Once the extension is entered, the call is connected to the specified recipient agent.</span><div id="bkmrk-business-initiated-c-3"><div id="bkmrk-business-initiated-c-4"><div>##### Business-initiated calls

</div></div></div>
<span>The business agent or user registers with FreeSWITCH using SIP credentials (see the [Configuring a VoIP Phone](/books/meta-whatsapp/page/integration-examples-developer-documentation) section for details).</span><span>The business user dials the b2c-sip (business-to-consumer) extension, which is managed by an IVR. The IVR then prompts for the WhatsApp number to call.</span><span>After the number is entered, the call is connected to the WhatsApp user via SIP.</span><div>The WA to FreeSWITCH leg uses SDES for media encryption key exchange with Opus as the audio codec. FreeSWITCH - SIP UA leg uses SDES for media encryption key exchange with Opus or G.711 audio codecs</div><div id="bkmrk-prerequisites-3"><div id="bkmrk-prerequisites-4"><div>#### Prerequisites

</div></div></div>
<span>FreeSWITCH Deployment: FreeSWITCH is deployed (for example, on a public cloud instance)</span><span>Operating System: Any OS compatible with FreeSWITCH. For example, CentOS 9</span><span>Domain: FreeSWITCH server is reachable via a public domain with a valid certificate</span><span>WhatsApp Business API: A WhatsApp business phone number is registered and [calling is enabled](https://support2.chatarchitect.com/books/meta-whatsapp/page/configure-call-settings-%7C-developer-documentation).</span><span>SIP Support: [SIP is enabled](/books/meta-whatsapp/page/sip-configuration-guide-whatsapp-business-calling-developer-documentation) on the WhatsApp Business Number </span>
<span>Note: FreeSWITCH is configured to listen on 5081 for TLS</span><span>SDES: [SDES is enabled](/books/meta-whatsapp/page/sip-configuration-guide-whatsapp-business-calling-developer-documentation) on the WhatsApp Business Number</span><div id="bkmrk-building-and-install-3"><div id="bkmrk-building-and-install-4"><div>#### Building and installing FreeSWITCH

</div></div></div><div>Refer to [https://developer.signalwire.com/freeswitch/FreeSWITCH-Explained/Installation/<span>⁠</span>](https://l.facebook.com/l.php?u=https%3A%2F%2Fdeveloper.signalwire.com%2Ffreeswitch%2FFreeSWITCH-Explained%2FInstallation%2F&h=AT4Se4Z9JKJ_RQKHLUeLTw9ppBfyr2A-7HBX-JfTqYdGUa_A--Vzc7GDfjf3KHaiJhDKOXMqHde_aCljQXrPQ8J7e_7QekpvVbzUNRQXtWWXZKWYXf1kYJg95rkVpZMijB5IKPOe_Hk9REOhQX7P2g)</div><div>This guide was tested using FreeSWITCH version 1.10.12. FreeSWITCH uses sofia (an open-source SIP user agent library). Sofia v1.13.17 was used for this guide</div><div id="bkmrk-freeswitch-configura"><div id="bkmrk-freeswitch-configura-1"><div>##### FreeSWITCH configuration

</div></div></div><div>These configuration files are placed under /usr/share/freeswitch/etc/freeswitch</div><div>**wa-biz-api-dialplan.xml**</div><div>Place the dial plan under /usr/share/freeswitch/etc/freeswitch/dialplan/default/wa-biz-api-dialplan.xml</div><div>```
<span><include></span><span><extension</span><span>name</span><span>=</span><span>"c2b_calls_sip_ivr"</span><span>></span><span><!--Dial plan is selected if the SIP request is coming from Meta--></span><span><condition</span><span>field</span><span>=</span><span>"${sip_from_host}"</span><span>expression</span><span>=</span><span>"^wa.meta.vc$"</span><span>></span><span><!--Verify the IP from where the request is coming, compare the IP with the Meta allowlisted IPs--></span><span><action</span><span>application</span><span>=</span><span>"check_acl"</span><span>data</span><span>=</span><span>"${network_addr} whatsapp_allow normal_clearing"</span><span>/></span><span><!--Enable encrypted media using SDES--></span><span><action</span><span>application</span><span>=</span><span>"set"</span><span>data</span><span>=</span><span>"rtp_secure_media=true"</span><span>/></span><span><action</span><span>application</span><span>=</span><span>"answer"</span><span>/></span><span><!--Add silence stream for  1 sec so that the media path is established between whatsapp and freeswitch to avoid audio clipping--></span><span><action</span><span>application</span><span>=</span><span>"playback"</span><span>data</span><span>=</span><span>"silence_stream://1000"</span><span>/></span><span><action</span><span>application</span><span>=</span><span>"play_and_get_digits"</span><span>data</span><span>=</span><span>"2 5 3 7000 # $${base_dir}/sounds/incoming_welcome.wav  $${base_dir}/sounds/incoming_invalid.wav extension \d+"</span><span>/></span><span><!--While the call is being bridged, play a ringtone for the caller--></span><span><action</span><span>application</span><span>=</span><span>"set"</span><span>data</span><span>=</span><span>"ringback=%(2000, 4000, 440.0, 480.0)"</span><span>/></span><span><!--Offer G711 and Opus for FreeSWITCH-SIP UA leg --></span><span><action</span><span>application</span><span>=</span><span>"export"</span><span>data</span><span>=</span><span>"nolocal:absolute_codec_string=PCMA,PCMU,OPUS@48000h@20i"</span><span>/></span><span><action</span><span>application</span><span>=</span><span>"bridge"</span><span>data</span><span>=</span><span>"user/${extension}"</span><span>/></span><span><action</span><span>application</span><span>=</span><span>"hangup"</span><span>/></span><span></condition></span><span></extension></span><span><extension</span><span>name</span><span>=</span><span>"b2c_calls_ivr"</span><span>></span><span><condition</span><span>field</span><span>=</span><span>"destination_number"</span><span>expression</span><span>=</span><span>"^b2c-sip$"</span><span>></span><span><!--Enable encrypted media using SDES--></span><span><action</span><span>application</span><span>=</span><span>"set"</span><span>data</span><span>=</span><span>"rtp_secure_media=true"</span><span>/></span><span><action</span><span>application</span><span>=</span><span>"answer"</span><span>/></span><span><action</span><span>application</span><span>=</span><span>"playback"</span><span>data</span><span>=</span><span>"silence_stream://1000"</span><span>/></span><span><action</span><span>application</span><span>=</span><span>"set"</span><span>data</span><span>=</span><span>"caller_id_check=${caller_id_number}"</span><span>/></span><span><action</span><span>application</span><span>=</span><span>"play_and_get_digits"</span><span>data</span><span>=</span><span>"2 12 3 20000 # $${base_dir}/sounds/outgoing_welcome.wav $${base_dir}/sounds/outgoing_invalid.wav whatsapp_number \d+"</span><span>/></span><span><action</span><span>application</span><span>=</span><span>"log"</span><span>data</span><span>=</span><span>"INFO [whatsapp_number] is ${whatsapp_number}"</span><span>/></span><span><!--While the call is being bridged, play a ringtone for the caller--></span><span><action</span><span>application</span><span>=</span><span>"set"</span><span>data</span><span>=</span><span>"ringback=%(2000, 4000, 440.0, 480.0)"</span><span>/></span><span><!--Offer only OPUS--></span><span><action</span><span>application</span><span>=</span><span>"export"</span><span>data</span><span>=</span><span>"nolocal:absolute_codec_string=OPUS@48000h@20i,OPUS@8000h@20i"</span><span>/></span><span><!--Bridge the call by calling META SIP with the WA Number--></span><span><action</span><span>application</span><span>=</span><span>"bridge"</span><span>data</span><span>=</span><span>"sofia/gateway/whatsapp/+${whatsapp_number}"</span><span>/></span><span><action</span><span>application</span><span>=</span><span>"hangup"</span><span>/></span><span></condition></span><span></extension></span><span></include></span>
```

</div><div>Audio files should be placed under /usr/share/freeswitch/sounds (not provided)</div>
<span>incoming\_welcome.wav</span><span>Incoming\_invalid.wav</span><span>outgoing\_welcome.wav</span><span>outgoing\_invalid.wav</span><div>**whatsapp.xml**</div><div>This file configures the WhatsApp gateway, copy the file to /usr/share/freeswitch/etc/freeswitch/sip_profiles/external/whatsapp.xml</div><div>```
<span><!--Gateway configuration for Meta SIP--></span><span><!--replace {phone-number},{meta-sip-password} and {domain-name} before starting FreeSWITCH--></span><span><include></span><span><gateway</span><span>name</span><span>=</span><span>"whatsapp"</span><span>></span><span><param</span><span>name</span><span>=</span><span>"username"</span><span>value</span><span>=</span><span>"{phone-number}"</span><span>/></span><span><param</span><span>name</span><span>=</span><span>"password"</span><span>value</span><span>=</span><span>"{meta-sip-password}"</span><span>/></span><span><param</span><span>name</span><span>=</span><span>"register"</span><span>value</span><span>=</span><span>"false"</span><span>/></span><span><param</span><span>name</span><span>=</span><span>"realm"</span><span>value</span><span>=</span><span>"wa.meta.vc"</span><span>/></span><span><param</span><span>name</span><span>=</span><span>"from-user"</span><span>value</span><span>=</span><span>"{phone-number}"</span><span>/></span><span><param</span><span>name</span><span>=</span><span>"from-domain"</span><span>value</span><span>=</span><span>"{domain-name}"</span><span>/></span><span></gateway></span><span></include></span>
```

</div><div>Replace the following placeholders with actual values</div>
<span>{phone-number}: WhatsApp Business Phone Number</span><span>{meta-sip-password}: SIP password issued by Meta. For more details on SIP password setup, see the [WhatsApp Cloud API documentation](/books/meta-whatsapp/page/sip-configuration-guide-whatsapp-business-calling-developer-documentation).</span><span>{domain-name}: DNS name of your FreeSWITCH SIP server</span><div>**acl.conf.xml**</div><div>Open /usr/share/freeswitch/etc/freeswitch/autoload_configs/acl.conf.xml</div><div>Add the following list under `network-lists` element</div><div>```
<span><!--IP addresses from Meta that are allowed to send SIP requests via the gateway. Keep this up to date--></span><span><list</span><span>name</span><span>=</span><span>"whatsapp_allow"</span><span>default</span><span>=</span><span>"deny"</span><span>></span><span><node</span><span>type</span><span>=</span><span>"allow"</span><span>cidr</span><span>=</span><span>"31.13.24.0/21"</span><span>/></span><span><node</span><span>type</span><span>=</span><span>"allow"</span><span>cidr</span><span>=</span><span>"31.13.64.0/18"</span><span>/></span><span><node</span><span>type</span><span>=</span><span>"allow"</span><span>cidr</span><span>=</span><span>"45.64.40.0/22"</span><span>/></span><span><node</span><span>type</span><span>=</span><span>"allow"</span><span>cidr</span><span>=</span><span>"57.141.0.0/21"</span><span>/></span><span><node</span><span>type</span><span>=</span><span>"allow"</span><span>cidr</span><span>=</span><span>"57.141.8.0/22"</span><span>/></span><span><node</span><span>type</span><span>=</span><span>"allow"</span><span>cidr</span><span>=</span><span>"57.141.12.0/23"</span><span>/></span><span><node</span><span>type</span><span>=</span><span>"allow"</span><span>cidr</span><span>=</span><span>"57.144.0.0/14"</span><span>/></span><span><node</span><span>type</span><span>=</span><span>"allow"</span><span>cidr</span><span>=</span><span>"66.220.144.0/20"</span><span>/></span><span><node</span><span>type</span><span>=</span><span>"allow"</span><span>cidr</span><span>=</span><span>"69.63.176.0/20"</span><span>/></span><span><node</span><span>type</span><span>=</span><span>"allow"</span><span>cidr</span><span>=</span><span>"69.171.224.0/19"</span><span>/></span><span><node</span><span>type</span><span>=</span><span>"allow"</span><span>cidr</span><span>=</span><span>"74.119.76.0/22"</span><span>/></span><span><node</span><span>type</span><span>=</span><span>"allow"</span><span>cidr</span><span>=</span><span>"102.132.96.0/20"</span><span>/></span><span><node</span><span>type</span><span>=</span><span>"allow"</span><span>cidr</span><span>=</span><span>"103.4.96.0/22"</span><span>/></span><span><node</span><span>type</span><span>=</span><span>"allow"</span><span>cidr</span><span>=</span><span>"129.134.0.0/16"</span><span>/></span><span><node</span><span>type</span><span>=</span><span>"allow"</span><span>cidr</span><span>=</span><span>"147.75.208.0/20"</span><span>/></span><span><node</span><span>type</span><span>=</span><span>"allow"</span><span>cidr</span><span>=</span><span>"157.240.0.0/16"</span><span>/></span><span><node</span><span>type</span><span>=</span><span>"allow"</span><span>cidr</span><span>=</span><span>"163.70.128.0/17"</span><span>/></span><span><node</span><span>type</span><span>=</span><span>"allow"</span><span>cidr</span><span>=</span><span>"163.77.128.0/17"</span><span>/></span><span><node</span><span>type</span><span>=</span><span>"allow"</span><span>cidr</span><span>=</span><span>"173.252.64.0/18"</span><span>/></span><span><node</span><span>type</span><span>=</span><span>"allow"</span><span>cidr</span><span>=</span><span>"179.60.192.0/22"</span><span>/></span><span><node</span><span>type</span><span>=</span><span>"allow"</span><span>cidr</span><span>=</span><span>"185.60.216.0/22"</span><span>/></span><span><node</span><span>type</span><span>=</span><span>"allow"</span><span>cidr</span><span>=</span><span>"185.89.216.0/22"</span><span>/></span><span><node</span><span>type</span><span>=</span><span>"allow"</span><span>cidr</span><span>=</span><span>"204.15.20.0/22"</span><span>/></span><span></list></span>
```

</div><div>**vars.xml**</div><div>Modify /usr/share/freeswitch/etc/freeswitch/vars.xml</div><div>```
<span>Add</span><span> line </span><span><</span><span>X</span><span>-</span><span>PRE</span><span>-</span><span>PROCESS cmd</span><span>=</span><span>"set"</span><span> data</span><span>=</span><span>"rtp_secure_media=mandatory"</span><span>/></span><span> under </span><span><include></span><span>Replace</span><span><</span><span>X</span><span>-</span><span>PRE</span><span>-</span><span>PROCESS cmd</span><span>=</span><span>"set"</span><span> data</span><span>=</span><span>"default_password=1234"</span><span>/></span><span>with</span><span>(</span><span>substitute </span><span>{</span><span>sip_ua_password</span><span>}</span><span>with</span><span> your password</span><span>)</span><span><</span><span>X</span><span>-</span><span>PRE</span><span>-</span><span>PROCESS cmd</span><span>=</span><span>"set"</span><span> data</span><span>=</span><span>"default_password={sip-ua-password}"</span><span>/></span><span>Replace</span><span><</span><span>X</span><span>-</span><span>PRE</span><span>-</span><span>PROCESS cmd</span><span>=</span><span>"set"</span><span> data</span><span>=</span><span>"domain=$${local_ip_v4}"</span><span>/></span><span>with</span><span>(</span><span>substitute </span><span>{</span><span>domain</span><span>-</span><span>name</span><span>}</span><span>with</span><span> your </span><span>FreeSWITCH</span><span> SIP server DNS</span><span>)</span><span><</span><span>X</span><span>-</span><span>PRE</span><span>-</span><span>PROCESS cmd</span><span>=</span><span>"set"</span><span> data</span><span>=</span><span>"domain={domain-name}”/>

Replace
  <X-PRE-PROCESS cmd="</span><span>stun</span><span>-</span><span>set</span><span>" data="</span><span>external_sip_ip</span><span>=</span><span>stun</span><span>:</span><span>stun</span><span>.</span><span>freeswitch</span><span>.</span><span>org</span><span>"/>
with (substitute {external-ip} with your FreeSWITCH public ip)
  <X-PRE-PROCESS cmd="</span><span>set</span><span>" data="</span><span>external_sip_ip</span><span>={</span><span>external</span><span>-</span><span>ip</span><span>}</span><span>"/>

Replace
  <X-PRE-PROCESS cmd="</span><span>stun</span><span>-</span><span>set</span><span>" data="</span><span>external_rtp_ip</span><span>=</span><span>stun</span><span>:</span><span>stun</span><span>.</span><span>freeswitch</span><span>.</span><span>org</span><span>"/>
with (substitute {external-ip} with your FreeSWITCH public ip)
  <X-PRE-PROCESS cmd="</span><span>stun</span><span>-</span><span>set</span><span>" data="</span><span>external_rtp_ip</span><span>={</span><span>external</span><span>-</span><span>ip</span><span>}</span><span>"/></span>
```

</div><div>**internal.xml**</div><div>Modify /usr/share/freeswitch/etc/freeswitch/sip_profiles/internal.xml Look for:</div><div>```
<span><param</span><span>name</span><span>=</span><span>"sip-trace"</span><span>value</span><span>=</span><span>"no"</span><span>/></span>
```

</div><div>Replace it with</div><div>```
<span><param</span><span>name</span><span>=</span><span>"sip-trace"</span><span>value</span><span>=</span><span>"yes"</span><span>/></span>
```

</div><div>**external.xml**Modify /usr/share/freeswitch/etc/freeswitch/sip_profiles/external.xml</div><div>```
<span>Replace</span><span><</span><span>param name</span><span>=</span><span>"sip-trace"</span><span> value</span><span>=</span><span>"no"</span><span>/></span><span>with</span><span><</span><span>param name</span><span>=</span><span>"sip-trace"</span><span> value</span><span>=</span><span>"yes"</span><span>/></span><span>Replace</span><span><</span><span>param name</span><span>=</span><span>"tls"</span><span> value</span><span>=</span><span>"$${external_ssl_enable}"</span><span>/></span><span>with</span><span><</span><span>param name</span><span>=</span><span>"tls"</span><span> value</span><span>=</span><span>"true"</span><span>/></span><span>Replace</span><span><!--<</span><span>param name</span><span>=</span><span>"tls-cert-dir"</span><span> value</span><span>=</span><span>""</span><span>/>--></span><span>with</span><span><</span><span>param name</span><span>=</span><span>"tls-cert-dir"</span><span> value</span><span>=</span><span>"/usr/share/freeswitch/etc/freeswitch/certs"</span><span>/></span>
```

</div><div>Make sure certificates are placed under /usr/share/freeswitch/etc/freeswitch/certs</div><div id="bkmrk-final-checklist-3"><div id="bkmrk-final-checklist-4"><div>#### Final checklist

</div></div></div>
<span>Double-check all configuration files for correct numbers, passwords, and domain names.</span><span>Make sure your firewall allows SIP (5081/TLS) and RTP (10000-20000) ports.</span><span>For more details on SIP password setup, see the [WhatsApp Cloud API documentation](/books/meta-whatsapp/page/sip-configuration-guide-whatsapp-business-calling-developer-documentation).</span><div id="bkmrk-troubleshooting-3"><div id="bkmrk-troubleshooting-4"><div>#### Troubleshooting

</div></div></div><div id="bkmrk-cannot-register-sip--3"><div id="bkmrk-cannot-register-sip--4"><div>##### Cannot register SIP UA

</div></div></div><div>Confirm that the SIP URL is correct and the domain is pointing to the FreeSWITCH server. Run host {domain-name} to verify that the IP address points to the FreeSWITCH server.</div><div id="bkmrk-trace-sip-messages"><div id="bkmrk-trace-sip-messages-1"><div>##### Trace SIP messages

</div></div></div><div>Start CLI (/usr/share/freeswitch/bin/fs_cli) to view SIP messages</div><div id="bkmrk-freeswitch-using-gra"><div id="bkmrk-freeswitch-using-gra-1"><div>### FreeSWITCH using Graph API with Janus

</div></div></div><div id="bkmrk-overview-6"><div id="bkmrk-overview-7"><div>#### Overview

</div></div></div><div>This guide explains how to set up [WhatsApp Business Calling API](/books/meta-whatsapp/page/cloud-api-calling-developer-documentation) using [WhatsApp Cloud API signaling](/books/meta-whatsapp/page/business-initiated-calls-developer-documentation) with [FreeSWITCH<span>⁠</span>](https://l.facebook.com/l.php?u=https%3A%2F%2Fsignalwire.com%2Ffreeswitch&h=AT4Se4Z9JKJ_RQKHLUeLTw9ppBfyr2A-7HBX-JfTqYdGUa_A--Vzc7GDfjf3KHaiJhDKOXMqHde_aCljQXrPQ8J7e_7QekpvVbzUNRQXtWWXZKWYXf1kYJg95rkVpZMijB5IKPOe_Hk9REOhQX7P2g), an open-source communication framework and [Janus<span>⁠</span>](https://l.facebook.com/l.php?u=https%3A%2F%2Fjanus.conf.meetecho.com%2F&h=AT4Se4Z9JKJ_RQKHLUeLTw9ppBfyr2A-7HBX-JfTqYdGUa_A--Vzc7GDfjf3KHaiJhDKOXMqHde_aCljQXrPQ8J7e_7QekpvVbzUNRQXtWWXZKWYXf1kYJg95rkVpZMijB5IKPOe_Hk9REOhQX7P2g), a general purpose WebRTC server. You’ll learn how to configure your FreeSWITCH server, connect SIP phones, and handle both incoming and outgoing WhatsApp calls.</div><div>![Architecture diagram showing FreeSWITCH with Janus integration](https://support2.chatarchitect.com/uploads/images/gallery/2026-04/embedded-image-qxjmgmj5.png)</div><div id="bkmrk-user-initiated-calls-6"><div id="bkmrk-user-initiated-calls-7"><div>##### User-initiated calls

</div></div></div>
<span>The WhatsApp user dials the business number.</span><span>The call is received by Webhook server which forwards it to FreeSWITCH server via Janus SIP plugin.</span><span>The call is received by FreeSWITCH and routed through an IVR, prompting the user to enter an extension, registered to the same FreeSWITCH server.</span><span>The call is then connected to the specified extension.</span><div id="bkmrk-business-initiated-c-6"><div id="bkmrk-business-initiated-c-7"><div>##### Business-initiated calls

</div></div></div>
<span>The business agent/user registers with FreeSWITCH using SIP credentials (see “[Configuring a VoIP Phone](/books/meta-whatsapp/page/integration-examples-developer-documentation)” section).</span><span>The business user dials the b2c-sip (business to consumer) extension, which is handled by an IVR. The IVR prompts for the WhatsApp number to call.</span><span>FreeSWITCH bridges the call to extension registered to Janus SIP plugin which translates it to an API request to Meta</span><span>The call is then connected to the WhatsApp user.</span><div>The Janus server sits between WA and FreeSWITCH and converts media from WA (WebRTC complaint with DTLS key exchange) to FreeSWITCH negotiated media (SDES key exchange).</div><div>FreeSWITCH - Sip UA will be using SDES for media encryption key exchange and opus or G711 for audio codec</div><div id="bkmrk-prerequisites-6"><div id="bkmrk-prerequisites-7"><div>#### Prerequisites

</div></div></div>
<span>FreeSWITCH Deployment: FreeSWITCH is deployed (for example, on a public cloud instance)</span><span>Janus Deployment: Can be deployed on the same machine as FreeSWITCH</span><span>Operating System: Any OS compatible with FreeSWITCH. For example, CentOS 9</span><span>Domain: FreeSWITCH server and Webhook server are reachable via a public domain with valid certificate</span><span>WhatsApp Business API: A WhatsApp business phone number is registered and [calling is enabled](https://support2.chatarchitect.com/books/meta-whatsapp/page/configure-call-settings-%7C-developer-documentation).</span><span>Webhooks: Configure Webhook callback URL pointing to domain name of the Webhook server</span><div id="bkmrk-integration-with-clo"><div id="bkmrk-integration-with-clo-1"><div>#### Integration with Cloud API signaling

</div></div></div><div>You will need to implement an integration module which sits between WA and Janus and translates Cloud API Signalling messages to Janus SIP plugin messages and vice versa.</div><div>You will need</div>
<span>A webhook server to receive calls webhook events from Meta</span><span>A Graph API module to send call messages to Meta</span><span>An implementation of [Janus SIP plugin<span>⁠</span>](https://l.facebook.com/l.php?u=https%3A%2F%2Fjanus.conf.meetecho.com%2Fdocs%2Fsip&h=AT4Se4Z9JKJ_RQKHLUeLTw9ppBfyr2A-7HBX-JfTqYdGUa_A--Vzc7GDfjf3KHaiJhDKOXMqHde_aCljQXrPQ8J7e_7QekpvVbzUNRQXtWWXZKWYXf1kYJg95rkVpZMijB5IKPOe_Hk9REOhQX7P2g) to connect to Janus. The Janus plugin implementation will connect to FreeSWITCH using extension 1000 which is reserved for bridging</span><div>Business initiated calls</div>
<span>The module will receive a SIP INVITE via Janus SIP plugin on extension 1000. The SIP INVITE is converted to a [Graph API request](https://support2.chatarchitect.com/books/meta-whatsapp/page/business-initiated-calls-%7C-developer-documentation#initiate-call). The SDP received in the SIP INVITE is sent verbatim as the SDP offer to WA via the Graph API call</span><span>When the call is accepted by the WA user, an accepted webhook is received. On receiving the webhook, the Janus SIP Plugin accepts the SIP INVITE passing the answer SDP in the [connect webhook](https://support2.chatarchitect.com/books/meta-whatsapp/page/business-initiated-calls-%7C-developer-documentation#call-connect-webhook)</span><div>User Initiated calls</div>
<span>The webhook server receives an incoming call via a webhook message containing the offer SDP. On receiving the call invite, the Janus SIP plugin sends an invite to FreeSWITCH via extension 1000. The destination extension is **c2b-sip.**</span><span>When the Janus SIP plugin receives the SIP 200 OK, a Graph API accept call request is sent to Meta to accept the incoming call by passing the SDP received as part of SIP answer</span><div id="bkmrk-building-and-install-6"><div id="bkmrk-building-and-install-7"><div>#### Building and installing Janus

</div></div></div><div>Refer to [https://github.com/meetecho/janus-gateway<span>⁠</span>](https://l.facebook.com/l.php?u=https%3A%2F%2Fgithub.com%2Fmeetecho%2Fjanus-gateway&h=AT4Se4Z9JKJ_RQKHLUeLTw9ppBfyr2A-7HBX-JfTqYdGUa_A--Vzc7GDfjf3KHaiJhDKOXMqHde_aCljQXrPQ8J7e_7QekpvVbzUNRQXtWWXZKWYXf1kYJg95rkVpZMijB5IKPOe_Hk9REOhQX7P2g)This guide was tested using version 1.2.3</div><div id="bkmrk-janus-configuration"><div id="bkmrk-janus-configuration-1"><div>#### Janus configuration

</div></div></div><div>**janus.jcfg**</div><div>Modify janus.jcfg which can be found at /usr/share/janus/etc/janus/janus.jcfg Set nat_1_1_mapping to the public IP of the Janus Server</div><div>To start Janus</div><div>```
<span>/usr/</span><span>share</span><span>/</span><span>janus</span><span>/</span><span>bin</span><span>/</span><span>janus  </span><span>--</span><span>debug</span><span>-</span><span>level</span><span>=</span><span>6</span><span>--</span><span>libnice</span><span>-</span><span>debug</span><span>=</span><span>on </span><span>-</span><span>S stun</span><span>.</span><span>l</span><span>.</span><span>google</span><span>.</span><span>com</span><span>:</span><span>19302</span><span>--</span><span>log</span><span>-</span><span>file</span><span>=</span><span>/var/</span><span>log</span><span>/</span><span>janus</span><span>.</span><span>log </span><span>--</span><span>config</span><span>=</span><span>/usr/</span><span>share</span><span>/</span><span>janus</span><span>/</span><span>etc</span><span>/</span><span>janus</span><span>/</span><span>janus</span><span>.</span><span>jcfg</span>
```

</div><div id="bkmrk-building-and-install-9"><div id="bkmrk-building-and-install-10"><div>#### Building and installing FreeSWITCH

</div></div></div><div>Refer to [https://developer.signalwire.com/freeswitch/FreeSWITCH-Explained/Installation/<span>⁠</span>](https://l.facebook.com/l.php?u=https%3A%2F%2Fdeveloper.signalwire.com%2Ffreeswitch%2FFreeSWITCH-Explained%2FInstallation%2F&h=AT4Se4Z9JKJ_RQKHLUeLTw9ppBfyr2A-7HBX-JfTqYdGUa_A--Vzc7GDfjf3KHaiJhDKOXMqHde_aCljQXrPQ8J7e_7QekpvVbzUNRQXtWWXZKWYXf1kYJg95rkVpZMijB5IKPOe_Hk9REOhQX7P2g)</div><div>This guide was tested using FreeSWITCH version 1.10.12. FreeSWITCH uses sofia (an open-source SIP user agent library). Sofia v1.13.17 was used for this guide</div><div>**FreeSWITCH Configuration**These configuration files are placed under /usr/share/freeswitch/etc/freeswitch</div><div>**wa-biz-api-dialplan.xml**</div><div>Place the dial plan under /usr/share/freeswitch/etc/freeswitch/dialplan/default/wa-biz-api-dialplan.xml</div><div>```
<span><include></span><span><extension</span><span>name</span><span>=</span><span>"c2b_calls_ivr"</span><span>></span><span><condition</span><span>field</span><span>=</span><span>"destination_number"</span><span>expression</span><span>=</span><span>"^c2b-sip$"</span><span>></span><span><action</span><span>application</span><span>=</span><span>"set"</span><span>data</span><span>=</span><span>"rtp_secure_media=true"</span><span>/></span><span><action</span><span>application</span><span>=</span><span>"answer"</span><span>/></span><span><!--Add silence stream for  1 sec so that the media path is established between whatsapp and freeswitch to avoid audio clipping. TODO: Investigate if silence can be removed--></span><span><action</span><span>application</span><span>=</span><span>"playback"</span><span>data</span><span>=</span><span>"silence_stream://1000"</span><span>/></span><span><action</span><span>application</span><span>=</span><span>"play_and_get_digits"</span><span>data</span><span>=</span><span>"2 5 3 7000 # $${base_dir}/sounds/incoming_welcome.wav  $${base_dir}/sounds/incoming_invalid.wav extension \d+"</span><span>/></span><span><!--While the call is being bridged, play a ringtone for the caller--></span><span><action</span><span>application</span><span>=</span><span>"set"</span><span>data</span><span>=</span><span>"ringback=%(2000, 4000, 440.0, 480.0)"</span><span>/></span><span><!--WA calls bridged via Janus through extension 1000 only support OPUS. However, the callee might be restricted to other codecs for example G722--></span><span><!--Therefore , don't restrict to OPUS for C2B calls and offer more codecs to the caller. Transcoding between OPUS and the negotiated codec by the caller--></span><span><!--will happen in freeswitch--></span><span><action</span><span>application</span><span>=</span><span>"export"</span><span>data</span><span>=</span><span>"nolocal:absolute_codec_string=PCMA,PCMU,OPUS@48000h@20i,G722"</span><span>/></span><span><action</span><span>application</span><span>=</span><span>"bridge"</span><span>data</span><span>=</span><span>"user/${extension}"</span><span>/></span><span><action</span><span>application</span><span>=</span><span>"hangup"</span><span>/></span><span></condition></span><span></extension></span><span><extension</span><span>name</span><span>=</span><span>"b2c_calls_ivr"</span><span>></span><span><condition</span><span>field</span><span>=</span><span>"destination_number"</span><span>expression</span><span>=</span><span>"^b2c-sip$"</span><span>></span><span><action</span><span>application</span><span>=</span><span>"set"</span><span>data</span><span>=</span><span>"rtp_secure_media=true"</span><span>/></span><span><action</span><span>application</span><span>=</span><span>"answer"</span><span>/></span><span><action</span><span>application</span><span>=</span><span>"playback"</span><span>data</span><span>=</span><span>"silence_stream://1000"</span><span>/></span><span><action</span><span>application</span><span>=</span><span>"set"</span><span>data</span><span>=</span><span>"caller_id_check=${caller_id_number}"</span><span>/></span><span><action</span><span>application</span><span>=</span><span>"log"</span><span>data</span><span>=</span><span>"INFO [caller id ] is ${caller_id_check}"</span><span>/></span><span><action</span><span>application</span><span>=</span><span>"play_and_get_digits"</span><span>data</span><span>=</span><span>"2 12 3 20000 # $${base_dir}/sounds/outgoing_welcome.wav $${base_dir}/sounds/outgoing_invalid.wav whatsapp_number \d+"</span><span>/></span><span><action</span><span>application</span><span>=</span><span>"log"</span><span>data</span><span>=</span><span>"INFO [whatsapp_number] is ${whatsapp_number}"</span><span>/></span><span><!--Add the whatsapp number entered by the user as a custom SIP header, Janus will use this WA user number in API request to Meta--></span><span><action</span><span>application</span><span>=</span><span>"export"</span><span>data</span><span>=</span><span>"sip_h_X-WhatsApp-Number=${whatsapp_number"</span><span>/></span><span><!--While the call is being bridged, play a ringtone for the caller--></span><span><action</span><span>application</span><span>=</span><span>"set"</span><span>data</span><span>=</span><span>"ringback=%(2000, 4000, 440.0, 480.0)"</span><span>/></span><span><!--WA calls bridged via Janus through extension 1000 only support OPUS. However, the caller might be restricted to other codecs for example G722--></span><span><!--Therefore , don't restrict to OPUS for B2C calls and let caller select other codecs--></span><span><!--However, force transcoding to OPUS by only offering OPUS to Janus--></span><span><action</span><span>application</span><span>=</span><span>"export"</span><span>data</span><span>=</span><span>"nolocal:absolute_codec_string=OPUS@48000h@20i,PCMU,PCMA"</span><span>/></span><span><!--Bridge the call to extension 1000 to which capi-calling is registered via Janus to route calls to WhatsApp--></span><span><action</span><span>application</span><span>=</span><span>"bridge"</span><span>data</span><span>=</span><span>"user/1000"</span><span>/></span><span><action</span><span>application</span><span>=</span><span>"hangup"</span><span>/></span><span></condition></span><span></extension></span><span></include></span>
```

</div><div>Audio files should be placed under /usr/share/freeswitch/sounds (not provided)</div>
<span>incoming\_welcome.wav</span><span>Incoming\_invalid.wav</span><span>outgoing\_welcome.wav</span><span>outgoing\_invalid.wav</span><div>**internal.xml**</div><div>Modify /usr/share/freeswitch/etc/freeswitch/sip_profiles/internal.xml Look for:</div><div>```
<span><param</span><span>name</span><span>=</span><span>"sip-trace"</span><span>value</span><span>=</span><span>"no"</span><span>/></span>
```

</div><div>Replace it with</div><div>```
<span><param</span><span>name</span><span>=</span><span>"sip-trace"</span><span>value</span><span>=</span><span>"yes"</span><span>/></span>
```

</div><div id="bkmrk-configuring-a-voip-p-3"><div id="bkmrk-configuring-a-voip-p-4"><div>#### Configuring a VoIP phone

</div></div></div><div>Refer to the [earlier section](/books/meta-whatsapp/page/integration-examples-developer-documentation)</div><div id="bkmrk-final-checklist-6"><div id="bkmrk-final-checklist-7"><div>#### Final checklist

</div></div></div>
<span>Double-check all configuration files for correct numbers, passwords, and domain names.</span><span>Make sure your firewall allows SIP (5061/TLS) and RTP (10000-20000) ports.</span><span>For more details on SIP password setup, see the [WhatsApp Cloud API documentation](/books/meta-whatsapp/page/sip-configuration-guide-whatsapp-business-calling-developer-documentation).</span><div id="bkmrk-troubleshooting-6"><div id="bkmrk-troubleshooting-7"><div>#### Troubleshooting

</div></div></div><div id="bkmrk-cannot-register-sip--6"><div id="bkmrk-cannot-register-sip--7"><div>##### Cannot register SIP UA

</div></div></div><div>Confirm that the SIP URL is correct and the domain is pointing to the FreeSWITCH server. Run host {domain-name} to verify that the IP address points to the FreeSWITCH server.</div><div id="bkmrk-trace-sip-messages-3"><div id="bkmrk-trace-sip-messages-4"><div>##### Trace SIP messages

</div></div></div><div>Start CLI (/usr/share/freeswitch/bin/fs_cli) to view SIP messages</div><div id="bkmrk-asterisk-using-graph"><div id="bkmrk-asterisk-using-graph-1"><div>### Asterisk using Graph API with RtpEngine

</div></div></div><div id="bkmrk-overview-9"><div id="bkmrk-overview-10"><div>#### Overview

</div></div></div><div>This guide explains how to set up [WhatsApp Business Calling API](/books/meta-whatsapp/page/cloud-api-calling-developer-documentation) using [WhatsApp Cloud API signaling](/books/meta-whatsapp/page/business-initiated-calls-developer-documentation) with [Asterisk<span>⁠</span>](https://l.facebook.com/l.php?u=https%3A%2F%2Fwww.asterisk.org%2F&h=AT4Se4Z9JKJ_RQKHLUeLTw9ppBfyr2A-7HBX-JfTqYdGUa_A--Vzc7GDfjf3KHaiJhDKOXMqHde_aCljQXrPQ8J7e_7QekpvVbzUNRQXtWWXZKWYXf1kYJg95rkVpZMijB5IKPOe_Hk9REOhQX7P2g), an open-source PBX (Private Branch Exchange) and [RtpEngine<span>⁠</span>](https://l.facebook.com/l.php?u=https%3A%2F%2Fgithub.com%2Fsipwise%2Frtpengine&h=AT4Se4Z9JKJ_RQKHLUeLTw9ppBfyr2A-7HBX-JfTqYdGUa_A--Vzc7GDfjf3KHaiJhDKOXMqHde_aCljQXrPQ8J7e_7QekpvVbzUNRQXtWWXZKWYXf1kYJg95rkVpZMijB5IKPOe_Hk9REOhQX7P2g), an open-source proxy used for relaying, manipulating, and controlling RTP streams. You’ll learn how to configure your Asterisk server, connect SIP phones, and handle both incoming and outgoing WhatsApp calls.</div><div id="bkmrk-user-initiated-calls-9"><div id="bkmrk-user-initiated-calls-10"><div>##### User-initiated calls

</div></div></div>
<span>The WhatsApp user dials the business number.</span><span>The call is received by the Webhook server which after bridging media using RtpEngine, forwards it to Asterisk using SIP.</span><span>The call is received by Asterisk and routed through an IVR, prompting the user to enter an extension, registered to the same Asterisk server.</span><span>The call is then connected to the specified extension.</span><div id="bkmrk-business-initiated-c-9"><div id="bkmrk-business-initiated-c-10"><div>##### Business-initiated calls

</div></div></div>
<span>The business agent/user registers with Asterisk using SIP credentials (see “[Configuring a VoIP Phone](/books/meta-whatsapp/page/integration-examples-developer-documentation)” section).</span><span>The business user dials the b2c-sip (business to consumer) extension, which is handled by an IVR. The IVR prompts for the WhatsApp number to call.</span><span>Asterisk bridges the call to extension registered by the integration module (see “Integration with Cloud API Signalling”)</span><span>On receiving the call, the integration module bridges the media using RtpEngine and then translates it to an API request to Meta</span><span>The call is then connected to the WhatsApp user.</span><div>RtpEngine acts as a media proxy and sits between the media stream of WA (WebRTC complaint with DTLS key exchange) and Asterisk (SDES key exchange)</div><div id="bkmrk-prerequisites-9"><div id="bkmrk-prerequisites-10"><div>#### Prerequisites

</div></div></div>
<span>Asterisk Deployment: Asterisk is deployed (for example, on a public cloud instance)</span><span>RtpEngine Deployment: Can be deployed on the same machine as Asterisk</span><span>Operating System: Any OS compatible with Asterisk and RtpEngine. For example, CentOS 9</span><span>Domain: Asterisk server and Webhook server are reachable via a public domain with valid certificate</span><span>WhatsApp Business API: A WhatsApp business phone number is registered and [calling is enabled](https://support2.chatarchitect.com/books/meta-whatsapp/page/configure-call-settings-%7C-developer-documentation).</span><span>Webhooks: Configure Webhook callback URL pointing to domain name of the Webhook server</span><div id="bkmrk-integration-with-clo-3"><div id="bkmrk-integration-with-clo-4"><div>#### Integration with Cloud API signaling

</div></div></div><div>You will need to implement an integration module that acts as a bridge between WhatsApp and Asterisk. This module will:</div>
<span>Translate Cloud API Signaling messages from WhatsApp to SIP for Asterisk, and vice versa</span><span>Use SIP signaling for communication between the SIP UA inside the module and Asterisk</span><span>Bridge the media between WhatsApp and Asterisk via RtpEngine</span><div>You will need following components, which are part of the integration module for the purpose of this setup</div>
<span>Webhook Server: Receives call webhook events from Meta (WhatsApp Cloud API)</span><span>Graph API client: Sends call-related requests to Meta using the Graph API</span><span>SIP User Agent (UA) such as PJSIP: Connects to Asterisk using extension 1000, which is reserved for bridging calls between WhatsApp and Asterisk.</span><span>RtpEngineClient: To control RtpEngine via [ng control protocol<span>⁠</span>](https://l.facebook.com/l.php?u=https%3A%2F%2Frtpengine.readthedocs.io%2Fen%2Flatest%2Fng_control_protocol.html&h=AT4Se4Z9JKJ_RQKHLUeLTw9ppBfyr2A-7HBX-JfTqYdGUa_A--Vzc7GDfjf3KHaiJhDKOXMqHde_aCljQXrPQ8J7e_7QekpvVbzUNRQXtWWXZKWYXf1kYJg95rkVpZMijB5IKPOe_Hk9REOhQX7P2g) for bridging media</span><div>![Architecture diagram showing Asterisk integration with RtpEngine for WhatsApp Business Calling](https://support2.chatarchitect.com/uploads/images/gallery/2026-04/embedded-image-wjmo3m1w.jpeg)</div><div>Business initiated calls</div>
<span>Business agent registered to the same Asterisk server dials b2c-sip extension to initiate a call to WhatsApp user</span><span>The extension prompts the business agent to enter WA user’s phone number</span><span>Asterisk sends a SIP INVITE request to extension 1000 with a custom header containing the dialed WA user phone number</span><span>The SIP UA inside the module would’ve registered at extension 1000 and hence receives the SIP INVITE from Asterisk</span><span>The SDP included in the SIP INVITE is sent to RtpEngine which returns a new SDP</span><span>The new SDP is included in the [Graph API request](/books/meta-whatsapp/page/business-initiated-calls-developer-documentation) to initiate a new call</span><span>When the WhatsApp user accepts the call, an “accepted” webhook is received</span><span>Upon receiving this webhook, the answer SDP received in the webhook is sent to RtpEngine which returns a new SDP</span><span>The SIP UA accepts the original SIP INVITE (step 3), passing along the new SDP received from RtpEngine</span><span>The call is now bridged between WA user, RtpEngine, and Asterisk</span><div>User Initiated calls</div>
<span>The webhook server inside the module receives an [incoming call webhook](/books/meta-whatsapp/page/user-initiated-calls-developer-documentation) from Meta, which includes the offer SDP</span><span>Upon receiving this call invite, the SDP included in the offer is sent to RtpEngine which returns a new SDP</span><span>The SIP UA inside the module sends a SIP INVITE to Asterisk using extension 1000 passing the new SDP from RtpEngine in the SIP INVITE. The destination extension is c2b-sip.</span><span>The extension prompts WA user to dial the extension of the business agent to connect to</span><span>Asterisk dials the specified extension and waits for an answer</span><span>After the agent answers the call, Asterisk sends SIP 200 OK to the SIP UA extension 1000 inside the module. The SDP in SIP 200 OK is sent to RtpEngine which returns a new SDP</span><span>A Graph API request is sent to Meta to [accept the incoming call](/books/meta-whatsapp/page/user-initiated-calls-developer-documentation), with the new SDP received from RtpEngine</span><div id="bkmrk-building-and-install-12"><div id="bkmrk-building-and-install-13"><div>#### Building and installing Asterisk

</div></div></div><div>Refer to https://docs.asterisk.org/Getting-Started/Installing-Asterisk/Installing-Asterisk-From-Source/Building-and-Installing-Asterisk/</div><div>This guide was tested using Asterisk version 22.5.2</div><div id="bkmrk-building-and-install-15"><div id="bkmrk-building-and-install-16"><div>#### Building and installing RtpEngine

</div></div></div><div>Refer to [https://github.com/sipwise/rtpengine<span>⁠</span>](https://l.facebook.com/l.php?u=https%3A%2F%2Fgithub.com%2Fsipwise%2Frtpengine&h=AT4Se4Z9JKJ_RQKHLUeLTw9ppBfyr2A-7HBX-JfTqYdGUa_A--Vzc7GDfjf3KHaiJhDKOXMqHde_aCljQXrPQ8J7e_7QekpvVbzUNRQXtWWXZKWYXf1kYJg95rkVpZMijB5IKPOe_Hk9REOhQX7P2g) to build and install RtpEngine This guide was tested using RtpEngine version 13.3.1.4</div><div>Refer to https://rtpengine.readthedocs.io/en/latest/ng_control_protocol.html for details on ng control protocol</div><div>To start RtpEngine run</div><div>```
<span>/usr/</span><span>bin</span><span>/</span><span>rtpengine </span><span>--</span><span>listen</span><span>-</span><span>ng</span><span>={</span><span>local</span><span>-</span><span>ip</span><span>}:</span><span>22222</span><span>--</span><span>interface</span><span>={</span><span>local</span><span>-</span><span>ip</span><span>}</span><span>\!</span><span>{</span><span>public</span><span>-</span><span>ip</span><span>}</span><span>-</span><span>f </span><span>-</span><span>E</span>
```

</div><div>Replace</div>
<span>{local-ip} with the local IP of the RtpEngine server</span><span>{public-ip} with the public IP of the RtpEngine server</span><div>**Asterisk Configuration**These configuration files are placed under /etc/asterisk/</div><div>**extensions.conf**</div><div>Replace the following placeholders with actual values</div>
<span>incoming\_welcome: incoming\_welcome.wav (not provided) place this file under /var/lib/asterisk/sounds</span><span>outgoing\_welcome: outgoing\_welcome.wav (not provided) place this file under /var/lib/asterisk/sounds</span><div>```
<span>[</span><span>handler</span><span>]</span><span>;</span><span>Set</span><span> headers on callee channel
exten </span><span>=></span><span> addheader</span><span>,</span><span>1</span><span>,</span><span>Set</span><span>(</span><span>PJSIP_HEADER</span><span>(</span><span>add</span><span>,</span><span>X</span><span>-</span><span>WhatsApp</span><span>-</span><span>Number</span><span>)=</span><span>$</span><span>{</span><span>DIGITS</span><span>})</span><span>
same </span><span>=></span><span> n</span><span>,</span><span>Return</span><span>()</span><span>[</span><span>default</span><span>]</span><span>
exten </span><span>=></span><span> _10XX</span><span>,</span><span>1</span><span>,</span><span>NoOp</span><span>()</span><span>
same </span><span>=></span><span> n</span><span>,</span><span>Dial</span><span>(</span><span>PJSIP</span><span>/</span><span>$</span><span>{</span><span>EXTEN</span><span>})</span><span>
same </span><span>=></span><span> n</span><span>,</span><span>Hangup</span><span>()</span><span>

exten </span><span>=></span><span> b2c</span><span>-</span><span>sip</span><span>,</span><span>1</span><span>,</span><span>NoOp</span><span>()</span><span>
same </span><span>=></span><span> n</span><span>,</span><span>Read</span><span>(</span><span>Digits</span><span>,</span><span>outgoing_welcome</span><span>,</span><span>0</span><span>,,</span><span>5</span><span>,</span><span>500</span><span>)</span><span>
same </span><span>=></span><span> n</span><span>,</span><span>Set</span><span>(</span><span>GLOBAL</span><span>(</span><span>DIGITS</span><span>)=</span><span>$</span><span>{</span><span>Digits</span><span>})</span><span>;</span><span>Before</span><span> starting a business initiated call</span><span>,</span><span> add customer WA header to store the WA user number captured </span><span>from</span><span> agent entered digits </span><span>(</span><span>DTMF</span><span>)</span><span>
same </span><span>=></span><span> n</span><span>,</span><span>Dial</span><span>(</span><span>PJSIP</span><span>/</span><span>1000</span><span>,,</span><span>b</span><span>(</span><span>handler</span><span>^</span><span>addheader</span><span>^</span><span>1</span><span>))</span><span>
same </span><span>=></span><span> n</span><span>,</span><span>Hangup</span><span>()</span><span>

exten </span><span>=></span><span> c2b</span><span>-</span><span>sip</span><span>,</span><span>1</span><span>,</span><span>NoOp</span><span>()</span><span>
same </span><span>=></span><span> n</span><span>,</span><span>Read</span><span>(</span><span>Digits</span><span>,</span><span>incoming_welcome</span><span>,</span><span>0</span><span>,,</span><span>5</span><span>,</span><span>500</span><span>)</span><span>
same </span><span>=></span><span> n</span><span>,</span><span>Dial</span><span>(</span><span>PJSIP</span><span>/</span><span>$</span><span>{</span><span>Digits</span><span>})</span><span>
same </span><span>=></span><span> n</span><span>,</span><span>Hangup</span><span>()</span>
```

</div><div>**pjsip.conf**</div><div>Replace the following placeholders with actual values</div>
<span>{external-media-address}: Public IP of the Asterisk server for media</span><span>{external-signaling-address}: Public IP of the Asterisk server for signaling</span><span>{local-net}: local network of the Asterisk server</span><span>{sip-ua-password}: Chosen SIP User Agent password</span><div>Note:</div><div>Extension 1000 is used to bridge WA calls with Asterisk see section **Integration with Cloud API Signaling**</div><div>```
<span>[</span><span>global</span><span>]</span><span>
type</span><span>=</span><span>global</span><span>
debug</span><span>=</span><span>yes </span><span>;</span><span>Enable</span><span>/</span><span>Disable</span><span> SIP debug logging</span><span>.</span><span>Valid</span><span> options include yes</span><span>|</span><span>no</span><span>[</span><span>transport</span><span>-</span><span>tcp</span><span>]</span><span>
type</span><span>=</span><span>transport
protocol</span><span>=</span><span>tcp
bind</span><span>=</span><span>0.0</span><span>.</span><span>0.0</span><span>;</span><span>External</span><span> IP address to </span><span>use</span><span>in</span><span> RTP handling
external_media_address</span><span>={</span><span>external</span><span>-</span><span>media</span><span>-</span><span>address</span><span>}</span><span>;</span><span>External</span><span> address </span><span>for</span><span> SIP signalling
external_signaling_address</span><span>={</span><span>external</span><span>-</span><span>signaling</span><span>-</span><span>address</span><span>}</span><span>;</span><span>Network</span><span> to consider </span><span>local</span><span> used </span><span>for</span><span> NAT purposes
local_net</span><span>={</span><span>local</span><span>-</span><span>net</span><span>}</span><span>[</span><span>endpointtemplate</span><span>](!)</span><span>
type</span><span>=</span><span>endpoint
context</span><span>=</span><span>default</span><span>
disallow</span><span>=</span><span>all
allow</span><span>=</span><span>OPUS</span><span>,</span><span>g722</span><span>,</span><span>g729</span><span>,</span><span>ulaw
</span><span>;</span><span>No</span><span> audio </span><span>if</span><span> direct_media </span><span>is</span><span>set</span><span> to yes
direct_media</span><span>=</span><span>no</span><span>
rtp_symmetric</span><span>=</span><span>yes
use_avpf</span><span>=</span><span>yes
media_encryption</span><span>=</span><span>sdes
media_use_received_transport</span><span>=</span><span>yes
rtcp_mux</span><span>=</span><span>yes

</span><span>[</span><span>authtemplate</span><span>](!)</span><span>
type</span><span>=</span><span>auth
auth_type</span><span>=</span><span>userpass
password</span><span>={</span><span>sip</span><span>-</span><span>ua</span><span>-</span><span>password</span><span>}</span><span>[</span><span>aortemplate</span><span>](!)</span><span>
type</span><span>=</span><span>aor
max_contacts</span><span>=</span><span>1</span><span>
remove_existing</span><span>=</span><span>yes

</span><span>[</span><span>1000</span><span>](</span><span>endpointtemplate</span><span>)</span><span>
disallow</span><span>=</span><span>all
</span><span>;</span><span>extension </span><span>1000</span><span>is</span><span> used </span><span>by</span><span>RtpEngine</span><span> to bridge whatsapp calls
</span><span>;</span><span>WhatsApp</span><span> only support OPUS
allow</span><span>=</span><span>OPUS
auth</span><span>=</span><span>1000</span><span>_auth
aors</span><span>=</span><span>1000</span><span>[</span><span>1000</span><span>_auth</span><span>](</span><span>authtemplate</span><span>)</span><span>
username</span><span>=</span><span>1000</span><span>[</span><span>1000</span><span>](</span><span>aortemplate</span><span>)</span><span>[</span><span>1001</span><span>](</span><span>endpointtemplate</span><span>)</span><span>
auth</span><span>=</span><span>1001</span><span>_auth
aors</span><span>=</span><span>1001</span><span>[</span><span>1001</span><span>_auth</span><span>](</span><span>authtemplate</span><span>)</span><span>
username</span><span>=</span><span>1001</span><span>[</span><span>1001</span><span>](</span><span>aortemplate</span><span>)</span><span>[</span><span>1002</span><span>](</span><span>endpointtemplate</span><span>)</span><span>
auth</span><span>=</span><span>1002</span><span>_auth
aors</span><span>=</span><span>1002</span><span>[</span><span>1002</span><span>_auth</span><span>](</span><span>authtemplate</span><span>)</span><span>
username</span><span>=</span><span>1002</span><span>[</span><span>1002</span><span>](</span><span>aortemplate</span><span>)</span><span>[</span><span>1003</span><span>](</span><span>endpointtemplate</span><span>)</span><span>
auth</span><span>=</span><span>1003</span><span>_auth
aors</span><span>=</span><span>1003</span><span>[</span><span>1003</span><span>_auth</span><span>](</span><span>authtemplate</span><span>)</span><span>
username</span><span>=</span><span>1003</span><span>[</span><span>1003</span><span>](</span><span>aortemplate</span><span>)</span><span>[</span><span>1004</span><span>](</span><span>endpointtemplate</span><span>)</span><span>
auth</span><span>=</span><span>1004</span><span>_auth
aors</span><span>=</span><span>1004</span><span>[</span><span>1004</span><span>_auth</span><span>](</span><span>authtemplate</span><span>)</span><span>
username</span><span>=</span><span>1004</span><span>[</span><span>1004</span><span>](</span><span>aortemplate</span><span>)</span><span>[</span><span>1005</span><span>](</span><span>endpointtemplate</span><span>)</span><span>
auth</span><span>=</span><span>1005</span><span>_auth
aors</span><span>=</span><span>1005</span><span>[</span><span>1005</span><span>_auth</span><span>](</span><span>authtemplate</span><span>)</span><span>
username</span><span>=</span><span>1005</span><span>[</span><span>1005</span><span>](</span><span>aortemplate</span><span>)</span>
```

</div><div id="bkmrk-configuring-a-voip-p-6"><div id="bkmrk-configuring-a-voip-p-7"><div>#### Configuring a VoIP phone

</div></div></div><div>Refer to the [earlier section](/books/meta-whatsapp/page/integration-examples-developer-documentation)</div><div id="bkmrk-final-checklist-9"><div id="bkmrk-final-checklist-10"><div>#### Final checklist

</div></div></div>
<span>Double-check all configuration files for correct numbers, passwords, and domain names.</span><span>Make sure your firewall allows SIP (5060/TCP) and RTP (10000-20000) ports.</span><span>For more details on SIP password setup, see the [WhatsApp Cloud API documentation](/books/meta-whatsapp/page/sip-configuration-guide-whatsapp-business-calling-developer-documentation).</span><div id="bkmrk-troubleshooting-9"><div id="bkmrk-troubleshooting-10"><div>#### Troubleshooting

</div></div></div><div id="bkmrk-cannot-register-sip--9"><div id="bkmrk-cannot-register-sip--10"><div>##### Cannot register SIP UA

</div></div></div><div>Confirm that the SIP URL is correct and the domain is pointing to the Asterisk server. Run host {domain-name} to verify that the IP address points to the Asterisk server.</div><div id="bkmrk-asterisk-with-built-"><div id="bkmrk-asterisk-with-built--1"><div>### Asterisk with built-in WebRTC using Graph API

</div></div></div><div>This approach is similar to [Asterisk using Graph API with RtpEngine ](/books/meta-whatsapp/page/integration-examples-developer-documentation) except that it uses the built-in WebRTC support in Asterisk and hence does not require RtpEngine.</div><div>The RtpEngineClient component is hence not required in this approach</div><div>In terms of configuration and setup, only difference is the configuration of extension 1000 which is given below</div><div>```
<span>...</span><span>;</span><span>Rest</span><span> of content omitted </span><span>for</span><span> brevity

</span><span>[</span><span>1000</span><span>](</span><span>endpointtemplate</span><span>)</span><span>
disallow</span><span>=</span><span>all
</span><span>;</span><span>extension </span><span>1000</span><span>is</span><span> used </span><span>by</span><span> SIP UA of the integration </span><span>module</span><span> to bridge </span><span>WhatsApp</span><span> calls
</span><span>;</span><span>WhatsApp</span><span> only support OPUS
allow</span><span>=</span><span>OPUS
auth</span><span>=</span><span>1000</span><span>_auth
aors</span><span>=</span><span>1000</span><span>
dtls_auto_generate_cert</span><span>=</span><span>yes
webrtc</span><span>=</span><span>yes
</span><span>;</span><span>Setting</span><span> webrtc</span><span>=</span><span>yes </span><span>is</span><span> a shortcut </span><span>for</span><span> setting the following options</span><span>:</span><span>;</span><span> use_avpf</span><span>=</span><span>yes
</span><span>;</span><span> media_encryption</span><span>=</span><span>dtls
</span><span>;</span><span> dtls_verify</span><span>=</span><span>fingerprint
</span><span>;</span><span> dtls_setup</span><span>=</span><span>actpass
</span><span>;</span><span> ice_support</span><span>=</span><span>yes
</span><span>;</span><span> media_use_received_transport</span><span>=</span><span>yes
</span><span>;</span><span> rtcp_mux</span><span>=</span><span>yes
</span>
```

</div></div>