LiveKit docs › Connectors › WhatsApp

---

# WhatsApp Connector

> Connect LiveKit to a WhatsApp Business phone number for voice calls.

Available in (BETA):
- [ ] Node.js
- [ ] Python

## Overview

The WhatsApp Connector bridges LiveKit with the WhatsApp communication platform, providing bidirectional audio streaming and media processing—including resampling, mixing, and codec translation. It manages all API calls needed to initiate, connect, and control the call lifecycle. The connector lets you bring WhatsApp calls directly into a LiveKit room, where you can optionally dispatch LiveKit Agents to handle the interaction.

WhatsApp participants can be identified using the `kind` field, which identifies the [type of participant](https://docs.livekit.io/intro/basics/rooms-participants-tracks/participants.md#types-of-participants) in a LiveKit room. For WhatsApp participants, this is `CONNECTOR`.

### Use cases

Use the WhatsApp Connector to build customer support workflows, triage systems, appointment and reminder flows, or outbound engagement experiences. For example, an agent can speak with a user during a call, then immediately send an invoice or follow-up information as a text message without switching channels.

## Prerequisites

To use the WhatsApp Connector, you need the following:

- A phone number registered with a [WhatsApp Business account](https://developers.facebook.com/docs/whatsapp).
- A [WhatsApp Cloud API](https://developers.facebook.com/docs/whatsapp/cloud-api) access token.
- A [Meta Developer Account](https://developers.facebook.com) to create and manage your app.
- An app capable of receiving and handling [WhatsApp webhooks](https://developers.facebook.com/docs/whatsapp/cloud-api/guides/set-up-webhooks).
- Call permissions enabled on the Meta platform:- **Inbound calls**: Configure available call hours for your business. To learn more, see [User-initiated calls](https://developers.facebook.com/docs/whatsapp/cloud-api/calling/user-initiated-calls).
- **Outbound calls**: Available only in certain regions. You must be in a supported region and obtain explicit permission from the user before initiating a call. To learn more, see [Business-initiated calls](https://developers.facebook.com/docs/whatsapp/cloud-api/calling/business-initiated-calls).

The WhatsApp Connector works with WhatsApp Cloud API v23.0 or v24.0.

## Key concepts

The WhatsApp Connector relies on webhooks and SDP negotiation to establish and manage calls.

### Webhooks

Webhooks are automated, realtime notifications that one application sends to another when specific events occur. They work by delivering an HTTP POST request to a designated URL. WhatsApp uses webhooks to notify your app whenever something happens, such as an incoming call or message.

For both inbound and outbound calls, WhatsApp sends a call connect webhook that includes the [Session Description Protocol (SDP)](#sdp) offer or answer needed to establish the connection. Your app must receive this webhook, extract the SDP, and pass it to a LiveKit Connector API to complete the connection.

Configuring a webhook endpoint is required to use the connector. Without it, your app cannot detect when a call is ready to connect or retrieve the SDP offer or answer needed to complete the setup.

To set up webhooks for your WhatsApp Business account, see the [webhook configuration guide](https://developers.facebook.com/docs/whatsapp/cloud-api/guides/set-up-webhooks).

### SDP

SDP is a standardized format used in multimedia communications to describe the parameters of a media session, such as media types, codecs, and transport protocols. WhatsApp uses SDP offer and answer negotiation to establish a media connection with LiveKit. For inbound calls, WhatsApp sends an SDP offer; for outbound calls, it sends an SDP answer.

## Making outbound calls

An outbound call is a WhatsApp call initiated from a WhatsApp Business account to a user's WhatsApp number. Outbound calling is not available in all regions. Check for feature [availability](https://developers.facebook.com/docs/whatsapp/cloud-api/calling#availability).

### Workflow

The flow for a business-initiated (outbound) call is as follows:

1. Your app calls the `DialWhatsAppCall` API to initiate an outbound call.

- This API call delegates to the WhatsApp Cloud API to [initiate the call](https://developers.facebook.com/docs/whatsapp/cloud-api/calling/business-initiated-calls#part-2--your-business-initiates-a-new-call-to-the-whatsapp-user) and returns a `WhatsAppCallId`.
- Meta begins dialing the user's WhatsApp number.
2. When the call is ready to connect, Meta sends a `call connect` [webhook](https://developers.facebook.com/docs/whatsapp/cloud-api/calling/business-initiated-calls#call-connect-webhook) containing the SDP answer.
3. Your app calls the `ConnectWhatsAppCall` API with the `WhatsAppCallId` and the [SDP](#sdp) answer to complete the connection.

The following diagram illustrates the outbound WhatsApp call flow:

```mermaid
sequenceDiagram
participant App as Your Application
participant LK as LiveKit Connector
participant Meta as Meta/WhatsApp
participant User as WhatsApp UserApp->>LK: DialWhatsAppCall(phone number, room, etc.)
LK->>Meta: Initiate call
Meta-->>LK: WhatsAppCallId
LK-->>App: WhatsAppCallId + RoomName
Meta-->>User: Ring notification
Note over Meta,User: User's phone rings
Meta->>App: Call connect webhook (SDP answer)
App->>LK: ConnectWhatsAppCall(CallId, SDP)
LK-->>App: Success
Note over App,User: Call connected - audio flows via LiveKit room
```

### Required webhooks

For outbound calls, WhatsApp sends a `call connect` webhook that includes the SDP answer. Your app must receive this webhook and pass the SDP to `ConnectWhatsAppCall` to complete the connection.

### Example

Completing an outbound call is a multi-step process:

1. Use the `DialWhatsAppCall` API to initiate an outbound call with the following parameters:

| Parameter | Required | Description |
| `WhatsAppPhoneNumberId` | Yes | Your WhatsApp Business [phone number](https://developers.facebook.com/docs/whatsapp/business-management-api/manage-phone-numbers) ID. |
| `WhatsAppToPhoneNumber` | Yes | The user's WhatsApp number to call. Must include the country code without the leading `+` sign. |
| `WhatsAppApiKey` | Yes | Your WhatsApp API access token. To learn more, see [Generate an access token](https://developers.facebook.com/docs/whatsapp/cloud-api/get-started/#step-2--generate-an-access-token). |
| `WhatsAppCloudApiVersion` | Yes | The WhatsApp Cloud API version (for example, `23.0` or `24.0`). |
| `DestinationCountry` | No | Optional two letter country code for the country where the call terminates. See [Regional routing](#regional-routing). |

Other optional fields include: `Agents`, `ParticipantMetadata`, `ParticipantAttributes`, and `RingingTimeout`.

For a full list of parameters and their descriptions, see the [DialWhatsAppCall](https://docs.livekit.io/reference/telephony/connectors-api.md#dialwhatsappcall) API reference.

**Node.js**:

```typescript
import { ConnectorClient } from 'livekit-server-sdk';

const connectorClient = new ConnectorClient(
  process.env.LIVEKIT_URL,
  process.env.LIVEKIT_API_KEY,
  process.env.LIVEKIT_API_SECRET,
);

const res = await connectorClient.dialWhatsAppCall({
  whatsappPhoneNumberId: 'whatsapp-business-phone-number-id',
  whatsappToPhoneNumber: 'user-number-to-dial',
  whatsappCloudApiVersion: '23.0',
  whatsappApiKey: 'your-meta-access-token',
  destinationCountry: 'US', // optional
  roomName: 'whatsapp-connector-test', // optional
  participantIdentity: 'test-identity', // optional
  participantName: 'test-user', // optional
  agents: [{ agentName: 'my-agent' }],
});

```

---

**Python**:

```python
from livekit import api

lkapi = api.LiveKitAPI()
from livekit.protocol.agent_dispatch import RoomAgentDispatch

res = await lkapi.connector.dial_whatsapp_call(
    api.DialWhatsAppCallRequest(
        whatsapp_phone_number_id="whatsapp-business-phone-number-id",
        whatsapp_to_phone_number="user-number-to-dial",
        whatsapp_cloud_api_version="23.0",
        whatsapp_api_key="your-meta-access-token",
        destination_country="US",  # optional
        room_name="whatsapp-connector-test",  # optional
        participant_identity="test-identity",  # optional
        participant_name="test-user",  # optional
        agents=[RoomAgentDispatch(agent_name="my-agent")],
    )
)

```

---

**Go**:

```go
res, err := connectorClient.DialWhatsAppCall(ctx, &livekit.DialWhatsAppCallRequest{
    WhatsappPhoneNumberId:   "whatsapp-business-phone-number-id",
    WhatsappToPhoneNumber:   "user-number-to-dial",
    WhatsappCloudApiVersion: "23.0",
    WhatsappApiKey:          "your-meta-access-token",
    DestinationCountry:      "US", // optional
    RoomName:                "whatsapp-connector-test", // optional
    ParticipantIdentity:     "test-identity", // optional
    ParticipantName:         "test-user", // optional
    Agents: []*livekit.RoomAgentDispatch{
        {
            AgentName: "my-agent",
        },
    },
})

```

---

**Kotlin**:

```kotlin
import io.livekit.server.ConnectorServiceClient
import io.livekit.server.WhatsAppCallOptions

val connectorClient = ConnectorServiceClient.createClient(
  host = System.getenv("LIVEKIT_URL").replaceFirst(Regex("^ws"), "http"),
  apiKey = System.getenv("LIVEKIT_API_KEY"),
  secret = System.getenv("LIVEKIT_API_SECRET"),
)

import livekit.LivekitAgentDispatch.RoomAgentDispatch

val res = connectorClient.dialWhatsAppCall(
    whatsappPhoneNumberId = "whatsapp-business-phone-number-id",
    whatsappToPhoneNumber = "user-number-to-dial",
    whatsappApiKey = "your-meta-access-token",
    whatsappCloudApiVersion = "23.0",
    options = WhatsAppCallOptions(
        destinationCountry = "US", // optional
        roomName = "whatsapp-connector-test", // optional
        participantIdentity = "test-identity", // optional
        participantName = "test-user", // optional
        agents = listOf(
            RoomAgentDispatch.newBuilder()
                .setAgentName("my-agent")
                .build(),
        ),
    ),
).execute()

```

---

**Rust**:

```rust
use livekit_api::services::connector::{ConnectorClient, DialWhatsAppCallOptions};

let connector_client = ConnectorClient::with_api_key(host, api_key, api_secret);

use livekit_protocol::RoomAgentDispatch;

let res = connector_client
    .dial_whatsapp_call(
        "whatsapp-business-phone-number-id",
        "user-number-to-dial",
        "your-meta-access-token",
        "23.0",
        DialWhatsAppCallOptions {
            destination_country: Some("US".into()), // optional
            room_name: Some("whatsapp-connector-test".into()), // optional
            participant_identity: Some("test-identity".into()), // optional
            participant_name: Some("test-user".into()), // optional
            agents: Some(vec![RoomAgentDispatch {
                agent_name: "my-agent".into(),
                ..Default::default()
            }]),
            ..Default::default()
        },
    )
    .await?;

```

The response includes a `WhatsAppCallId` from Meta and a `RoomName` (either provided using the `RoomName` parameter or auto-generated).
2. Meta then sends a `call connect` [webhook](https://developers.facebook.com/docs/whatsapp/cloud-api/calling/business-initiated-calls#call-connect-webhook) containing the SDP answer.

Upon receiving the webhook, call `ConnectWhatsAppCall` immediately with the `WhatsAppCallId` and the SDP answer from the webhook to complete the connection:

**Node.js**:

```typescript
const res = await connectorClient.connectWhatsAppCall(
  call.id,
  { type: 'answer', sdp: call.session.sdp },
);

```

---

**Python**:

```python
from livekit.protocol.rtc import SessionDescription

res = await lkapi.connector.connect_whatsapp_call(
    api.ConnectWhatsAppCallRequest(
        whatsapp_call_id=call.id,
        sdp=SessionDescription(type="answer", sdp=call.session.sdp),
    )
)

```

---

**Go**:

```go
res, err := connectorClient.ConnectWhatsAppCall(ctx, &livekit.ConnectWhatsAppCallRequest{
    WhatsappCallId: call.ID,
    Sdp: &livekit.SessionDescription{
        Type: "answer",
        Sdp:  call.Session.SDP,
    },
})

```

---

**Kotlin**:

```kotlin
import livekit.LivekitRtc.SessionDescription

val res = connectorClient.connectWhatsAppCall(
    whatsappCallId = call.id,
    sdp = SessionDescription.newBuilder()
        .setType("answer")
        .setSdp(call.session.sdp)
        .build(),
).execute()

```

---

**Rust**:

```rust
use livekit_protocol::SessionDescription;

let res = connector_client
    .connect_whatsapp_call(
        &call.id,
        SessionDescription {
            r#type: "answer".into(),
            sdp: call.session.sdp.clone(),
        },
    )
    .await?;

```

> ❗ **Delayed connection can result in silence**
> 
> Because the user's phone starts ringing when the `DialWhatsAppCall` call is processed, delays in calling `ConnectWhatsAppCall` after the webhook is received can result in silence and eventual disconnection.

### Disconnecting calls

Use `DisconnectWhatsAppCall` to end an active WhatsApp call. You must call this API for both business-initiated and user-initiated disconnects. When a user hangs up, Meta sends a [call terminate webhook](https://developers.facebook.com/docs/whatsapp/cloud-api/calling/user-initiated-calls#call-terminate-webhook) to your app. Your webhook handler must then call `DisconnectWhatsAppCall` with `USER_INITIATED` so LiveKit can clean up the connector session and room resources.

> ℹ️ **Automatic cleanup after 30 seconds**
> 
> If you don't call `DisconnectWhatsAppCall` after a user hangs up, LiveKit automatically cleans up the call after 30 seconds. During this window, any agents, egress, or other services running in the room continue to run unnecessarily. Always call the API promptly to avoid wasted resources.

#### Parameters

| Parameter | Required | Description |
| `whatsapp_call_id` | Yes | The call ID provided by Meta. |
| `whatsapp_api_key` | Conditional | Your Meta API key. Required when `disconnect_reason` is `BUSINESS_INITIATED`. Optional for `USER_INITIATED` because no API call to WhatsApp is needed. |
| `disconnect_reason` | No | The reason for disconnecting the call. Defaults to `BUSINESS_INITIATED`. |

The `disconnect_reason` field accepts one of the following values:

- `BUSINESS_INITIATED`: The business is ending the call. Requires `whatsapp_api_key`.
- `USER_INITIATED`: The user ended the call. Use this when you receive a [call terminate webhook](https://developers.facebook.com/docs/whatsapp/cloud-api/calling/user-initiated-calls#call-terminate-webhook) from Meta. Note that Meta also sends this webhook when the business disconnects, so calling the API twice results in an error.

#### Business-initiated disconnect example

**Node.js**:

```typescript
await connectorClient.disconnectWhatsAppCall(
  'call-id-from-meta',
  'your-meta-access-token',
  'BUSINESS_INITIATED',
);

```

---

**Python**:

```python
await lkapi.connector.disconnect_whatsapp_call(
    api.DisconnectWhatsAppCallRequest(
        whatsapp_call_id="call-id-from-meta",
        whatsapp_api_key="your-meta-access-token",
        disconnect_reason=api.DisconnectWhatsAppCallRequest.BUSINESS_INITIATED,
    )
)

```

---

**Go**:

```go
_, err := connectorClient.DisconnectWhatsAppCall(context.Background(), &livekit.DisconnectWhatsAppCallRequest{
    WhatsappCallId:   "call-id-from-meta",
    WhatsappApiKey:   "your-meta-access-token",
    DisconnectReason: livekit.DisconnectWhatsAppCallRequest_BUSINESS_INITIATED,
})

if err != nil {
    // Handle error
}

```

---

**Kotlin**:

```kotlin
import livekit.LivekitConnectorWhatsapp.DisconnectWhatsAppCallRequest.DisconnectReason

val response = connectorClient.disconnectWhatsAppCall(
    whatsappCallId = "call-id-from-meta",
    whatsappApiKey = "your-meta-access-token",
    disconnectReason = DisconnectReason.BUSINESS_INITIATED,
).execute()

```

---

**Rust**:

```rust
connector_client
    .disconnect_whatsapp_call_with_reason(
        "call-id-from-meta",
        "your-meta-access-token",
        DisconnectReason::BusinessInitiated,
    )
    .await?;

```

#### User-initiated disconnect example

When you receive a call terminate webhook from Meta indicating the user hung up, call `DisconnectWhatsAppCall` with `USER_INITIATED` to clean up the connector session. No API key is needed because no call to WhatsApp is made:

**Node.js**:

```typescript
await connectorClient.disconnectWhatsAppCall(
  'call-id-from-meta',
  undefined, // no API key needed
  'USER_INITIATED',
);

```

---

**Python**:

```python
await lkapi.connector.disconnect_whatsapp_call(
    api.DisconnectWhatsAppCallRequest(
        whatsapp_call_id="call-id-from-meta",
        disconnect_reason=api.DisconnectWhatsAppCallRequest.USER_INITIATED,
    )
)

```

---

**Go**:

```go
_, err := connectorClient.DisconnectWhatsAppCall(context.Background(), &livekit.DisconnectWhatsAppCallRequest{
    WhatsappCallId:   "call-id-from-meta",
    DisconnectReason: livekit.DisconnectWhatsAppCallRequest_USER_INITIATED,
})

```

---

**Kotlin**:

```kotlin
import livekit.LivekitConnectorWhatsapp.DisconnectWhatsAppCallRequest.DisconnectReason

val response = connectorClient.disconnectWhatsAppCall(
    whatsappCallId = "call-id-from-meta",
    disconnectReason = DisconnectReason.USER_INITIATED,
).execute()

```

---

**Rust**:

```rust
connector_client
    .disconnect_whatsapp_call_with_reason(
        "call-id-from-meta",
        "",
        DisconnectReason::UserInitiated,
    )
    .await?;

```

## Accepting inbound calls

To accept inbound WhatsApp calls, you must handle webhooks from Meta and call the `AcceptWhatsAppCall` API.

### Workflow

1. A user calls your WhatsApp Business number.
2. Meta sends a `call connect` webhook containing call details and the SDP offer.
3. Your app calls `AcceptWhatsAppCall` with the information from the webhook to accept the call.
4. The API returns the `RoomName` for the call. If the API doesn't return an error, the call is connected.

### Required webhooks

For inbound calls, WhatsApp sends a `call connect` webhook that includes the SDP offer. Your app must receive this webhook and pass the SDP offer to the `AcceptWhatsAppCall` API to complete the connection.

### Example

The following webhook handler example processes the `call connect` webhook and calls the `AcceptWhatsAppCall` API with the following parameters:

| Parameter | Required | Description |
| `WhatsAppPhoneNumberId` | Yes | Your WhatsApp Business [phone number](https://developers.facebook.com/docs/whatsapp/business-management-api/manage-phone-numbers) ID. |
| `WhatsAppApiKey` | Yes | Your Meta API key. To learn more, see [Generate an access token](https://developers.facebook.com/docs/whatsapp/cloud-api/get-started/#step-2--generate-an-access-token). |
| `WhatsAppCloudApiVersion` | Yes | WhatsApp [Cloud API](https://developers.facebook.com/docs/whatsapp/cloud-api/) version (for example, `23.0` or `24.0`). |
| `WhatsAppCallId` | Yes | WhatsApp call ID provided by Meta in the webhook. |
| `Sdp` | Yes | The [SDP](#sdp) offer provided by Meta in the webhook. |

The webhook handler creates a room named `whatsapp-connector-room` and dispatches the agent named `whatsapp-agent` to the room after the connection is established:

**Node.js**:

```typescript
// In your webhook handler
async function handleWhatsAppCallWebhook(webhookData: WhatsAppCallWebhook) {
  const response = await connectorClient.acceptWhatsAppCall({
    whatsappPhoneNumberId: '<whatsapp-business-phone-number-id>',
    whatsappApiKey: '<meta-access-token>',
    whatsappCloudApiVersion: '23.0',
    whatsappCallId: webhookData.callId,
    sdp: webhookData.sdp,
    roomName: 'whatsapp-connector-room',
    agents: [{ agentName: 'whatsapp-agent' }],
  });
}

```

---

**Python**:

```python
from livekit.protocol.agent_dispatch import RoomAgentDispatch

# In your webhook handler
async def handle_whatsapp_call_webhook(webhook_data):
    response = await lkapi.connector.accept_whatsapp_call(
        api.AcceptWhatsAppCallRequest(
            whatsapp_phone_number_id="<whatsapp-business-phone-number-id>",
            whatsapp_api_key="<meta-access-token>",
            whatsapp_cloud_api_version="23.0",
            whatsapp_call_id=webhook_data.call_id,
            sdp=webhook_data.sdp,
            room_name="whatsapp-connector-room",
            agents=[RoomAgentDispatch(agent_name="whatsapp-agent")],
        )
    )

```

---

**Go**:

```go
// In your webhook handler
func handleWhatsAppCallWebhook(w http.ResponseWriter, r *http.Request) {
    // Parse webhook payload from Meta
    var webhookData WhatsAppCallWebhook
    json.NewDecoder(r.Body).Decode(&webhookData)

    // Accept the call
    response, err := connectorClient.AcceptWhatsAppCall(context.Background(), &livekit.AcceptWhatsAppCallRequest{
        WhatsappPhoneNumberId:   "<whatsapp-business-phone-number-id>",
        WhatsappApiKey:          "<meta-access-token>",
        WhatsappCloudApiVersion: "23.0",
        WhatsappCallId:          webhookData.CallId,
        Sdp:                     webhookData.Sdp,
        RoomName:                "whatsapp-connector-room",
        Agents: []*livekit.RoomAgentDispatch{
            {
                AgentName: "whatsapp-agent",
            },
        },
    })

    if err != nil {
        // Handle error
        w.WriteHeader(http.StatusInternalServerError)
        return
    }

    w.WriteHeader(http.StatusOK)
}

```

---

**Kotlin**:

```kotlin
import io.livekit.server.WhatsAppCallOptions
import livekit.LivekitAgentDispatch.RoomAgentDispatch
import livekit.LivekitRtc.SessionDescription

// In your webhook handler
fun handleWhatsAppCallWebhook(webhookData: WhatsAppCallWebhook) {
    val response = connectorClient.acceptWhatsAppCall(
        whatsappPhoneNumberId = "<whatsapp-business-phone-number-id>",
        whatsappApiKey = "<meta-access-token>",
        whatsappCloudApiVersion = "23.0",
        whatsappCallId = webhookData.callId,
        sdp = webhookData.sdp,
        options = WhatsAppCallOptions(
            roomName = "whatsapp-connector-room",
            agents = listOf(
                RoomAgentDispatch.newBuilder()
                    .setAgentName("whatsapp-agent")
                    .build(),
            ),
        ),
    ).execute()
}

```

---

**Rust**:

```rust
use livekit_api::services::connector::{ConnectorClient, AcceptWhatsAppCallOptions};
use livekit_protocol::RoomAgentDispatch;

// In your webhook handler
async fn handle_whatsapp_call_webhook(
    connector_client: &ConnectorClient,
    webhook_data: &WhatsAppCallWebhook,
) -> Result<(), Box<dyn std::error::Error>> {
    let response = connector_client
        .accept_whatsapp_call(
            "<whatsapp-business-phone-number-id>",
            "<meta-access-token>",
            "23.0",
            &webhook_data.call_id,
            webhook_data.sdp.clone(),
            AcceptWhatsAppCallOptions {
                room_name: Some("whatsapp-connector-room".into()),
                agents: Some(vec![RoomAgentDispatch {
                    agent_name: "whatsapp-agent".into(),
                    ..Default::default()
                }]),
                ..Default::default()
            },
        )
        .await?;
    Ok(())
}

```

The same optional parameters as for outbound calls are available for customizing the participant and room. For explicit agent dispatch, make sure to include the `Agents` parameter. Use `WaitUntilAnswered` to block until the call is answered before receiving a response.

For a full list of parameters and their descriptions, see the [AcceptWhatsAppCall](https://docs.livekit.io/reference/telephony/connectors-api.md#acceptwhatsappcall) API reference.

## Setting up webhooks

This section covers the required configuration steps in the Meta Developer Console. To learn more about implementing a webhook handler, see the [WhatsApp webhook configuration guide](https://developers.facebook.com/docs/whatsapp/cloud-api/guides/set-up-webhooks).

To configure WhatsApp call webhooks:

1. Sign in to the [**Meta Developer Console**](https://developers.facebook.com/apps/) and select your app.
2. Select **WhatsApp** → **Configuration**.
3. Enter the webhook URL in **Callback URL**.
4. Enter any string for **Verify token**. Save it for your webhook handler.
5. Subscribe to the events you want to receive. At a minimum, enable the `calls` event.
6. Select the same **Version** for all subscribed webhooks: **v23.0** or **v24.0**.

## Agent dispatch

You can automatically dispatch LiveKit Agents to WhatsApp calls by including agent dispatch rules in your call requests, enabling your AI agents to interact with WhatsApp callers.

To explicitly dispatch a specific agent to an inbound or outbound call, use the `Agents` parameter in the `AcceptWhatsAppCall` or `DialWhatsAppCall` API:

**Node.js**:

```typescript
// ... other parameters
agents: [
  {
    agentName: 'whatsapp-agent',
    metadata: '{"language": "en", "department": "sales"}',
  },
],

```

---

**Python**:

```python
from livekit.protocol.agent_dispatch import RoomAgentDispatch

# ... other parameters
agents=[
    RoomAgentDispatch(
        agent_name="whatsapp-agent",
        metadata='{"language": "en", "department": "sales"}',
    ),
],

```

---

**Go**:

```go
// ... other parameters
Agents: []*livekit.RoomAgentDispatch{
    {
        AgentName: "whatsapp-agent",
        Metadata:  `{"language": "en", "department": "sales"}`,
    },
},

```

---

**Kotlin**:

```kotlin
import livekit.LivekitAgentDispatch.RoomAgentDispatch

// ... other parameters
agents = listOf(
    RoomAgentDispatch.newBuilder()
        .setAgentName("whatsapp-agent")
        .setMetadata("""{"language": "en", "department": "sales"}""")
        .build(),
),

```

---

**Rust**:

```rust
use livekit_protocol::RoomAgentDispatch;

// ... other parameters
agents: Some(vec![RoomAgentDispatch {
    agent_name: "whatsapp-agent".into(),
    metadata: r#"{"language": "en", "department": "sales"}"#.into(),
}]),

```

For more information on creating voice agents, see the [LiveKit Agents documentation](https://docs.livekit.io/agents/overview.md).

## Regional routing

Use the `destination_country` parameter to optimize call routing based on the caller's location. Provide an ISO 3166-1 alpha-2 code (for example, `US`, `GB`, `IN`).

**Node.js**:

```typescript
const response = await connectorClient.dialWhatsAppCall({
  // ... other parameters
  destinationCountry: 'US',
});

```

---

**Python**:

```python
response = await lkapi.connector.dial_whatsapp_call(
    api.DialWhatsAppCallRequest(
        # ... other parameters
        destination_country="US",
    )
)

```

---

**Go**:

```go
response, err := connectorClient.DialWhatsAppCall(context.Background(), &livekit.DialWhatsAppCallRequest{
    // ... other parameters
    DestinationCountry: "US",
})

```

---

**Kotlin**:

```kotlin
val response = connectorClient.dialWhatsAppCall(
    // ... other required parameters
    options = WhatsAppCallOptions(
        destinationCountry = "US",
    ),
).execute()

```

---

**Rust**:

```rust
let response = connector_client
    .dial_whatsapp_call(
        // ... other required parameters
        DialWhatsAppCallOptions {
            destination_country: Some("US".into()),
            ..Default::default()
        },
    )
    .await?;

```

## Troubleshooting

The following troubleshooting steps can help you resolve common issues with the WhatsApp Connector.

### Call not connecting

- Verify your WhatsApp API key permissions.
- Ensure your phone number is registered and verified.
- Confirm the correct Cloud API version.
- Check webhook URL accessibility from Meta.

### Audio quality issues

- Check network connectivity between LiveKit and Meta.
- Confirm that media tracks are being published correctly.
- Use `destination_country` to optimize routing.

### Webhook not receiving events

- Verify the webhook URL.
- Ensure the endpoint is publicly accessible.
- Check event subscriptions.
- Validate webhook signatures if enabled.

## Next steps

- **[LiveKit Agents](https://docs.livekit.io/agents/overview.md)**: Build AI voice agents to handle WhatsApp calls.

- **[Participant APIs](https://docs.livekit.io/home/server/managing-participants.md)**: Learn how to manage participants in LiveKit rooms.

---

This document was rendered at 2026-06-07T11:36:30.951Z.
For the latest version of this document, see [https://docs.livekit.io/telephony/connectors/whatsapp.md](https://docs.livekit.io/telephony/connectors/whatsapp.md).

To explore all LiveKit documentation, see [llms.txt](https://docs.livekit.io/llms.txt).