Skip to content
chatAgent
Esc
↑↓navigate↵open⌘Jpreview
On this page

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.

Integration Architecture

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

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

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

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
  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

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)

# 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)

{
    "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)

{
    "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

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

Last updated on August 1, 2026