WhatsApp Agent
Audience: Sales · Management · QA · Support · Engineering · Where in app: Settings → AI Agents → WhatsApp Agent (per-agent tabs: Agent, Rules, Connect Number) · Plan availability: Per-company admin gate whatsapp_agents_allowed (a count) — see Plan & limits
The WhatsApp Agent lets you connect a WhatsApp number and have an AI answer your customers' WhatsApp messages automatically — the same brain as your web Chat Agent, but on WhatsApp. A company can run multiple WhatsApp agents, each with its own name, system prompt, reply rules, and connected WhatsApp number. Each agent is a slot in company.whatsapp_agents, identified by an agent_key, and flips to active once a number is connected.
What it does
- Answers inbound WhatsApp messages with an AI agent that mirrors the web chat brain (knowledge base, product catalog, order lookup, and the company's single connected calendar are wired server-side — see How it works).
- Supports many agents per company, each with its own prompt, rules, and bound WhatsApp number.
- Runs a rules engine so you control when and how it replies (let AI respond, stay silent, send a fixed reply, or hand off to a human) based on message content, timing, contact history, and AI signals (intent, sentiment, confidence, KB hit, spam).
- Connects a number through Dualhook using a manual two-step onboarding (webhook details + Meta Cloud API credentials).
- Enriches the connected number's identity (business display name + profile picture) from the Meta business profile, shown on the Connect tab and the agent card.
How it works
The flow spans the frontend config, the backend agent CRUD, and the message runtime in ms-communication.
- Create an agent. From the agent list (
AgentList.vue) you create an agent with just a name; everything else is editable afterwards. ThisPOST /whatsapp-agentsadds a slot tocompany.whatsapp_agentswith a generatedagent_key. - Configure behavior (Agent tab →
Behavior.vue): set the agent name and an optional system prompt. There is no per-agent tool picker — the knowledge base and product catalog auto-enable on integration, order lookup is always offered, and the active calendar is derived server-side. Saving advances to the Rules tab. - Set rules (Rules tab →
Rules.vue): build ordered rules that run top-to-bottom; the first match wins, and if none match the AI answers normally. Stored under the agent'smeta.rules. - Connect a number (Connect tab →
Connect.vue), a manual two-step onboarding via Dualhook:- Step 1 — webhook details:
POST /whatsapp-agents/:agent_key/webhook-setupmints (idempotently) a Webhook URL + Verify Token to paste into Dualhook's "Webhook Override" form for the number. - Step 2 — Meta credentials:
POST /whatsapp-agents/:agent_key/credentialssaves the Phone Number ID + Access Token (and optional WhatsApp Business Account ID) so the agent can send. This activates the agent (status: active).
- Step 1 — webhook details:
- Runtime. Inbound messages arrive on the Meta webhook → ms-communication's
WhatsAppRuleEngineevaluates the agent's rules, then either lets the AI respond, stays silent, sends a canned reply, or hands off. The backendWhatsappAgentControllersanitizes rule JSON against the same signal/operator/action whitelist the runtime understands, so malformed rules can never persist. (verify the exact ms-communication inbound webhook handler + send path.)
Status values
The agent (and its connected number) report a status, surfaced as a coloured badge:
| Status | Meaning |
|---|---|
draft | Created, no number connected yet. |
connecting | Onboarding in progress. |
active | Number connected and answering. |
disconnected | Number connection lost/removed. |
Configuration & options
Agent tab (Behavior.vue)
| Field | Stored as | Notes |
|---|---|---|
| Agent name | name | Required. |
| System instructions | system_prompt | Optional. Tells the agent who it is and how to behave. Blank → falls back to the default sales-assistant prompt. |
Rules tab (Rules.vue → agent meta.rules)
Ordered list; first match wins; no match → AI answers normally. Each rule has a name, an enabled toggle, a match mode (all/any), one or more conditions, and an action. Quick-start templates are provided (outside-hours auto-reply, pricing → send link, unhappy → human, spam → ignore, opt-out → stop replying).
Condition signals & operators (must mirror ms-communication's WhatsAppRuleEngine and the backend sanitizer):
| Signal | Operators | Value |
|---|---|---|
| Message text | contains, not_contains, equals, starts_with, matches_regex | text |
| Working hours | is_within, is_outside | — |
| Day of week | is, is_not, in, not_in | weekday(s) |
| Contact | is_new, is_returning | — |
| Message count | eq (=), gt (>), lt (<) | number |
| Intent (AI) | in, not_in | from intent set + custom intents |
| Sentiment (AI) | is, is_not | positive / neutral / negative |
| Confidence (AI) | gte (≥), lte (≤) | 0.0–1.0 |
| Knowledge base hit (AI) | is_true, is_false | — |
| Spam / abuse (AI) | is_true, is_false | — |
Base intents: greeting, pricing, product_inquiry, support, booking, order_status, complaint, human_request, goodbye, other (plus any meta.custom_intents). AI signals add "a quick classification step per message" (flagged in the UI).
Actions:
| Action | action.type | Notes |
|---|---|---|
| Let AI respond | respond | Default. |
| Stay silent (record only) | silent | No reply sent. |
| Send a fixed reply | canned | Requires a message body. |
| Hand off to a human | handoff | Optional message before handing off; blank stays silent. |
On save, conditions missing a signal/operator are filtered out, and only canned/handoff keep a message.
Connect tab (Connect.vue)
| Field | Sent as | Notes |
|---|---|---|
| Phone Number ID | phone_number_id | Required. From the Dualhook dashboard. |
| Access Token | meta_access_token | Required. Meta Cloud API access token (password field; cleared after submit). |
| WhatsApp Business Account ID | waba_id | Optional. |
The connected card shows the Meta verified name, display number, and profile picture (from agent.connection, enriched server-side via WhatsAppProfileHelper). "Update credentials" re-opens the credential form.
For QA/Support: the Agent and Rules tabs track unsaved edits and prompt before navigation; Connect uses its own mutations (no dirty-prompt). Toasts confirm each save ("Agent settings updated", "Rules saved", "WhatsApp number connected").
Behaviors & edge cases
- Multi-agent, shared cap. The list query returns
{ agents, count, allowed }.count/allowedare company-wide (members only receive their own agents but still see the shared cap). The "Create agent" tile disappears when the cap is reached or the package allows zero. - Member scoping. Members can manage only the agents they created (
created_by); owners/agency/admins manage all. Legacy agents withoutcreated_byare owner-only. - First-match rule ordering. Rules evaluate top-to-bottom; the order in the list is significant.
- Webhook setup is idempotent. Generating webhook details reuses the existing channel/token, so re-running step 1 is safe.
- Delete is destructive. Deleting an agent removes its config and disconnects its number; it cannot be undone.
- Provider note. Connection is via Dualhook onto Meta's WhatsApp Cloud API (manual "developer plan" onboarding — no automated Platform API embedded signup in this path, though a
/connectroute for embedded signup exists). (verify which onboarding path is live in production.)
Plan & limits
- Gating flag: the WhatsApp card and create flow are gated on
company.whatsapp_agents_allowed(a count, admin-controlled per company).Agents.vueshows the card when(whatsapp_agents_allowed ?? 0) > 0. When the count is 0, the list shows "Your package doesn't include WhatsApp agents"; when the count is used up, "Your company has used all N WhatsApp agent(s)". - Cap is shared across all users in the company.
- AI credits: AI replies and per-message AI classification (intent/sentiment/confidence/KB/spam used by rules) consume AI credits — see AI Credits. (verify per-message classification credit accounting.)
- Sales/Management framing: WhatsApp Agent extends the always-on AI brain to WhatsApp with fine-grained control over when it speaks vs. defers to a human.
Technical implementation
- Frontend:
frontend/src/views/settings/ai/agents/WhatsAppAgent/—index.vue(per-agent tabs),AgentList.vue(list/create/delete + cap),Behavior.vue(name/prompt),Rules.vue(rules engine UI + templates),Connect.vue(Dualhook onboarding). Card:WhatsAppAgentCard.vue. Repository:frontend/src/repositories/admin/whatsapp-agents.js. Composable:frontend/src/composables/useWhatsappAgent.js. - Backend:
backend/app/controllers/WhatsappAgentController.js(CRUD + connect/webhook-setup/credentials, rule-JSON sanitizer),backend/app/routes/whatsappAgentRoutes.js,backend/app/helpers/WhatsAppProfileHelper.js(Meta profile enrichment). Config persists incompany.whatsapp_agents[](each agent:agent_key,name,system_prompt,meta.rules,connection,status,created_by). - Runtime: message handling and rule evaluation live in ms-communication (
WhatsAppRuleEngine) — see ms-communication. AI generation/classification is served by ms-ai. Nox surfaces config/state but does not connect numbers — see Nox assistant.
Related
- Chat Agent (the web-chat brain WhatsApp mirrors)
- Knowledge Base
- AI Credits
- ms-communication service
- ms-ai service