Skip to content
AI Agent How-To

Home › Connect agents to apps

How to Connect an AI Agent to WhatsApp (Cloud API + Python)

Intermediate ~5 min read Last tested October 2026

Updated 2026-10-15

This guide connects an AI agent to WhatsApp through Meta’s official WhatsApp Business Platform Cloud API. Incoming messages hit your webhook, the agent writes a reply, and you send it back through the Graph API. Unofficial “WhatsApp Web” libraries can get numbers banned, so avoid them for anything real.

Prerequisites

  • A Meta developer account and a Meta Business account
  • A server reachable over HTTPS (for local testing, a tunnel such as cloudflared tunnel --url http://localhost:8000 or ngrok)
  • Python 3.10+ and an LLM API key

Steps

1. Create the WhatsApp app

  1. At developers.facebook.com, click Create app, choose the Business type, and add the WhatsApp product.
  2. Under WhatsApp → API Setup you get a free test number, its Phone number ID, and a temporary access token (valid ~24 hours). Add your personal phone as a recipient.
  3. For production, create a System User in Business Settings and generate a permanent token with whatsapp_business_messaging and whatsapp_business_management permissions.

2. Install dependencies

pip install fastapi uvicorn httpx openai
export WA_TOKEN="EAAG..."  WA_PHONE_ID="1234567890"  WA_VERIFY="pick-any-secret"

3. Write the webhook server

# app.py
import os, httpx
from fastapi import FastAPI, Request, Response
from openai import OpenAI

app, llm = FastAPI(), OpenAI()
GRAPH = f"https://graph.facebook.com/v21.0/{os.environ['WA_PHONE_ID']}/messages"
HISTORY: dict[str, list] = {}       # per-user short-term memory (use a DB in production)

@app.get("/webhook")                # Meta calls this once to verify your URL
def verify(request: Request):
    p = request.query_params
    if p.get("hub.mode") == "subscribe" and p.get("hub.verify_token") == os.environ["WA_VERIFY"]:
        return Response(p.get("hub.challenge"), media_type="text/plain")
    return Response(status_code=403)

@app.post("/webhook")
async def incoming(request: Request):
    data = await request.json()
    for entry in data.get("entry", []):
        for change in entry.get("changes", []):
            for msg in change["value"].get("messages", []):
                if msg.get("type") == "text":
                    await handle(msg["from"], msg["text"]["body"])
    return {"ok": True}             # always 200 fast, or Meta retries

async def handle(user: str, text: str):
    hist = HISTORY.setdefault(user, [{"role": "system",
             "content": "You are a friendly assistant on WhatsApp. Keep replies under 80 words."}])
    hist.append({"role": "user", "content": text})
    reply = llm.chat.completions.create(model="gpt-4.1-mini", messages=hist[-20:]).choices[0].message.content
    hist.append({"role": "assistant", "content": reply})
    async with httpx.AsyncClient() as c:
        r = await c.post(GRAPH, headers={"Authorization": f"Bearer {os.environ['WA_TOKEN']}"},
            json={"messaging_product": "whatsapp", "to": user, "type": "text", "text": {"body": reply}})
        r.raise_for_status()

Graph API versions change over time. Use the version shown in your app dashboard if v21.0 has been retired.

4. Run it and register the webhook

uvicorn app:app --port 8000
cloudflared tunnel --url http://localhost:8000     # prints an https URL

In WhatsApp → Configuration, set the Callback URL to https://YOUR-URL/webhook and the Verify token to your WA_VERIFY value, click Verify and save, then subscribe to the messages field.

5. Test

Send a WhatsApp message from your registered phone to the test number. The agent replies within a few seconds.

6. Add tools

Turn handle() into the tool-calling loop from Build your first AI agent in Python to let the agent book appointments, look up orders, etc.

Rules that matter

  • You can send free-form replies only within 24 hours of the user’s last message. Outside that window you must use a pre-approved message template.
  • Webhooks can be delivered more than once. De-duplicate on msg["id"].

Common errors

Webhook verification fails: the verify token doesn’t match, or you returned JSON instead of the raw hub.challenge string.

(#131030) Recipient phone number not in allowed list: with a test number, add the recipient under API Setup first.

(#131047) Re-engagement message: more than 24 hours since the user wrote. Use a template message.

Error validating access token: Session has expired: the temporary token expired. Use a System User token.