---
title: WhatsApp Business Cloud API
---
# WhatsApp Business Cloud API

## Overview

Official API for businesses to send and receive messages on WhatsApp. Integrated via a **thin FastAPI gateway** that routes messages to Rivet actors.

- **Docs**: [developers.facebook.com/docs/whatsapp/cloud-api](https://developers.facebook.com/docs/whatsapp/cloud-api)
- **Setup**: [developers.facebook.com](https://developers.facebook.com)

## Integration Architecture

```mermaid
graph TB
    subgraph "WhatsApp Side"
        USER[User Phone]
        WS[WhatsApp Servers]
    end

    subgraph "Our Side"
        subgraph "FastAPI Gateway"
            WH[Webhook Endpoint]
            VERIFY[Signature Verification]
            ROUTE[Route to Rivet Actor]
        end

        subgraph "Rivet Actor"
            ACTOR[ShoppingAgentActor]
            FMT[WhatsApp Formatter]
        end

        API[WhatsApp Business API]
    end

    USER -->|sends message| WS
    WS -->|webhook POST| WH
    WH --> VERIFY
    VERIFY --> ROUTE
    ROUTE --> ACTOR
    ACTOR --> FMT
    FMT --> API
    API --> WS
    WS --> USER

    style WH fill:#fff9c4
    style API fill:#25d366
    style ACTOR fill:#c8e6c9,stroke:#388e3c
```

## The Gateway Is Minimal

```python
from fastapi import FastAPI, Request, BackgroundTasks

app = FastAPI()

@app.post("/webhook")
async def webhook(request: Request, background_tasks: BackgroundTasks):
    body = await request.json()
    for msg in extract_messages(body):
        user_id = msg["sender"]
        actor = await rivet.get_actor(ShoppingAgentActor, user_id)
        background_tasks.add_task(actor.on_message, msg["text"])
    return {"status": "ok"}  # Immediate 200 to WhatsApp
```

The gateway does NOT:
- Process messages
- Manage agent state
- Format responses
- Call LLMs or Shopify

It only:
1. Verifies webhook signature
2. Extracts user_id + text
3. Gets/creates Rivet actor for user
4. Sends message to actor
5. Returns 200 OK

The **actor** does everything else, including sending the final response via WhatsApp.

## Message Flow

```mermaid
sequenceDiagram
    participant U as User
    participant W as WhatsApp
    participant G as FastAPI
    participant A as Actor
    participant F as Formatter

    U->>W: Sends message
    W->>G: Webhook POST
    G-->>W: 200 OK (instant)
    G->>A: on_message(text)
    A->>A: Process + generate response
    A->>F: Format for WhatsApp
    F->>W: POST /messages (send reply)
    W->>U: Deliver message
```

## Key Capabilities

### Sending Messages
- Text messages (4096 char limit)
- Media (images, videos, documents)
- Interactive messages (buttons, lists)
- Templates (for notifications)

### Receiving Messages
- Webhook-based delivery
- Real-time processing
- Message status updates (delivered, read)

## Message Types for Shopping

```mermaid
graph LR
    subgraph "Product Results"
        LIST[List Message<br/>Multiple products]
        PROD[Product Card<br/>Single product]
    end

    subgraph "Cart/Orders"
        BTN[Button Message<br/>Actions]
        TEXT[Text Message<br/>Status updates]
    end

    subgraph "Policies/Help"
        TEXT2[Text Message<br/>Formatted help]
    end
```

## Setup Requirements

1. **Facebook Business account** — [business.facebook.com](https://business.facebook.com)
2. **WhatsApp Business account** — Business Manager → WhatsApp → Add phone number
3. **WhatsApp Cloud API access** — Apps → Create App → Business → WhatsApp
4. **Webhook verification** — Token + callback URL
5. **Phone number verification** — For production use

## Rate Limits

| Limit | Value |
|-------|-------|
| Messages per second (business) | 200 |
| Messages per second (phone number) | 50 |
| Conversation window | 24 hours |
| Template messages | Require pre-approval |

## Session Windows

- 24-hour customer service window
- After 24 hours, need template messages
- Templates require pre-approval

## Security

- End-to-end encryption (WhatsApp native)
- **Webhook signature verification** — `X-Hub-Signature-256` header
- Access token management
- IP whitelisting (optional)

### Credentials Required

**Sending replies** requires only two credentials, passed to the Messages
endpoint as the URL path ID and the Bearer header:

- `WHATSAPP_PHONE_NUMBER_ID` — your business phone number ID
- `WHATSAPP_ACCESS_TOKEN` — your system-user access token

**Receiving webhooks** additionally needs two optional values to authenticate
inbound requests. When they are not set, the gateway logs a warning and skips
verification (dev mode):

- `WHATSAPP_APP_SECRET` — used to verify the `X-Hub-Signature-256` header
- `WHATSAPP_VERIFY_TOKEN` — used to answer Meta's initial GET challenge

### Signature Verification

```python
import hmac, hashlib, os

def verify_signature(payload: bytes, signature: str) -> bool:
    expected = hmac.new(
        os.environ["WHATSAPP_APP_SECRET"].encode(),
        payload,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature)
```

## WhatsApp Formatter (Inside Actor)

```python
# extensions/whatsapp_formatter.py
def format_for_whatsapp(response: str) -> dict:
    """Format agent response for WhatsApp Cloud API."""
    # WhatsApp message limit
    max_length = 4096
    if len(response) > max_length:
        response = response[:max_length - 50] + "\n\n_(truncated)_"

    return {
        "messaging_product": "whatsapp",
        "to": user_id,
        "text": {"body": response}
    }
```

## Interactive Messages

### List Messages (Product Results)

```python
{
    "messaging_product": "whatsapp",
    "to": user_id,
    "type": "interactive",
    "interactive": {
        "type": "list",
        "header": {"type": "text", "text": "🛍️ Products Found"},
        "body": {"text": f"Found {len(products)} products:"},
        "footer": {"text": "Tap to view details"},
        "action": {
            "button": "View Products",
            "sections": [{
                "title": "Results",
                "rows": [
                    {"id": f"product_{p['id']}", "title": p['name'], "description": f"${p['price']}"}
                    for p in products
                ]
            }]
        }
    }
}
```

### Button Messages (Cart Actions)

```python
{
    "messaging_product": "whatsapp",
    "to": user_id,
    "type": "interactive",
    "interactive": {
        "type": "button",
        "body": {"text": "🛒 Your cart total: $120"},
        "action": {
            "buttons": [
                {"type": "reply", "reply": {"id": "checkout", "title": "Checkout"}},
                {"type": "reply", "reply": {"id": "add_more", "title": "Add More"}},
                {"type": "reply", "reply": {"id": "clear", "title": "Clear Cart"}}
            ]
        }
    }
}
```

## Error Handling

```mermaid
flowchart TD
    SEND[Send Message] --> CHECK{Success?}
    CHECK -->|Yes| LOG[Log success]
    CHECK -->|No| TYPE{Error type?}

    TYPE -->|Rate limit| WAIT[Wait + retry]
    TYPE -->|Auth error| REFRESH[Refresh token]
    TYPE -->|Invalid phone| NOTIFY[Notify user]
    TYPE -->|Network error| RETRY[Retry with backoff]

    WAIT --> SEND
    REFRESH --> SEND
    RETRY --> SEND
```

## See Also

- [Integration Guide](/integration-guide) — Full wiring
- [Rivet Actor Model](/rivet-actor-model) — Actor implementation
- [Architecture](/architecture) — High-level overview
