Skip to main content
Connect your AI agent to WhatsApp with a single command. Choose between the official Cloud API (production) or Web mode (scan a QR code, no tokens needed).
The user messages on WhatsApp; the bot forwards the chat to the agent and replies in the thread.

Quick Start

No tokens, no developer account — just scan a QR code.
1

Install

2

Start

A QR code appears in your terminal. Open WhatsApp → Linked Devices → scan it.
3

Chat

Open your own contact (message yourself) and send a message. The bot replies.
Experimental — Web mode uses a reverse-engineered protocol. Your number may be banned by WhatsApp. Use Cloud API for production.
Multiple agents on one bot? Route each inbound business number to a different agent with the Agent Registry — one bot, N agents, dispatched by phone number.

How It Works

Cloud API vs Web Mode


Inbound Media → Vision

Photos and documents sent by users are downloaded via the WhatsApp Graph API, validated, and forwarded to your agent’s vision capability — no placeholder text, no extra code.
1

Vision agent — works out of the box

Any vision-capable model receives photos automatically. No configuration needed.
Send a photo to your WhatsApp business number. The agent sees the image and replies.
2

Limit or disable inbound media

Control media size or disable it entirely with max_inbound_media_bytes.

How the security pipeline works

What if my agent has no vision capability? The adapter checks whether agent.chat() accepts attachments. If it doesn’t, the attachment is silently skipped and only the caption text is forwarded. Your existing text-only agents keep working with zero changes.

Configuration


Interactive Messages

WhatsApp bots render MessagePresentation natively — approval buttons, quick replies, and select menus become tappable Cloud API interactive messages, with no code change to existing agents.

How WhatsApp adapts

See Bot Presentations for the portable model shared across Telegram, Slack, Discord, and WhatsApp.

Message Filtering

By default, the bot responds only to self-chat — when you message your own number. This prevents it from replying to every conversation. Identity canonicalization runs first, so every later check — self-chat, outgoing guard, and allowlist — sees one stable phone-form identity regardless of whether the message arrived as a <lid>@lid or <phone>@s.whatsapp.net JID. See Identity: LID vs phone JID.

Four Layers of Protection

Stale Message Guard

Messages older than when the bot connected are dropped. Prevents replaying old conversations on reconnect.

Self-Chat Check

Only messages where sender = chat JID pass.

Outgoing Guard

Your messages sent to other people’s chats are always blocked — even if they’re in the allowlist.

Allowlists

Optionally allow specific phone numbers or groups.

Identity: LID vs phone JID

In Web mode, WhatsApp may address the same person with two interchangeable JIDs — the privacy LID (<lid>@lid) and the phone JID (<phone>@s.whatsapp.net) — and the web bridge can surface either form for the same person across messages. The adapter reconciles both to the phone form before any allowlist, session, memory, or pairing key is derived. It learns the mapping from whatsmeow’s SenderAlt alternate-JID field, so:
  • Allowlists match either form. A phone-number entry authorises the same person whether they arrive as <lid>@lid or <phone>@s.whatsapp.net.
  • One session and memory bucket. LID-form and phone-form turns from the same person resolve to a single canonical id — no split history.
  • Stable pairing. Pairing state carries across both forms, so an already-paired user is never asked to re-pair.
  • Self-chat stays self-chat. Same-session self-chat detection compares the canonicalized chat form, so an LID-addressed self-chat is never mistaken for an outgoing message and dropped.
No configuration is required. An unknown address is returned unchanged (fail-open) — behaviour is never worse than passing the raw JID through.
This uses the reusable IdentityCanonicalizerProtocol extension point. To plug canonicalization into another platform with multiple address forms, see Identity Canonicalization.

Expand Who Can Message the Bot

Only responds when you message your own number.

Filtering Matrix

Phone numbers are normalized automatically — +1-234-567-890 and 1234567890 match the same number.

Python SDK Filtering

YAML Config


Built-in Commands

Register custom commands:

CLI Options


Architecture

