Connect WhatsApp to Fabric Agents — scan a QR code with your phone, then drive sessions by messaging yourself or routing a contact via /pair.
WhatsApp uses an unofficial Web API (Baileys). You pair your account by scanning a QR code — same flow as WhatsApp Web — and then drive sessions by messaging yourself ("self-chat"). That avoids the need for a separate bot number.
Unofficial Web API
Baileys emulates a WhatsApp Web client. It works well, but WhatsApp can throttle or suspend numbers they detect as automated. Use a personal account you don't mind risking, and don't spam. Meta's terms of service only formally cover the Business Cloud API, which isn't what this is.
Prerequisites
- A phone with WhatsApp installed and signed in.
- Node.js installed on the machine running the server (for packaged desktop builds this is handled automatically; for headless server builds, see the env vars below).
1. Connect WhatsApp in Fabric Agents
- Open Fabric Agents → Settings → Messaging.
- Click Connect on the WhatsApp row.
- A dialog opens showing a QR code.
- On your phone, open WhatsApp → Settings → Linked Devices → Link a Device.
- Point your phone at the QR code.
- The dialog switches to "Connected as <your name>". Done.
Your Baileys session state is saved at ~/.fabric-agent/workspaces/{workspace-id}/messaging/whatsapp-auth/. Subsequent launches reconnect automatically — you only scan once.
First connection sometimes shows your number instead of your name
Immediately after scanning, the linked-device record hasn't fully propagated yet. If the status card shows just your phone number, click Reconfigure → Reconnect once and it'll resolve to your name. This also populates the self-chat identifier that WhatsApp uses for privacy- preserving chats — self-chat messages won't be recognised until it's set.
2. Test with self-chat
The easiest way to test — and the default driving surface — is messaging yourself. On WhatsApp Desktop or your phone:
-
Open your own chat (the "You" chat, or type your own name in the search box).
-
Send:
/help -
A 🤖-prefixed reply should arrive listing the available commands. That confirms the full round-trip: your phone → WhatsApp servers → Baileys worker → session manager → renderer → back out.
-
Create a session:
/new quick testA new session appears in your workspace sidebar. Every subsequent message you send to yourself drives that agent; replies come back in the same chat.
The 🤖 prefix on bot replies lets you visually distinguish them from your own messages in the self-chat. You can turn self-chat off in Settings → Messaging → ⋯ on the WhatsApp row → Self-chat if you only want other contacts driving sessions.
3. Drive a session from another contact
To let someone else drive a specific session:
-
In the Fabric Agents app, open the session you want to share → session menu (⋯) → Pair over WhatsApp. A 6-digit code appears and is valid for ~5 minutes.
-
On the other person's phone, they message your WhatsApp number with:
/pair 123456 -
Their chat is now bound to that session. Their subsequent messages drive the agent; replies come back to them.
Codes are single-use and rate-limited per sender (a handful of attempts per minute) to prevent brute force.
4. Attachments
WhatsApp supports sending files to the agent. The bot accepts:
| Type | Max size | Delivered to the agent as |
|---|---|---|
| Photo | 20 MB | Image attachment on the next turn |
| Document | 20 MB | File attachment (raw bytes + filename) |
| Voice note | 20 MB | Audio file |
| Video | 20 MB | Video file |
| Audio | 20 MB | Audio file |
Caption text sent with a media message becomes the user's text for that turn.
5. Response modes
Default is progress — one evolving message per run. WhatsApp does support message editing (recent versions of the protocol), so streaming mode does live-edit a single message as tokens arrive.
Change the mode per-binding from Settings → Messaging → ⋯ on the binding row → Response mode.
See Messaging overview — response modes.
Headless server
When Fabric Agents runs as a headless server (packages/server/src/index.ts), the WhatsApp worker is spawned as a Node subprocess. Bun can't run Baileys' crypto dependencies directly, so a real Node binary must be reachable.
| Env var | Default | Notes |
|---|---|---|
FABRIC_MESSAGING_WA_WORKER | $FABRIC_BUNDLED_ASSETS_ROOT/packages/messaging-whatsapp-worker/dist/worker.cjs | Absolute path to the built worker bundle. The worker is CJS + Node target. |
FABRIC_MESSAGING_NODE_BIN | node | Command used to spawn the worker. Override if Node isn't on PATH under a non-default name. |
The Docker image (ghcr.io/fabric-pro/fabric-agents-server) installs Node 20 alongside Bun and ships the worker bundle at the default path, so out-of-box it just works.
Reconnect or disconnect
- Reconnect — Settings → Messaging → ⋯ on WhatsApp row → Reconnect. Reloads the persisted session, usually without a re-scan.
- Reconfigure — same menu → Reconfigure. Forces a fresh QR scan (e.g. if you switched phones).
- Disconnect — same menu → Disconnect. Logs out on the WhatsApp side and clears local auth state. Next connect is a fresh QR scan.
Troubleshooting
Nothing happens when I send a message — check the messaging log at ~/.fabric-agent/logs/messaging-gateway.log. If you see upsert skip: own_outbound, WhatsApp is routing your self-chat messages under your LID (a newer privacy-preserving identity) and Baileys hasn't learnt your self-LID yet. Reconfigure → Reconnect populates it.
Worker exited with code 1 / "Cannot find module worker.cjs" — the WhatsApp worker bundle wasn't built. For dev builds run bun run build:wa-worker once; for packaged apps this is part of bun run electron:build.
QR scan gets stuck / disconnects with statusCode=515 — WhatsApp sometimes forces a reconnect right after the first pair. The worker retries automatically within a second or two; the status card transitions from "QR received" to "connected" when it settles.
/help doesn't respond — the bot might be connected but the self-chat check is failing. Check ~/.fabric-agent/logs/messaging-gateway.log for lines like upsert skip: own_outbound remoteJid=...@lid selfLid=?. If selfLid is ?, reconnect once — the self-LID populates on the second session.
I want to force a fresh pair — delete ~/.fabric-agent/workspaces/{workspace-id}/messaging/whatsapp-auth/ and reconnect.
Related
- Messaging overview — response modes, bindings, workspace scoping
- Command reference — every slash command
- Telegram setup — alternative platform, official Bot API