@elizaos/plugin-whatsapp 2.0.0-beta.1 → 2.0.3-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shaw Walters and elizaOS Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,50 +1,28 @@
1
- # plugin-whatsapp
1
+ # @elizaos/plugin-whatsapp
2
2
 
3
- WhatsApp plugin for ElizaOS. Supports both WhatsApp Cloud API and Baileys (QR authentication), enabling agents to send and receive messages, media, reactions, and interactive content via WhatsApp.
3
+ WhatsApp plugin for elizaOS. Connects Eliza agents to WhatsApp via the **WhatsApp Cloud API** (Meta Business) or **Baileys** (personal account / QR-code auth).
4
4
 
5
- ## Features
5
+ ## Capabilities
6
6
 
7
- - **Text Messages**: Send and receive text messages with URL preview
8
- - **Media Messages**: Send images, videos, audio, documents, and stickers
9
- - **Reactions**: Send and remove emoji reactions on messages
10
- - **Interactive Messages**: Send button and list messages for rich interactions
11
- - **Location Messages**: Share location data with name and address
12
- - **Template Messages**: Send pre-approved message templates
13
- - **Webhooks**: Handle incoming messages and status updates
14
- - **Baileys QR Auth**: Connect personal WhatsApp accounts with QR login + session persistence
15
- - **Message Status**: Track sent, delivered, read, and failed statuses
16
- - **Media Downloads**: Retrieve media URLs for incoming messages
7
+ - Send and receive text messages (inbound messages ingested into agent memory)
8
+ - Send emoji reactions, remove reactions
9
+ - Support for media captions (image, video, document) on inbound messages
10
+ - Interactive message content extraction (button replies, list replies)
11
+ - Location and reaction message handling
12
+ - Baileys QR-code pairing with session persistence
13
+ - Multi-account support (multiple WhatsApp numbers per agent)
14
+ - DM and group access policies (open / allowlist / pairing / disabled)
15
+ - Webhook verification and `X-Hub-Signature-256` security for Cloud API
17
16
 
18
17
  ## Installation
19
18
 
20
- ### TypeScript
21
-
22
19
  ```bash
23
20
  npm install @elizaos/plugin-whatsapp
24
21
  ```
25
- ## Configuration
26
22
 
27
- ### Environment Variables
23
+ ## Enabling the Plugin
28
24
 
29
- | Variable | Required | Description |
30
- |----------|----------|-------------|
31
- | `WHATSAPP_ACCESS_TOKEN` | Yes | WhatsApp Business API access token |
32
- | `WHATSAPP_PHONE_NUMBER_ID` | Yes | Phone number ID from WhatsApp Business API |
33
- | `WHATSAPP_WEBHOOK_VERIFY_TOKEN` | No | Token for webhook verification |
34
- | `WHATSAPP_BUSINESS_ACCOUNT_ID` | No | Business account ID |
35
- | `WHATSAPP_API_VERSION` | No | Graph API version (default: v24.0) |
36
- | `WHATSAPP_AUTH_METHOD` | No | `cloudapi` or `baileys` (auto-detected if omitted) |
37
- | `WHATSAPP_AUTH_DIR` | No | Path for Baileys multi-file auth state |
38
- | `WHATSAPP_SESSION_PATH` | No | Alternative to `WHATSAPP_AUTH_DIR` for Baileys auth state |
39
- | `WHATSAPP_PRINT_QR` | No | Print QR in terminal for Baileys auth (default: true) |
40
- | `WHATSAPP_DM_POLICY` | No | DM handling policy: `open`, `allowlist`, `pairing`, or `disabled` |
41
- | `WHATSAPP_GROUP_POLICY` | No | Group handling policy: `open`, `allowlist`, or `disabled` |
42
- | `WHATSAPP_ALLOW_FROM` | No | Comma-separated allowlist for DM senders (when DM policy is `allowlist`) |
43
- | `WHATSAPP_GROUP_ALLOW_FROM` | No | Comma-separated allowlist for group senders (when group policy is `allowlist`) |
44
-
45
- ### TypeScript Configuration
46
-
47
- The plugin self-registers `WhatsAppConnectorService` on the elizaOS runtime and reads its config from runtime settings / environment variables — no manual construction is required. Just register the default export on your character/agent:
25
+ Add the plugin to your character file:
48
26
 
