What This Page Covers
How to enable and configure the WhatsApp Business Calling API on a business phone number — including who can call, when calls are accepted, audio codec choices, and how to listen for settings changes via webhook.
If you want to use SIP signaling instead of Graph API + webhooks, the SIP-specific portions of /<PHONE_NUMBER_ID>/settings live on SIP Configuration.
Configure Call Settings
POST /<PHONE_NUMBER_ID>/settings
Permission: whatsapp_business_management (advanced access for end-business clients).
Full request body shape:
{
"calling": {
"status": "ENABLED",
"call_icon_visibility": "DEFAULT",
"call_icons": {
"restrict_to_user_countries": ["US", "BR"]
},
"call_hours": {
"status": "ENABLED",
"timezone_id": "America/Manaus",
"weekly_operating_hours": [
{ "day_of_week": "MONDAY", "open_time": "0400", "close_time": "1020" },
{ "day_of_week": "TUESDAY", "open_time": "0900", "close_time": "1700" }
],
"holiday_schedule": [
{ "date": "2026-01-01", "start_time": "0000", "end_time": "2359" }
]
},
"callback_permission_status": "ENABLED",
"audio": {
"additional_codecs": ["PCMA", "PCMU"]
}
}
}
All fields are optional. Omitting a field leaves its current value unchanged — except call_hours.holiday_schedule, which is replaced wholesale by what you send (omit it and any prior holidays are deleted).
Success response:
{ "success": true }
calling.status
| Value | Effect |
|---|---|
ENABLED | Calling features active. WhatsApp client renders the call-button icon in chat and business-info screens. |
DISABLED | Calling features off. Call icon hidden across the app. |
Updates propagate near-real-time to users who already have your number in their contacts; for everyone else, propagation is eventual but server-side semantics are honored immediately.
call_icon_visibility
Controls whether the call button is shown to users when calling is ENABLED:
| Value | What it does |
|---|---|
DEFAULT | Call button visible in chat menu bar and business info page. Users can place unsolicited calls. |
DISABLE_ALL | Call button hidden in chat and info page. All external entry points (contact-app dial, etc.) also disabled. But users can still call you via Call Buttons & Deep Links — voice_call interactive messages, template buttons, wa.me/call/<num> links. |
DISABLE_ALL is best treated as a coarse first-level filter; rely on webhooks + per-message routing to enforce per-user policy.
call_icons (Restrict by Country)
Restrict where the call button appears by user country. Empty array means no restriction.
"call_icons": {
"restrict_to_user_countries": ["US", "BR"]
}
Country is determined by the user's registered phone number, not their physical location. A user with a US-registered number traveling abroad still sees the icon if US is in the list.
call_hours
Restrict when user-initiated calls are accepted. Outside the configured weekly hours and holiday schedule, callers see a "chat instead" / "request callback" screen (callback option only shown if callback_permission_status: ENABLED).
"call_hours": {
"status": "ENABLED",
"timezone_id": "America/Manaus",
"weekly_operating_hours": [
{ "day_of_week": "MONDAY", "open_time": "0400", "close_time": "1020" }
],
"holiday_schedule": [
{ "date": "2026-01-01", "start_time": "0000", "end_time": "2359" }
]
}
| Field | Notes |
|---|---|
status | ENABLED enforces the schedule. DISABLED makes the business 24/7. |
timezone_id | IANA timezone name (America/Menominee, Asia/Singapore, etc.). |
weekly_operating_hours[] | Up to 2 entries per day_of_week. Times are 4-digit 24-hour strings (e.g. "0400" = 04:00, "1020" = 10:20). open_time must precede close_time. No overlapping entries. |
holiday_schedule[] | Optional. Up to 20 date overrides. Same time format. Sending the field replaces all existing holidays — to keep prior holidays, include them in every request. |
callback_permission_status
When ENABLED, after a user calls you (whether you pick up or miss it), they're auto-prompted to grant call permission so you can call them back. See Call Permissions for the full mechanics.
audio.additional_codecs
OPUS is always the default and cannot be removed. Optionally enable G.711 (PCMA/PCMU) for interoperability with legacy telephony / PSTN gateways.
"audio": { "additional_codecs": ["PCMA", "PCMU"] }
When G.711 is enabled and selected during SDP negotiation, audio is transcoded between OPUS (WhatsApp side) and G.711 (your side) — adds latency, lower fidelity, higher bandwidth (~64 kbps vs OPUS's ~20 kbps for similar quality). Use only when you must interop with G.711-only equipment.
To disable additional codecs:
"audio": { "additional_codecs": [] }
Get Current Settings
GET /<PHONE_NUMBER_ID>/settings
Returns the current calling configuration plus other phone-number settings. SIP password is omitted by default — pass ?include_sip_credentials=true to include it.
{
"calling": {
"status": "ENABLED",
"call_icon_visibility": "DEFAULT",
"callback_permission_status": "ENABLED",
"call_hours": { /* ... */ },
"sip": { "status": "ENABLED", "servers": [{ "hostname": "[REDACTED]" }] },
"audio": { "additional_codecs": ["PCMA", "PCMU"] }
}
}
Restrictions in the Response
If Meta has temporarily restricted your phone number's calling capability (typically due to high negative user feedback), the response includes a restrictions object:
"calling": {
"restrictions": {
"restrictions_list": [
{
"type": "RESTRICTED_BUSINESS_INITIATED_CALLING",
"reason": "Business initiated calling capability has been temporarily disabled for this phone number due to high negative feedback from users.",
"expiration": 1754072386
}
]
}
}
| Field | Notes |
|---|---|
type | RESTRICTED_BUSINESS_INITIATED_CALLING or RESTRICTED_USER_INITIATED_CALLING |
reason | Human-readable description |
expiration | Unix timestamp (UTC) when the restriction lifts |
When restricted, calling endpoints for the affected direction return errors until expiration. Reduce sender load on permissions and outbound calls and improve quality before the next restriction hits.
Settings Webhook (account_settings_update)
Subscribe to the account_settings_update webhook field to be notified when phone-number settings change — including your own updates.
Currently only changes to these calling fields trigger the webhook: status, call_icon_visibility, callback_permission_status, sip.status, and srtp_key_exchange_protocol.
{
"object": "whatsapp_business_account",
"entry": [
{
"id": "102290129340398",
"changes": [
{
"field": "account_settings_update",
"value": {
"messaging_product": "whatsapp",
"timestamp": "1671644824",
"type": "phone_number_settings",
"phone_number_settings": {
"phone_number_id": "123456789012345",
"calling": {
"status": "ENABLED",
"call_icon_visibility": "DEFAULT",
"callback_permission_status": "ENABLED",
"call_hours": { /* full call_hours object */ },
"sip": {
"status": "ENABLED",
"servers": [{ "hostname": "[REDACTED]", "port": 5061 }]
}
}
}
}
}
]
}
]
}
Subscribed app must have whatsapp_business_management permission. Same app rule as messaging webhooks: it must be subscribed to the WABA.
Dualhook stance: Dualhook does not auto-subscribe to account_settings_update. To receive these webhooks, subscribe your own app to the field at the WABA level and host the receiver yourself — these events bypass Dualhook entirely (see Webhook Subscription Fields).
Client Refresh Behavior
After updating call settings, WhatsApp users may take up to 7 days to reflect the change in their client UI — though most refresh much sooner. The server-side semantics are honored immediately; the lag is purely cosmetic on the user's app.
To force an immediate refresh in WhatsApp: enter the chat with the business and open the chat info page. That triggers a fresh fetch.
You can also configure call settings from WhatsApp Manager → Account tools → Phone numbers → gear icon → Calls tab.