What SIP Mode Is
Session Initiation Protocol (SIP) is the standard signaling protocol for VoIP. WhatsApp Business Calling can use SIP for call signaling instead of Graph API endpoints + calls webhooks.
When SIP is enabled on a business phone number:
- Calling-related Graph API endpoints (
/<PHONE_NUMBER_ID>/calls) stop working — return error131055. - Calling webhooks (
callsfield) are not sent. - Messaging Graph API + webhooks continue to work normally — SIP only intercepts the calling signaling path.
Use SIP if you have a SIP-based contact center, IVR, or telephony infrastructure that needs native SIP integration. Otherwise, prefer Graph API + webhooks for simpler operations.
Trade-offs vs Graph API + Webhooks
| Graph API + Webhooks | SIP | |
|---|---|---|
| Setup complexity | Lower — webhook endpoint + WebRTC stack | Higher — SIP server + TLS certificate + digest auth |
| Operational overhead | Lower | Higher (TLS cert lifecycle, SIP server uptime) |
| Native fit for SIP-based call centers | Awkward (need translation layer) | Native |
| Calling webhooks | Yes | No — SIP messages replace them |
| Functional parity | Yes | Yes |
| Recommended for | Most setups | Only when SIP is already core infra |
Prerequisites
- All standard calling prerequisites met.
- Your app has
whatsapp_business_messagingfor the business phone number — verify by sending a test message before configuring SIP. - Your app mode is Live, not Development.
- A standards-compliant third-party SIP server that supports TLS transport and digest authentication.
TLS Certificate Requirements
TLS transport is mandatory for SIP. Two requirements:
- Meta's cert has subject name
wa.meta.vc. Your SIP client should validate it. - Your SIP server's cert must have a subject name covering the SIP domain you configure (e.g.
meta-voip.example.com). Meta validates it on connection.
Meta does not support mutual TLS. When Meta acts as a TLS client, your TLS server must not request a client certificate. If you do, Meta returns a cert with a random dynamic-host subject that won't pass your validation.
Verify your TLS setup before reporting that calls aren't being delivered:
openssl s_client -quiet -verify_hostname meta-voip.example.com -connect meta-voip.example.com:5061
A valid cert returns verify return:1 for each depth and connects cleanly. Hostname mismatch produces verify error:num=62:hostname mismatch. Connection refused / timeout means the host isn't listening for TLS on that port.
Configure SIP
POST /<PHONE_NUMBER_ID>/settings
{
"calling": {
"sip": {
"status": "ENABLED",
"servers": [
{
"hostname": "sip.example.com",
"port": 5061,
"request_uri_user_params": {
"tgrp": "wacall",
"trunk-context": "byoc.example.com"
}
}
]
}
}
}
| Field | Notes |
|---|---|
status | ENABLED makes SIP exclusive (no Graph API/webhooks for calling). DISABLED is the default. Disabling does NOT clear servers — they persist for re-enabling. |
servers[] | One server per phone number. Multiple entries in the GET response means different apps configured different servers (we extract the app from the access token). |
hostname | TLS-only. Your SIP server hostname. |
port | TLS port (default 5061). |
request_uri_user_params | Optional key/value pairs added to the user portion of the request URI. Useful for trunk groups (tgrp, trunk-context per RFC 4904). Max key/value 128 chars each. |
To delete a SIP server, pass an empty servers array. If servers remain afterward, they belong to a different app — disable SIP entirely or use the corresponding app's token to clear them.
At least one SIP server (any app) must exist when sip.status: ENABLED.
Get and Include SIP Password
Meta generates a unique SIP password per (phone number + app) combination. Retrieve it by adding ?include_sip_credentials=true to the GET settings call:
GET /<PHONE_NUMBER_ID>/settings?include_sip_credentials=true
{
"calling": {
"sip": {
"status": "ENABLED",
"servers": [
{
"app_id": 123456789012345,
"hostname": "sip.example.com",
"sip_user_password": "<SIP_USER_PASSWORD>"
}
]
}
}
}
Configure this password on your SIP server so it can respond to digest authentication challenges from Meta. Treat the password as a secret — Dualhook customers should pull it via API and store it themselves; we don't proxy or cache it.
Reset SIP Password
There's no dedicated "rotate password" endpoint. To force regeneration:
- Disable SIP and clear servers (
status: "DISABLED",servers: []). - Re-enable SIP with your server (
status: "ENABLED",servers: [{ "hostname": "..." }]). - Fetch with
include_sip_credentials=trueto read the new password.
Make sure you've recorded any old password before doing this — the rotation is irreversible.
Business-Initiated SIP Flow
- Send an initial SIP INVITE to
wa.meta.vc. Request URI for calling user+11234567890:sip:+11234567890@wa.meta.vc;transport=tls. - Meta returns
SIP/2.0 407 Proxy Authentication Requiredwith aWWW-Authenticateheader. - Send a second INVITE with a proper
Authorizationheader per RFC 3261 digest auth — username = your business phone number (normalized), password = Meta-generated SIP password. - Meta routes the call to the WhatsApp user.
Constraints on your INVITE:
Fromheader username: fully normalized business phone number.Fromheader domain: must match the SIP server hostname you configured.- SDP offer: WebRTC-compatible (ICE + DTLS-SRTP + OPUS) — or SDES if configured (see below).
If you receive 403 SIP server foo.com from INVITE does not match any SIP server configured for phone number id [ID], your From header domain doesn't match the SIP server hostname stored in your config. Sub-domains of the configured domain are valid (e.g. bar.foo.com matches foo.com).
User-Initiated SIP Flow
- WhatsApp user calls your business number.
- Meta sends a SIP INVITE to your configured SIP server.
- Recommended: challenge with
407 Proxy Authentication Required(digest auth). Meta resends the INVITE with the auth header. - Respond with
200 OKcontaining your SDP answer.
If you don't challenge (no digest auth), Meta sends the INVITE without auth — security best practice is to challenge.
User experience is identical whether you're on SIP or Graph API — the user has no idea which signaling path you use.
If your SIP server doesn't receive the INVITE, the most common causes are TLS certificate validation errors, app permission mismatch, or firewall / port reachability issues.
Custom SIP Headers
Meta adds these custom headers to SIP requests:
| Header | When | Value |
|---|---|---|
x-wa-meta-call-duration | SIP BYE from Meta on established calls | Call duration in seconds |
x-wa-meta-wacid | SIP INVITE (UIC) and BYE (UIC + BIC) | WhatsApp call ID |
x-wa-meta-cta-payload | UIC INVITE when call originated from a voice_call button with payload | Business-specified payload |
x-wa-meta-deeplink-payload | UIC INVITE when call originated from a wa.me/call/<num>?biz_payload=... deep link | Business-specified payload |
SDES vs DTLS for SRTP Key Exchange
SRTP needs a key-exchange mechanism. Two options:
| DTLS (default) | SDES | |
|---|---|---|
| Industry-standard | Yes | Older standard |
| Requires ICE/DTLS handshake | Yes | No |
| Call setup time | Slower (handshake completes after SDP exchange) | Faster (key in SDP, sent over secure SIP) |
| Supports WebRTC stacks | Yes | Yes |
| When to prefer | Default for most setups | When using SIP and you want shorter call setup, or to address audio clipping caused by DTLS retry intervals |
DTLS retries on a 1s, 2s, 4s backoff — common SIP setups see ~3 seconds of dropped media at call start while waiting for the DTLS client hello. SDES sends the key in the SDP itself, so SRTP can flow immediately after SDP exchange. See Calling Troubleshooting → Audio Clipping for the full audio-clipping mitigation menu.
Configure SRTP Key Exchange
POST /<PHONE_NUMBER_ID>/settings
{
"calling": {
"srtp_key_exchange_protocol": "SDES"
}
}
Possible values: DTLS (default) or SDES.
To check current setting:
GET /<PHONE_NUMBER_ID>/settings
If the field has not been explicitly set, it's not returned.
Note: Meta still expects the business side to send the maiden SRTP packet for both UIC and BIC.
Common SIP Errors
| SIP status / error | Meaning | Fix |
|---|---|---|
400 Asset not found | From header phone number is not a registered business number | Check the number and resend |
403 SIP server X from INVITE does not match... | From header domain doesn't match configured SIP server hostname | Update SIP config or From header |
403 No Approved Call Permission Found | No permission from recipient (or recipient not on WhatsApp) | Get permission first (Call Permissions) |
403 The app [APP_ID] configured for SIP server X is not authorized for phone number id [ID] | App used to configure SIP doesn't have whatsapp_business_messaging on the number | Reconfigure with the right app |
403 Business Initiated Connected Call Per Day Limit Hit | 5 connected BICs in 24h reached | Wait or check pricing tier |
404 SIP INVITEs using IP in request URI are not allowed | Don't use IP literal in request URI | Use the correct request URI (see flow examples) |
407 Proxy Authentication Required | Standard digest auth challenge from Meta | Resend with Authorization header |
408 RTP Timeout | No media received for too long | See Audio Clipping & Media Issues |
480 Temporarily Unavailable | User unreachable / didn't answer | Try later; unanswered calls degrade permission |
486 Busy Here | User declined the call | Try later; rejections degrade permission |
487 Request Terminated | You sent SIP CANCEL before Meta responded | Expected — your CANCEL worked |
503 Service Unavailable | Generic internal error | Retry later or contact Meta support |
Full error reference and Graph-API-side errors on Calling Troubleshooting.
SIP FAQ
Why is user-initiated call disconnecting immediately after enabling SIP?
Most likely TLS certificate validation error. Run the openssl s_client check above.
Why am I not getting SIP requests when expected?
Common causes: TLS cert validation error, SIP not actually enabled (verify with GET settings), app that configured SIP lacks whatsapp_business_messaging, network/firewall blocking Meta's IP ranges, or SIP server not listening on the configured port. Verify TCP reachability with nc -zvw2 -G 2 <sip-host> <sip-port>.
Why is my SIP TERMINATE not hanging up the user?
Usually TLS handshake failure when your SIP server tries to establish TLS to Meta's. Capture SIP traffic with pcap or check SIP server logs.
Why does my SIP server keep responding 401 Unauthorized for UIC?
Meta supports digest auth. After your 401, Meta resends the INVITE with Authorization. Confirm your SIP server is configured with username = (normalized) business phone number, password = Meta-generated password. Or disable digest auth on your SIP server (not recommended).
Why is my SIP server responding 488 Not Acceptable Here?
Likely your SIP server doesn't support WebRTC ICE. Switch the business phone number to use SDES instead of DTLS.
Do I need to SIP REGISTER the business phone number to Meta?
No. REGISTER requests fail with 403 Forbidden. Meta's SIP server only owns the meta.vc domain (where WhatsApp consumers live). Your business numbers belong to the SIP domain you configure.
Does Meta support SIP re-INVITEs?
No. Returns 500 Internal Server Error.
SIP vs Graph API — is one functionally better?
No, they have parity. Pick based on your existing infrastructure.
If I use SIP, do I still need webhooks?
Yes — but only for messaging and other non-calling events. SIP only covers call signaling.
Does Meta have an approved list of SIP vendors / SBCs?
No. Any compatible standards-compliant SIP server works.