49
27
  ```typescript
50
28
  import whatsappPlugin from "@elizaos/plugin-whatsapp";
@@ -55,228 +33,143 @@ export const character = {
55
33
  };
56
34
  ```
57
35
 
58
- The service picks up `WHATSAPP_ACCESS_TOKEN` + `WHATSAPP_PHONE_NUMBER_ID` (Cloud API) or `WHATSAPP_AUTH_DIR` (Baileys / QR) automatically. See the env-var table above.
36
+ The plugin also auto-enables when a `connectors.whatsapp` block is present in agent config.
59
37
 
60
- To access the service at runtime (e.g. to send a message from your own code):
38
+ ## Configuration
61
39
 
62
- ```typescript
63
- import type { WhatsAppConnectorService } from "@elizaos/plugin-whatsapp";
40
+ ### Cloud API (Meta Business)
64
41
 
65
- const service = runtime.getService<WhatsAppConnectorService>("whatsapp");
66
- await service?.sendMessage({ type: "text", to: "+14155552671", content: "hello" });
67
- ```
42
+ | Variable | Required | Description |
43
+ |----------|----------|-------------|
44
+ | `WHATSAPP_ACCESS_TOKEN` | Yes | Long-lived access token from Meta Business Manager |
45
+ | `WHATSAPP_PHONE_NUMBER_ID` | Yes | Phone number ID registered in Meta Business |
46
+ | `WHATSAPP_APP_SECRET` | Yes (webhooks) | App Secret for `X-Hub-Signature-256` verification on incoming webhook POSTs |
47
+ | `WHATSAPP_WEBHOOK_VERIFY_TOKEN` | No | Token for Meta's one-time GET webhook subscribe handshake |
48
+ | `WHATSAPP_BUSINESS_ACCOUNT_ID` | No | WABA ID (informational only) |
49
+ | `WHATSAPP_API_VERSION` | No | Graph API version string (default: `v24.0`) |
68
50
 
69
- ## Usage
51
+ ### Baileys (personal account / QR auth)
70
52
 
71
- ### Sending Messages
53
+ | Variable | Required | Description |
54
+ |----------|----------|-------------|
55
+ | `WHATSAPP_AUTH_DIR` | Yes (Baileys) | Directory to persist multi-file Baileys auth state |
56
+ | `WHATSAPP_SESSION_PATH` | No | Alternative name for `WHATSAPP_AUTH_DIR` |
57
+ | `WHATSAPP_AUTH_METHOD` | No | Force transport: `cloudapi` or `baileys` (overrides auto-detection) |
72
58
 
73
- The TypeScript snippets below use two variables:
59
+ **Transport detection:** `WHATSAPP_AUTH_METHOD` wins when set. Otherwise: `WHATSAPP_AUTH_DIR` present → Baileys; `WHATSAPP_ACCESS_TOKEN` + `WHATSAPP_PHONE_NUMBER_ID` present → Cloud API. Baileys takes precedence when both are set.
74
60
 
75
- - `service` — the registered `WhatsAppConnectorService`, obtained via `runtime.getService<WhatsAppConnectorService>("whatsapp")`. This is the recommended path: it routes through the same auth + policy stack the agent uses for incoming messages.
76
- - `client` — the underlying low-level client (`IWhatsAppClient`), used only for advanced media APIs not exposed on the service. Construct one with the exported `ClientFactory.create({ accessToken, phoneNumberId })` (Cloud API) or `ClientFactory.create({ authDir })` (Baileys) — the concrete `WhatsAppClient` / `BaileysClient` classes are internal.
61
+ ### Access Control
77
62
 
78
- #### Text Message
63
+ | Variable | Default | Description |
64
+ |----------|---------|-------------|
65
+ | `WHATSAPP_DM_POLICY` | `pairing` | `open`, `allowlist`, `pairing`, or `disabled` |
66
+ | `WHATSAPP_GROUP_POLICY` | `allowlist` | `open`, `allowlist`, or `disabled` |
67
+ | `WHATSAPP_ALLOW_FROM` | — | Comma-separated E.164 numbers allowed in DMs (when policy is `allowlist`) |
68
+ | `WHATSAPP_GROUP_ALLOW_FROM` | — | Comma-separated E.164 numbers allowed as group senders |
79
69
 