Cloud-mode webhook verification: inbound Meta webhooks are HMAC-verified via the shared helper. Set WHATSAPP_APP_SECRET (see Messaging Bots). Details: Webhook Verification.

Key Components


Long Agent Turns

A long agent turn on WhatsApp — deep research, big refactor, a slow model — stays BUSY for as long as it is making any progress, and is never restarted mid-stream. The gateway watches each channel’s health and only restarts a channel when it is genuinely wedged. Progress comes from inbound transport activity (someone messaged the bot) and in-run progress (the agent emitted a streamed token, called a tool, or fired an emitter event). As long as either signal advanced within stuck_after (default 900s), the channel stays BUSY and will not be killed. Only when no signal arrives for stuck_after seconds does the channel escalate to STUCK (recoverable, will be restarted).
The same mechanism applies to every channel adapter, not just WhatsApp. For the full evaluator behaviour, configuration knobs (stuck_after, busy_after), and the HealthResult.last_run_progress field, see Channel Supervision.

Troubleshooting

Fixed in latest version. The stale-message guard drops any message older than when the bot connected. If you still see this, update to the latest version:
Fixed in latest version. The default filter now checks that both the sender AND chat JID match (true self-chat), not just IsFromMe. Update your installation.
These are normal and harmless. They come from the WhatsApp protocol layer (whatsmeow) when old session keys can’t decrypt certain messages. The bot automatically suppresses most of these. They don’t affect functionality.
This is an upstream protocol error from the Signal encryption layer. It means a message had expired keys. This is not a bug in PraisonAI — it’s a normal part of the WhatsApp protocol. The message is simply skipped.
This appears when Ctrl+C is pressed. It’s harmless — the bot is disconnecting from WhatsApp servers. The latest version suppresses this warning.
This happens when the AI agent tries to run a command in /home/user (a Linux path) on macOS. Fixed in latest version — the tool now automatically falls back to your home directory.
Fixed in latest version. The bot now properly shuts down background threads on exit. Update your installation.
  1. Use a modern terminal (iTerm2, Windows Terminal)
  2. Ensure segno is installed: pip install 'praisonai[bot-whatsapp-web]'
  3. If a saved session exists, no QR is needed. Delete to re-link:
WhatsApp Web sessions expire if your phone is offline for 14+ days. Delete and re-scan:

Best Practices

Web mode (mode="web") needs only a QR-code scan and no tokens — perfect for demos. For anything user-facing, switch to the official Cloud API (mode="cloud"), which is stable, supports webhooks, and won’t break when the linked phone goes offline.
Never hard-code the Cloud API token or phone-number ID in source. Load them from environment variables so the same bot code runs across staging and production without leaking credentials into version control.
WhatsApp accepts images, audio, and documents. Rely on the built-in inbound-media security pipeline (SSRF guard, type checks) and message filtering rather than passing raw attachments straight to the model — malicious payloads are stopped at the edge.
Agent replies that take time can look like the bot has stalled. Send a quick status message for long-running turns so users know work is in progress, keeping the WhatsApp thread responsive.

Standalone scheduled delivery (no gateway)

You do not need a running WhatsApp Bot process to deliver a scheduled brief to WhatsApp. From OS cron / CI / a scale-to-zero deployment, praisonai schedule tick will POST directly to the WhatsApp Cloud API using the same env the live bot reads (WHATSAPP_ACCESS_TOKEN, WHATSAPP_PHONE_NUMBER_ID, and either an explicit deliver: whatsapp:<recipient> target or WHATSAPP_HOME_CHANNEL). Sends are retried up to 4 times with exponential backoff on transient failures. See Out-of-process delivery.

Inbound Media

Full reference for inbound media: security pipeline, SSRF guard, and patterns

Messaging Bots

All supported platforms: Telegram, Discord, Slack, WhatsApp

WhatsApp MCP

Send WhatsApp messages from agents using MCP tools

Bot Commands

Custom command registration and handling

Approval Protocol

Human-in-the-loop tool approval for bots