Before you start
A WhatsApp agent runs on Meta's WhatsApp Business Platform through the Cloud API, not on the WhatsApp app on someone's phone. To use it you need:
- A Meta business account, and a WhatsApp Business Account inside it.
- A phone number for the agent: the one your customers already know, moved to the platform, or a new one.
- Someone at your company who can approve the setup in Meta's tools. The accounts stay in your name.
Meta's getting started guide walks through the setup. When we build the agent, we do it with you in the first milestone.
1. Map the job
Start from real conversations, not from what the agent could do. Export a few weeks of chats, read them, and write down three lists: what it handles, what it never does, and when it hands off to a person.
| It handles | It never does | It hands off when |
|---|---|---|
| Questions about products, prices and stock, from the catalog. | Promise a refund, a discount or a delivery date it can't check. | The customer complains or asks for a person. |
| Order status, from the order system. | Ask for card numbers in the chat. | A payment failed or an order is missing. |
| Store hours and locations. | Answer questions outside the store's business. | It can't find the answer in your data. |
These lists become the agent's instructions and, later, its test cases. Keep the first version to one job. A second one can come once the first passes its evals.
2. Wire it to your data
An agent answers well when it looks things up instead of remembering them. It gets two kinds of access:
- Tools: small actions on your systems, such as
check_stock,find_orderorbook_slot. Each does one thing, and the agent can't do anything its tools don't allow. - Retrieval: search over your documents and help pages, so each answer comes with the passage it came from.
Messages reach the agent through a webhook: Meta sends each new message to an address on your server, and the agent replies through the Cloud API. This is the skeleton in Python with FastAPI, the stack we use:
import hashlib
import hmac
import os
from fastapi import BackgroundTasks, FastAPI, HTTPException, Request
from fastapi.responses import PlainTextResponse
app = FastAPI()
VERIFY_TOKEN = os.environ["WHATSAPP_VERIFY_TOKEN"]
APP_SECRET = os.environ["META_APP_SECRET"].encode()
@app.get("/webhooks/whatsapp")
def verify(request: Request) -> PlainTextResponse:
# Meta calls this once, when you register the webhook.
query = request.query_params
if query.get("hub.mode") == "subscribe" and query.get("hub.verify_token") == VERIFY_TOKEN:
return PlainTextResponse(query.get("hub.challenge", ""))
raise HTTPException(403)
@app.post("/webhooks/whatsapp")
async def receive(request: Request, tasks: BackgroundTasks) -> dict[str, str]:
body = await request.body()
signature = "sha256=" + hmac.new(APP_SECRET, body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(signature, request.headers.get("X-Hub-Signature-256", "")):
raise HTTPException(401)
payload = await request.json()
for entry in payload.get("entry", []):
for change in entry.get("changes", []):
for message in change["value"].get("messages", []):
# Answer outside the request: Meta expects a quick 200.
tasks.add_task(answer, message)
return {"status": "received"}import httpx
GRAPH = "https://graph.facebook.com/v23.0" # the Graph API version your app uses
PHONE_NUMBER_ID = os.environ["WHATSAPP_PHONE_NUMBER_ID"]
TOKEN = os.environ["WHATSAPP_TOKEN"]
async def answer(message: dict) -> None:
... # the agent: look things up with its tools, decide, then send_text() or hand off
async def send_text(to: str, text: str) -> None:
async with httpx.AsyncClient() as client:
response = await client.post(
f"{GRAPH}/{PHONE_NUMBER_ID}/messages",
headers={"Authorization": f"Bearer {TOKEN}"},
json={"messaging_product": "whatsapp", "to": to, "type": "text", "text": {"body": text}},
)
response.raise_for_status()- Meta signs each delivery with your app secret. Check the signature before you trust the payload.
- Return 200 quickly and answer from a background job. Meta retries deliveries that fail, so the same message can arrive twice: keep the ids of the messages you've handled and skip repeats.
- Keep tokens and secrets in a secret manager, never in the code.
3. Write the evals
Evals tell you the agent is ready before a customer finds out it isn't. Each one is a real message with the outcome it should get:
{"message": "Do you have the black running shoes in size 42?", "expect": "answer", "must_use": "check_stock"}
{"message": "My order never arrived and I want my money back", "expect": "hand_off"}
{"message": "Can you give me a discount if I buy two?", "expect": "decline", "must_not": "offer a discount"}- Take the cases from your real chats, hard ones included: complaints, angry messages, questions it must not answer.
- Agree on a pass threshold before the build, and keep the agent off until it meets it.
- Run the whole set on every change, and again when the model or the prompt changes.
- Add cases in each language your customers write in.
On this site
The AI that sorts the briefs we receive has 31 graded cases and stays off until it passes 90% of them. The agents we build follow the same rule, with a threshold agreed with you.
4. Pilot and watch
Open it to a small group of real customers first, with your team watching:
- A console where your team reads conversations and takes over the ones the agent hands off, with the conversation so far.
- A second AI provider that takes over if the first one fails, so an outage doesn't leave customers without an answer.
- The cost of every conversation, so you know what the agent will cost at full volume.
Every conversation that goes wrong becomes a new eval case. When the agent passes the set again, the pilot grows.
WhatsApp's rules that shape the design
Meta's platform has rules a website chat doesn't. Three of them change how the agent is built:
- Customers write first. The agent replies freely in the customer service window that opens when a customer writes. To start a conversation, or to write after that window closes, a business can only send message templates that Meta approves beforehand (how templates work).
- Opt-in comes first. Before you message someone who hasn't written to you, they must have agreed to hear from you on WhatsApp, as Meta's Business Messaging Policy requires.
- Templates are billed. Meta charges for them by category and country; its pricing page has the rates.
So we design for it from the first step: the agent answers inside the window, and the messages it has to start, like reminders and order updates, go out as approved templates.
What it costs
Building one with us is an AI Agent engagement, from $8,000, with a fixed price per milestone. Model usage and Meta's fees are billed to your own accounts. The details are in How much does an AI agent cost?, and the service is at WhatsApp AI agents.