80
- **TypeScript**:
81
- ```typescript
82
- const service = runtime.getService<WhatsAppConnectorService>("whatsapp");
83
- await service?.sendMessage({ type: "text", to: "1234567890", content: "Hello, World!" });
84
- ```
70
+ ### Agent Behavior
85
71
 
86
- **Python**:
72
+ | Variable | Default | Description |
73
+ |----------|---------|-------------|
74
+ | `WHATSAPP_AUTO_REPLY` | `false` | When `true`, inbound messages trigger automatic agent replies. Off by default — messages are stored in memory only |
87
75
 
88
- **Rust**:
76
+ ## Usage
89
77
 
90
- #### Image Message
78
+ ### Accessing the Service
91
79
 
92
- **TypeScript**:
93
80
  ```typescript
94
- await client.sendImage('1234567890', 'https://example.com/image.jpg', 'Caption');
95
- ```
96
-
97
- **Python**:
81
+ import type { WhatsAppConnectorService } from "@elizaos/plugin-whatsapp";
98
82
 
99
- **Rust**:
83
+ const service = runtime.getService<WhatsAppConnectorService>("whatsapp");
84
+ ```
100
85
 
101
- #### Interactive Button Message
86
+ ### Sending a Text Message
102
87
 
103
- **TypeScript**:
104
88
  ```typescript
105
- await client.sendButtonMessage(
106
- '1234567890',
107
- 'Choose an option:',
108
- [
109
- { id: 'opt1', title: 'Option 1' },
110
- { id: 'opt2', title: 'Option 2' },
111
- { id: 'opt3', title: 'Option 3' },
112
- ],
113
- 'Header Text',
114
- 'Footer Text'
115
- );
89
+ await service?.sendMessage({
90
+ type: "text",
91
+ to: "+14155552671", // E.164 format for Cloud API; JID or E.164 for Baileys
92
+ content: "Hello from elizaOS!",
93
+ });
116
94
  ```
117
95
 
118
- **Python**:
119
-
120
- **Rust**:
96
+ ### Sending a Message with Reply Threading
121
97
 
122
- ### Sending Reactions
123
-
124
- **TypeScript**:
125
98
  ```typescript
