- Respond to messages in real time via webhooks
- Persist conversations using Timbal Knowledge Bases or JSONL
- Handle text, audio, images, and documents
Setup Requirements
Meta WhatsApp App and Webhook
Meta WhatsApp App and Webhook
1
Create or open your WhatsApp App
Go to the Meta console and open your app’s WhatsApp section: Meta WhatsApp App Dashboard.
2
Set Callback URL and Verify Token
- Set the Callback URL to your endpoint, e.g.,
https://yourdomain.com/ - Set a Verify Token (keep it secret)
- In your app code, use the same token (see
WHATSAPP_VERIFY_TOKENin the example below) - Click Verify and Save
3
Subscribe to fields
In the WhatsApp product settings, subscribe to message-related events (e.g., messages, statuses).
Environment Variables
Environment Variables
Create a
.env file and set:.env
The included
whatsapp_tools.send_whatsapp_message currently references WHATSAPP_ACCESS_TOKEN/WHATSAPP_PHONE_NUMBER_ID. Ensure these are set. If you see mismatched names in your local template (e.g., WHATSAPP_TOKEN, PHONE_NUMBER_ID), set both pairs to be safe.Minimal Webhook App (FastAPI)
Use a simple FastAPI app to receive the webhook and pass the full payload to the agent. The agent will process everything inpre_hook and send responses in post_hook.
app.py
Creating the Agent
agent.py
pre_hook runs before invoking the agent. It extracts metadata from the webhook, builds a prompt from the incoming message, persists the inbound event, and sets values in span.input for the agent to use during inference.
agent.py
post_hook runs after obtaining the agent’s response. It sends the text via WhatsApp and persists the outbound event to JSONL.
agent.py
Optional: system prompt example
Show example system_prompt
Show example system_prompt
Optional: Timbal KB persistence and history
If you prefer using Timbal Knowledge Bases instead of JSONL, you can import and query records with the platform helpers. These are async functions; adapt their usage to your environment accordingly.Media Handling Notes
- Images: The webhook includes an image
id. Use the Graph API to fetch the media URL or content using yourWHATSAPP_ACCESS_TOKEN. Provide the URL or aFileobject to the agent if needed. - Audio: The webhook includes an audio
id. You can fetch and transcribe audio, then pass the transcript as the prompt. - Documents: You receive basic metadata (e.g., filename). Decide whether to fetch and analyze content or treat as a reference.
pre_hook minimal: extract the message type, create a concise prompt, and persist the event.
Complete implementation reference
For a full, end-to-end reference (webhook app, helpers, and utilities), see the official WhatsApp examples in the Timbal repository:Possible Improvements
Delay response to batch context (debounce)
Delay response to batch context (debounce)
Each WhatsApp webhook creates a separate agent instance. Persist every inbound message immediately (JSONL or KB), then wait a short debounce window. After that window, if storage shows a newer message for the same user, bail this run so the most recent instance answers with full context. No in-memory buffer is required.
- Why it helps: avoids replying to partial context when the user is still typing or sending media.
- Trade-offs: adds small latency; choose a short window (e.g., 800–1500 ms).
- Example approach (JSONL):
Mark inbound message as read
Mark inbound message as read
Use the WhatsApp Cloud API to mark messages as read. This improves UX and clears unread indicators for the user.Call
mark_as_read(message_id) right after parsing the webhook.Progress updates (typing indicator and ack)
Progress updates (typing indicator and ack)
You can mark the message as read and briefly show a typing indicator while the agent thinks or uses tools. Optionally send a short acknowledgement, then follow up with the final answer.
- Call this right after parsing the webhook and before long operations.
- Keep interim notifications minimal to avoid noise.
Persist and reuse media in the KB
Persist and reuse media in the KB
Persist metadata for images, audio, videos, and documents so the agent can reuse them as context later (e.g., to re-attach an image or analyze it again).Suggested fields to store: Later, query recent media by
id, user_phone, direction, message_type, media_id, media_url (or object store key), mime_type, caption, timestamp.user_phone or conversation_id and inject URLs or file handles into the agent context as needed.Running
Troubleshooting
Webhook verification fails
Webhook verification fails
- Verify token: Ensure the value in Meta matches
VERIFY_TOKENin your app - Public URL: Your callback must be publicly reachable (use ngrok)
- HTTPS: Required in production
Messages not sent
Messages not sent
- Tokens: Confirm
WHATSAPP_ACCESS_TOKENandWHATSAPP_PHONE_NUMBER_IDare set - Phone ID: Ensure your app uses the correct phone number ID
- Permissions: Check token permissions in Access Token Debugger
No context/history
No context/history
- Check
ORG_IDandKB_IDif using Timbal KB - If using JSONL, verify the JSONL file path and write permissions