> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pyai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Answer WhatsApp calls with an Omni agent

> Connect a WhatsApp Business number to Omni: register the number, enable calling, and let your agent answer WhatsApp voice calls (and place them, with the user's permission).

Your customers already have WhatsApp open. With WhatsApp Business Calling, a
tap on the call button in your business chat rings straight into an
[Omni](/realtime/omni-protocol) agent, no phone number to buy, no telephony
bridge to run. PyAI terminates Meta's WebRTC leg and hands your agent the same
audio it gets on a phone call.

<Info>
  **Preview.** WhatsApp calling is rolling out per deployment. The API below is
  final; ask us to enable it on your org.
</Info>

## How it fits together

```mermaid theme={null}
flowchart LR
  user([WhatsApp user]) -->|taps Call| meta[Meta Cloud API]
  meta -->|calls webhook| pyai[PyAI]
  meta <-->|WebRTC: Opus, DTLS-SRTP| pyai
  pyai <-->|PCM16| omni[Omni agent]
```

Meta signals the call to PyAI (`calls` webhook) and streams the audio over
WebRTC. PyAI answers, converts the audio, and opens an Omni session for the
agent bound to the number. You never touch SDP, ICE, or Opus.

## Before you start

* A **WhatsApp Business number on Meta's Cloud API** with a messaging limit of
  at least 2,000 conversations per day (Meta's prerequisite for calling).
* A **system-user access token** for that WhatsApp Business Account with the
  `whatsapp_business_messaging` permission.
* A PyAI **live** API key with the `telephony:manage` scope.

## 1. Point Meta's webhooks at PyAI

In your Meta app: **WhatsApp → Configuration → Webhooks**. Set the callback URL
to `https://api.pyai.com/public/whatsapp/webhook`, use the verify token PyAI
gave you, and subscribe to **`calls`** and **`messages`** (the second one
carries call-permission replies).

## 2. Register the number and bind an agent

```bash theme={null}
curl https://api.pyai.com/v1/whatsapp/numbers \
  -H "Authorization: Bearer $PYAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "waba_id": "1029384756",
    "phone_number_id": "1234567890",
    "display_phone_number": "+14155550123",
    "access_token": "EAAB...",
    "agent_id": "agent_29c8b2bb..."
  }'
```

The token is stored encrypted and never returned. Rebind the agent any time
with `POST /v1/whatsapp/numbers/{id}/assign`.

## 3. Turn calling on

```bash theme={null}
curl -X POST https://api.pyai.com/v1/whatsapp/numbers/wan_.../calling \
  -H "Authorization: Bearer $PYAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": true }'
```

This pushes Meta's calling settings for the number (call button on, and a user
who calls you automatically grants a 7-day call-back permission). Users may
take a little while to see the call button; opening the chat info page refreshes
it.

That's it for inbound. Tap the call button in the business chat and your agent
answers with its greeting.

## Calling a user (business-initiated)

Meta requires the user's permission before you can call them. Ask for it:

```bash theme={null}
curl -X POST https://api.pyai.com/v1/whatsapp/call-permissions \
  -H "Authorization: Bearer $PYAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "number_id": "wan_...", "to": "+919876543210",
        "text": "May we call you about your order?" }'
```

Meta shows the user a prompt; their answer arrives on the webhook and PyAI
records it. Check it with `GET /v1/whatsapp/call-permissions?number_id=…&user=…`.
Then place the call:

```bash theme={null}
curl -X POST https://api.pyai.com/v1/whatsapp/calls \
  -H "Authorization: Bearer $PYAI_API_KEY" \
  -H "Idempotency-Key: order-4711-callback" \
  -H "Content-Type: application/json" \
  -d '{ "number_id": "wan_...", "to": "+919876543210" }'
```

Without a live permission the call is refused with `call_permission_required`.
Permission requests are rate-limited by Meta (one per 24 hours, two per 7 days
per user), and business-initiated calls are not offered in every country.

## Call records

`GET /v1/whatsapp/calls` lists calls newest first with direction, status,
connect and end times, and duration. Hang up from your side with
`POST /v1/whatsapp/calls/{id}/terminate`.

## What's different from a phone call

* **No DTMF.** WhatsApp users speak; keypad tones are not delivered to the agent.
* **No transfer to a human.** There is no phone leg to transfer; end the call
  and follow up in the chat instead.
* **Audio is wideband** on WhatsApp's side; the agent hears it at telephony
  quality today.

## Reference

* The `WhatsApp` tag in the [OpenAPI contract](https://api.pyai.com/openapi.json) lists every endpoint and schema.
* [Telephony audio](/reference/telephony-audio) for what the agent hears on a call leg.
* Meta's [Cloud API Calling](https://developers.facebook.com/docs/whatsapp/cloud-api/calling) docs for number prerequisites and regional availability.