126
- await client.sendReaction({
127
- to: '1234567890',
128
- messageId: 'wamid.xxx',
129
- emoji: '👍',
99
+ await service?.sendMessage({
100
+ type: "text",
101
+ to: "+14155552671",
102
+ content: "This is a reply",
103
+ replyToMessageId: "wamid.xxxxx",
130
104
  });
131
-
132
- // Remove reaction
133
- await client.removeReaction('1234567890', 'wamid.xxx');
134
105
  ```
135
106
 
136
- **Python**:
137
-
138
- **Rust**:
107
+ ### Creating a Low-Level Client
139
108
 
140
- ### Handling Webhooks
109
+ Use `ClientFactory` when you need direct access to Cloud API media endpoints:
141
110
 
142
- **TypeScript**:
143
111
  ```typescript
144
- import express from 'express';
112
+ import { ClientFactory } from "@elizaos/plugin-whatsapp";
145
113
 
146
- const app = express();
114
+ // Cloud API
115
+ const client = ClientFactory.create({ accessToken: "...", phoneNumberId: "..." });
147
116
 
148
- const service = runtime.getService<WhatsAppConnectorService>("whatsapp");
117
+ // Baileys
118
+ const client = ClientFactory.create({ authMethod: "baileys", authDir: "./wa-auth" });
119
+ ```
149
120
 
150
- // Verification endpoint
151
- app.get('/webhook', (req, res) => {
152
- const mode = String(req.query['hub.mode'] ?? '');
153
- const token = String(req.query['hub.verify_token'] ?? '');
154
- const challenge = String(req.query['hub.challenge'] ?? '');
155
-
156
- const reply = service?.verifyWebhook(mode, token, challenge);
157
- if (reply) {
158
- res.status(200).send(reply);
159
- } else {
160
- res.sendStatus(403);
161
- }
162
- });
121
+ ### Webhook Setup (Cloud API)
163
122
 
164
- // Message handling endpoint
165
- app.post('/webhook', express.json(), async (req, res) => {
166
- await service?.handleWebhook(req.body);
167
- res.sendStatus(200);
168
- });
169
- ```
123
+ The plugin automatically registers these HTTP routes on the agent:
170
124
 
171
- **Python**:
125
+ - `GET /api/whatsapp/webhook` — Meta subscription verification (public)
126
+ - `POST /api/whatsapp/webhook` — Incoming message delivery (validates `X-Hub-Signature-256`)
172
127
 
173
- **Rust**:
128
+ Point your Meta App webhook URL to `https://<your-agent-host>/api/whatsapp/webhook`.
174
129
 
175
- ### Event Handling
130
+ ### QR Pairing (Baileys)
176
131
 
177
- **TypeScript** (using event emitter pattern):
178
- ```typescript
179
- // Events are emitted by the webhook handler
180
- webhookHandler.onMessage((message) => {
181
- console.log('Message received:', message);
182
- });
132
+ Start a pairing session via the agent's HTTP API:
183
133
 
184
- webhookHandler.onStatus((status) => {
185
- console.log('Status update:', status);
186
- });
134
+ ```bash
135
+ # Start pairing
136
+ curl -X POST http://localhost:31337/api/whatsapp/pair \
137
+ -H "Content-Type: application/json" \
138
+ -d '{"accountId": "default"}'
139
+
140
+ # Check status
141
+ curl http://localhost:31337/api/whatsapp/status?accountId=default
142
+
143
+ # Stop pairing
144
+ curl -X POST http://localhost:31337/api/whatsapp/pair/stop \
145
+ -H "Content-Type: application/json" \
146
+ -d '{"accountId": "default"}'
147
+
148
+ # Logout and remove auth state
149
+ curl -X POST http://localhost:31337/api/whatsapp/disconnect \
150
+ -H "Content-Type: application/json" \
151
+ -d '{"accountId": "default"}'
187
152
  ```
188
153
 
189
- **Python**:
190
-
191
- **Rust**:
192
-
193
- ## Actions
194
-
195
- WhatsApp messaging is exposed through the canonical message connector actions.
196
- Use `source: "whatsapp"` when a request needs to target WhatsApp explicitly.
197
- Media, templates, and interactive messages remain available through the service
198
- and low-level client APIs shown above; they are not advertised as separate
199
- executable action names.
200
-
201
- | Primary action | Operation | Description |
202
- |----------------|-----------|-------------|
203
- | `MESSAGE` | `send` | Send a message to a phone number, contact, user, group, or room |
204
- | `MESSAGE` | `read` | Read recent WhatsApp conversation messages |
205
- | `MESSAGE` | `search` | Search WhatsApp conversation history |
206
- | `MESSAGE` | `react` | Send or remove a reaction on a message |
207
- | `MESSAGE` | `get_user` | Resolve a WhatsApp contact or user |
208
-
209
- ## Event Types
210
-
211
- | Event | Description |
212
- |-------|-------------|
213
- | `MESSAGE_RECEIVED` | New message received |
214
- | `MESSAGE_SENT` | Message was sent |
215
- | `MESSAGE_DELIVERED` | Message was delivered |
216
- | `MESSAGE_READ` | Message was read |
217
- | `MESSAGE_FAILED` | Message delivery failed |
218
- | `REACTION_RECEIVED` | Reaction received on a message |
219
- | `REACTION_SENT` | Reaction was sent |
220
- | `INTERACTIVE_REPLY` | User replied to interactive message |
221
- | `WEBHOOK_VERIFIED` | Webhook was verified |
222
-
223
- ## Common Reactions
224
-
225
- The plugin provides constants for common reaction emojis:
226
-
227
- | Name | Emoji |
228
- |------|-------|
229
- | `THUMBS_UP` | 👍 |
230
- | `THUMBS_DOWN` | 👎 |
231
- | `HEART` | ❤️ |
232
- | `LAUGHING` | 😂 |
233
- | `SURPRISED` | 😮 |
234
- | `SAD` | 😢 |
235
- | `PRAYING` | 🙏 |
236
- | `CLAPPING` | 👏 |
237
- | `FIRE` | 🔥 |
238
- | `CELEBRATION` | 🎉 |
239
-
240
- ## API Reference
241
-
242
- ### WhatsAppClient / WhatsAppService
243
-
244
- | Method | Description |
245
- |--------|-------------|
246
- | `sendTextMessage(to, text)` | Send a text message |
247
- | `sendImage(to, url, caption?)` | Send an image |
248
- | `sendVideo(to, url, caption?)` | Send a video |
249
- | `sendAudio(to, url)` | Send audio |
250
- | `sendDocument(to, url, filename?, caption?)` | Send a document |
251
- | `sendLocation(to, lat, lng, name?, address?)` | Send a location |
252
- | `sendReaction(params)` | Send a reaction |
253
- | `removeReaction(to, messageId)` | Remove a reaction |
254
- | `sendButtonMessage(to, body, buttons, header?, footer?)` | Send button message |
255
- | `sendListMessage(to, body, buttonText, sections, header?, footer?)` | Send list message |
256
- | `markMessageAsRead(messageId)` | Mark a message as read |
257
- | `getMediaUrl(mediaId)` | Get download URL for media |
258
- | `verifyWebhook(token)` | Verify webhook token |
154
+ ## Multi-Account
259
155
 
260
- ## Troubleshooting
156
+ Configure multiple WhatsApp accounts under `character.settings.whatsapp.accounts.<id>`. Each entry accepts the same fields as the top-level config (`authDir`, `accessToken`, `phoneNumberId`, `dmPolicy`, `groupPolicy`, etc.) plus an optional `name` for display.
261
157
 
262
- ### Common Issues
158
+ ## Message Connector Protocol
263
159
 
264
- 1. **Message not delivered**: Ensure the phone number is in international format without `+` prefix (e.g., `1234567890`).
160
+ `WhatsAppConnectorService` registers with the elizaOS message connector system. Supported capabilities: `send_message`, `read_messages`, `search_messages`, `send_reaction`, `contact_resolution`, `chat_context`, `get_user`. Target kinds: `phone`, `contact`, `user`, `group`, `room`.
265
161
 
266
- 2. **Webhook not verified**: Check that your `WHATSAPP_WEBHOOK_VERIFY_TOKEN` matches the token configured in the Meta Developer Portal.
162
+ Use `source: "whatsapp"` when targeting WhatsApp from an orchestrator or workflow.
163
+
164
+ ## Troubleshooting
267
165
 
268
- 3. **Media upload fails**: Ensure media URLs are publicly accessible and the file format is supported by WhatsApp.
166
+ **Messages not delivered:** Ensure phone numbers are in E.164 format (e.g. `+14155552671`). For Cloud API, bare number strings (no `+`) also work.
269
167
 
270
- 4. **Rate limiting**: WhatsApp has rate limits on the number of messages. Implement exponential backoff for retries.
168
+ **Webhook verification fails:** Confirm `WHATSAPP_WEBHOOK_VERIFY_TOKEN` in your env matches the token configured in the Meta Developer Portal webhook settings.
271
169
 
272
- ### Error Codes
170
+ **Webhook POST rejected (401):** Set `WHATSAPP_APP_SECRET` to the App Secret shown in your Meta App dashboard.
273
171
 
274
- | Code | Description |
275
- |------|-------------|
276
- | 130429 | Rate limit reached |
277
- | 131000 | Something went wrong |
278
- | 131030 | Invalid recipient |
279
- | 131051 | Message type is not supported |
172
+ **Baileys QR not appearing:** Start a session with `POST /api/whatsapp/pair`, then poll `GET /api/whatsapp/status` (the status advances to `waiting_for_qr`). The QR itself is delivered as a `whatsapp-qr` event with a `qrDataUrl` field broadcast over the agent's WebSocket — render that data URL.
280
173
 
281
174
  ## License
282
175
 
package/auto-enable.ts CHANGED
@@ -8,7 +8,7 @@ import type { PluginAutoEnableContext } from "@elizaos/core";
8
8
 
9
9
  /** Enable when a `whatsapp` connector block is present and not explicitly disabled. */
10
10
  export function shouldEnable(ctx: PluginAutoEnableContext): boolean {
11
- const c = (ctx.config?.connectors as Record<string, unknown> | undefined)
11
+ const c = (ctx.config.connectors as Record<string, unknown> | undefined)
12
12
  ?.whatsapp;
13
13
  if (!c || typeof c !== "object") return false;
14
14
  const config = c as Record<string, unknown>;