whalibmob 3.3.1 → 4.4.0
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/README.md +639 -183
- package/cli.js +918 -400
- package/lib/Client.js +731 -0
- package/lib/messages/MessageSender.js +65 -7
- package/lib/proto/MessageProto.js +36 -9
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -1,297 +1,753 @@
|
|
|
1
|
-
|
|
1
|
+
<div align='center'>whalibmob is a pure JavaScript Node.js library for interacting with the WhatsApp Mobile API.</div>
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
##
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
> [!CAUTION]
|
|
6
|
+
> Use a dedicated phone number with this library. Connecting with a number that is already active on a real device will cause WhatsApp to log that device out.
|
|
6
7
|
|
|
7
|
-
>
|
|
8
|
+
> [!IMPORTANT]
|
|
9
|
+
> This project is not affiliated, associated, authorized, endorsed by, or in any way officially connected with WhatsApp or any of its subsidiaries or affiliates. "WhatsApp" and related names are registered trademarks of their respective owners. Use at your own discretion.
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
- whalibmob does not require a browser, Selenium, or any other external runtime — it communicates directly with WhatsApp using a **TCP socket** and the **Noise Protocol** handshake.
|
|
12
|
+
- The library operates as a real **iOS mobile device**, not as WhatsApp Web. It uses the Mobile API endpoint, which behaves differently from the Web API.
|
|
13
|
+
- Signal Protocol encryption is **fully inlined** in pure JavaScript — no native binaries, no node-gyp, runs anywhere Node.js runs.
|
|
10
14
|
|
|
11
|
-
##
|
|
15
|
+
## Install
|
|
12
16
|
|
|
13
|
-
|
|
14
|
-
|
|
17
|
+
```sh
|
|
18
|
+
npm install whalibmob
|
|
19
|
+
```
|
|
15
20
|
|
|
16
|
-
|
|
21
|
+
Install the CLI globally:
|
|
17
22
|
|
|
18
|
-
|
|
23
|
+
```sh
|
|
24
|
+
npm install -g whalibmob
|
|
25
|
+
```
|
|
19
26
|
|
|
20
|
-
|
|
27
|
+
## Index
|
|
28
|
+
|
|
29
|
+
- [Connecting Account](#connecting-account)
|
|
30
|
+
- [Register a New Number](#register-a-new-number)
|
|
31
|
+
- [Connect](#connect)
|
|
32
|
+
- [Saving & Restoring Sessions](#saving--restoring-sessions)
|
|
33
|
+
- [Handling Events](#handling-events)
|
|
34
|
+
- [Example to Start](#example-to-start)
|
|
35
|
+
- [All Events](#all-events)
|
|
36
|
+
- [Sending Messages](#sending-messages)
|
|
37
|
+
- [Text Message](#text-message)
|
|
38
|
+
- [Quote Message](#quote-message)
|
|
39
|
+
- [Mention User](#mention-user)
|
|
40
|
+
- [Reaction Message](#reaction-message)
|
|
41
|
+
- [Edit Message](#edit-message)
|
|
42
|
+
- [Delete Message](#delete-message)
|
|
43
|
+
- [Forward Message](#forward-message)
|
|
44
|
+
- [Media Messages](#media-messages)
|
|
45
|
+
- [Image Message](#image-message)
|
|
46
|
+
- [Video Message](#video-message)
|
|
47
|
+
- [Audio Message](#audio-message)
|
|
48
|
+
- [Voice Note](#voice-note)
|
|
49
|
+
- [Document Message](#document-message)
|
|
50
|
+
- [Sticker Message](#sticker-message)
|
|
51
|
+
- [Status / Stories](#status--stories)
|
|
52
|
+
- [Send States in Chat](#send-states-in-chat)
|
|
53
|
+
- [Reading Messages](#reading-messages)
|
|
54
|
+
- [Update Presence](#update-presence)
|
|
55
|
+
- [Modifying Chats](#modifying-chats)
|
|
56
|
+
- [Archive / Unarchive a Chat](#archive--unarchive-a-chat)
|
|
57
|
+
- [Mute / Unmute a Chat](#mute--unmute-a-chat)
|
|
58
|
+
- [Mark a Chat Read / Unread](#mark-a-chat-read--unread)
|
|
59
|
+
- [Pin / Unpin a Chat](#pin--unpin-a-chat)
|
|
60
|
+
- [Star / Unstar a Message](#star--unstar-a-message)
|
|
61
|
+
- [Disappearing Messages](#disappearing-messages)
|
|
62
|
+
- [User Queries](#user-queries)
|
|
63
|
+
- [Check If a Number Has WhatsApp](#check-if-a-number-has-whatsapp)
|
|
64
|
+
- [Fetch Profile About](#fetch-profile-about)
|
|
65
|
+
- [Fetch Profile Picture](#fetch-profile-picture)
|
|
66
|
+
- [Subscribe to Presence](#subscribe-to-presence)
|
|
67
|
+
- [Change Profile](#change-profile)
|
|
68
|
+
- [Change Display Name](#change-display-name)
|
|
69
|
+
- [Change About Text](#change-about-text)
|
|
70
|
+
- [Change Profile Picture](#change-profile-picture)
|
|
71
|
+
- [Privacy](#privacy)
|
|
72
|
+
- [Block / Unblock User](#block--unblock-user)
|
|
73
|
+
- [Get Block List](#get-block-list)
|
|
74
|
+
- [Update Privacy Settings](#update-privacy-settings)
|
|
75
|
+
- [Update Default Disappearing Mode](#update-default-disappearing-mode)
|
|
76
|
+
- [Groups](#groups)
|
|
77
|
+
- [Create a Group](#create-a-group)
|
|
78
|
+
- [Add / Remove or Demote / Promote](#add--remove-or-demote--promote)
|
|
79
|
+
- [Change Subject](#change-subject)
|
|
80
|
+
- [Change Description](#change-description)
|
|
81
|
+
- [Change Settings](#change-settings)
|
|
82
|
+
- [Leave a Group](#leave-a-group)
|
|
83
|
+
- [Get Invite Code](#get-invite-code)
|
|
84
|
+
- [Revoke Invite Code](#revoke-invite-code)
|
|
85
|
+
- [Join Using Invitation Code](#join-using-invitation-code)
|
|
86
|
+
- [Query Metadata](#query-metadata)
|
|
87
|
+
- [Get Request Join List](#get-request-join-list)
|
|
88
|
+
- [Approve / Reject Request Join](#approve--reject-request-join)
|
|
89
|
+
- [Toggle Ephemeral in Group](#toggle-ephemeral-in-group)
|
|
90
|
+
- [CLI Reference](#cli-reference)
|
|
91
|
+
- [Interactive Shell](#interactive-shell)
|
|
92
|
+
- [WhatsApp IDs](#whatsapp-ids)
|
|
93
|
+
- [Transport](#transport)
|
|
94
|
+
- [Media Encryption](#media-encryption)
|
|
95
|
+
|
|
96
|
+
## Connecting Account
|
|
97
|
+
|
|
98
|
+
### Register a New Number
|
|
99
|
+
|
|
100
|
+
Registration is a one-time process. You need a phone number that can receive an SMS or voice call.
|
|
101
|
+
|
|
102
|
+
**Step 1 — request a verification code**
|
|
21
103
|
|
|
22
|
-
```
|
|
23
|
-
|
|
104
|
+
```js
|
|
105
|
+
const {
|
|
106
|
+
createNewStore, saveStore, requestSmsCode
|
|
107
|
+
} = require('whalibmob')
|
|
108
|
+
const path = require('path')
|
|
109
|
+
const fs = require('fs')
|
|
110
|
+
|
|
111
|
+
const phone = '919634847671' // country code + number, no '+'
|
|
112
|
+
const sessDir = path.join(process.env.HOME, '.waSession')
|
|
113
|
+
const sessFile = path.join(sessDir, phone + '.json')
|
|
114
|
+
|
|
115
|
+
fs.mkdirSync(sessDir, { recursive: true })
|
|
116
|
+
|
|
117
|
+
const store = createNewStore(phone)
|
|
118
|
+
saveStore(store, sessFile)
|
|
119
|
+
|
|
120
|
+
await requestSmsCode(store, 'sms') // 'sms' | 'voice' | 'wa_old'
|
|
24
121
|
```
|
|
25
122
|
|
|
26
|
-
|
|
123
|
+
**Step 2 — verify the code**
|
|
27
124
|
|
|
28
|
-
```
|
|
29
|
-
|
|
125
|
+
```js
|
|
126
|
+
const { loadStore, saveStore, verifyCode } = require('whalibmob')
|
|
127
|
+
|
|
128
|
+
const store = loadStore(sessFile)
|
|
129
|
+
const result = await verifyCode(store, '123456')
|
|
130
|
+
|
|
131
|
+
if (result.status === 'ok') {
|
|
132
|
+
saveStore(result.store, sessFile)
|
|
133
|
+
console.log('registered')
|
|
134
|
+
}
|
|
30
135
|
```
|
|
31
136
|
|
|
32
|
-
|
|
137
|
+
### Connect
|
|
33
138
|
|
|
34
|
-
|
|
139
|
+
```js
|
|
140
|
+
const { WhalibmobClient } = require('whalibmob')
|
|
141
|
+
const path = require('path')
|
|
142
|
+
|
|
143
|
+
const client = new WhalibmobClient({
|
|
144
|
+
sessionDir: path.join(process.env.HOME, '.waSession')
|
|
145
|
+
})
|
|
35
146
|
|
|
36
|
-
|
|
147
|
+
client.on('connected', () => {
|
|
148
|
+
console.log('connected')
|
|
149
|
+
})
|
|
37
150
|
|
|
38
|
-
|
|
39
|
-
wa registration --check 919634847671
|
|
151
|
+
await client.init('919634847671')
|
|
40
152
|
```
|
|
41
153
|
|
|
42
|
-
|
|
154
|
+
## Saving & Restoring Sessions
|
|
155
|
+
|
|
156
|
+
Sessions are automatically persisted to disk as JSON files under the `sessionDir` you provide. The file is named `<phone>.json`. On the next `client.init()` call the session is restored and no re-registration is needed.
|
|
157
|
+
|
|
158
|
+
```js
|
|
159
|
+
const client = new WhalibmobClient({
|
|
160
|
+
sessionDir: path.join(process.env.HOME, '.waSession')
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
// no need to register again — just connect
|
|
164
|
+
await client.init('919634847671')
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
> [!NOTE]
|
|
168
|
+
> Each phone number uses its own session file. The library handles Signal Protocol key persistence automatically.
|
|
169
|
+
|
|
170
|
+
## Handling Events
|
|
171
|
+
|
|
172
|
+
whalibmob uses the EventEmitter syntax for events.
|
|
173
|
+
|
|
174
|
+
### Example to Start
|
|
175
|
+
|
|
176
|
+
```js
|
|
177
|
+
const { WhalibmobClient } = require('whalibmob')
|
|
178
|
+
const path = require('path')
|
|
179
|
+
|
|
180
|
+
async function connect() {
|
|
181
|
+
const client = new WhalibmobClient({
|
|
182
|
+
sessionDir: path.join(process.env.HOME, '.waSession')
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
client.on('connected', async () => {
|
|
186
|
+
console.log('connected')
|
|
187
|
+
await client.sendText('919634847671@s.whatsapp.net', 'Hello!')
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
client.on('disconnected', () => {
|
|
191
|
+
console.log('disconnected — reconnecting...')
|
|
192
|
+
setTimeout(() => connect(), 3000)
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
client.on('message', msg => {
|
|
196
|
+
console.log('message from', msg.from, msg.text)
|
|
197
|
+
})
|
|
43
198
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
199
|
+
client.on('auth_failure', ({ reason }) => {
|
|
200
|
+
console.error('session revoked:', reason)
|
|
201
|
+
// re-register the number
|
|
202
|
+
})
|
|
47
203
|
|
|
48
|
-
|
|
49
|
-
|
|
204
|
+
await client.init('919634847671')
|
|
205
|
+
}
|
|
50
206
|
|
|
51
|
-
|
|
52
|
-
wa registration --request-code 919634847671 --method wa_old
|
|
207
|
+
connect()
|
|
53
208
|
```
|
|
54
209
|
|
|
55
|
-
###
|
|
210
|
+
### All Events
|
|
211
|
+
|
|
212
|
+
| Event | Payload | Description |
|
|
213
|
+
|---|---|---|
|
|
214
|
+
| `connected` | — | Session authenticated and ready |
|
|
215
|
+
| `disconnected` | — | Connection closed |
|
|
216
|
+
| `reconnecting` | `{ attempt, delay }` | Lost connection, will retry |
|
|
217
|
+
| `reconnected` | — | Connection restored |
|
|
218
|
+
| `auth_failure` | `{ reason }` | Session revoked or banned |
|
|
219
|
+
| `message` | message object | Incoming message received |
|
|
220
|
+
| `receipt` | `{ type, id, from }` | Delivery / read / played receipt |
|
|
221
|
+
| `presence` | `{ from, available, lastSeen }` | Contact came online or went offline |
|
|
222
|
+
| `notification` | node object | Group or contact update notification |
|
|
223
|
+
| `call` | `{ from }` | Incoming call event |
|
|
224
|
+
| `error` | Error | Unhandled transport error |
|
|
225
|
+
|
|
226
|
+
The message object contains:
|
|
56
227
|
|
|
57
|
-
```
|
|
58
|
-
|
|
228
|
+
```js
|
|
229
|
+
{
|
|
230
|
+
id: string, // message ID
|
|
231
|
+
from: string, // sender JID
|
|
232
|
+
participant: string, // group sender JID (groups only)
|
|
233
|
+
ts: number, // Unix timestamp
|
|
234
|
+
text: string, // text body (plain text messages)
|
|
235
|
+
plaintext: Buffer, // decrypted raw payload
|
|
236
|
+
mediaType: string // 'image' | 'video' | 'audio' | 'document' | 'sticker'
|
|
237
|
+
}
|
|
59
238
|
```
|
|
60
239
|
|
|
61
|
-
|
|
240
|
+
## Sending Messages
|
|
241
|
+
|
|
242
|
+
### Text Message
|
|
62
243
|
|
|
63
|
-
```
|
|
64
|
-
|
|
244
|
+
```js
|
|
245
|
+
await client.sendText('919634847671@s.whatsapp.net', 'Hello!')
|
|
65
246
|
```
|
|
66
247
|
|
|
67
|
-
|
|
248
|
+
### Quote Message
|
|
68
249
|
|
|
250
|
+
```js
|
|
251
|
+
// pass { quotedMsgId, quotedParticipant } in options
|
|
252
|
+
await client.sendText(
|
|
253
|
+
'919634847671@s.whatsapp.net',
|
|
254
|
+
'This is a reply',
|
|
255
|
+
{ quotedMsgId: 'ABCDEF123456', quotedParticipant: '919634847671@s.whatsapp.net' }
|
|
256
|
+
)
|
|
69
257
|
```
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
258
|
+
|
|
259
|
+
### Mention User
|
|
260
|
+
|
|
261
|
+
```js
|
|
262
|
+
await client.sendText(
|
|
263
|
+
'120363000000000000@g.us',
|
|
264
|
+
'@919634847671 hello!',
|
|
265
|
+
{ mentions: ['919634847671@s.whatsapp.net'] }
|
|
266
|
+
)
|
|
74
267
|
```
|
|
75
268
|
|
|
76
|
-
|
|
269
|
+
### Reaction Message
|
|
77
270
|
|
|
78
|
-
|
|
271
|
+
```js
|
|
272
|
+
// react to a message
|
|
273
|
+
await client.sendReaction('919634847671@s.whatsapp.net', 'MSGID123', '👍')
|
|
79
274
|
|
|
80
|
-
|
|
275
|
+
// remove a reaction — pass empty string
|
|
276
|
+
await client.sendReaction('919634847671@s.whatsapp.net', 'MSGID123', '')
|
|
277
|
+
```
|
|
81
278
|
|
|
82
|
-
|
|
83
|
-
|---|---|
|
|
84
|
-
| `wa registration --check <phone>` | Check if a number has WhatsApp |
|
|
85
|
-
| `wa registration --request-code <phone>` | Request SMS verification code |
|
|
86
|
-
| `wa registration --request-code <phone> --method voice` | Request code via voice call |
|
|
87
|
-
| `wa registration --request-code <phone> --method wa_old` | Request code via old WA account |
|
|
88
|
-
| `wa registration --register <phone> --code <code>` | Complete registration |
|
|
279
|
+
### Edit Message
|
|
89
280
|
|
|
90
|
-
|
|
281
|
+
> [!NOTE]
|
|
282
|
+
> Editing is only possible within 15 minutes of the original send.
|
|
91
283
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
284
|
+
```js
|
|
285
|
+
await client.editMessage(
|
|
286
|
+
'MSGID123', // original message ID
|
|
287
|
+
'919634847671@s.whatsapp.net',
|
|
288
|
+
'Corrected text here'
|
|
289
|
+
)
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Delete Message
|
|
293
|
+
|
|
294
|
+
```js
|
|
295
|
+
// delete for yourself only
|
|
296
|
+
await client.deleteMessage('MSGID123', '919634847671@s.whatsapp.net', true, false)
|
|
297
|
+
|
|
298
|
+
// delete for everyone (revoke)
|
|
299
|
+
await client.deleteMessage('MSGID123', '919634847671@s.whatsapp.net', true, true)
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Forward Message
|
|
303
|
+
|
|
304
|
+
```js
|
|
305
|
+
await client.forwardMessage('919634847671@s.whatsapp.net', 'text to forward')
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
## Media Messages
|
|
309
|
+
|
|
310
|
+
### Image Message
|
|
311
|
+
|
|
312
|
+
```js
|
|
313
|
+
// from file path
|
|
314
|
+
await client.sendImage('919634847671@s.whatsapp.net', './photo.jpg', { caption: 'Look at this' })
|
|
315
|
+
|
|
316
|
+
// from Buffer
|
|
317
|
+
await client.sendImage('919634847671@s.whatsapp.net', buffer, {
|
|
318
|
+
caption: 'Photo',
|
|
319
|
+
mimetype: 'image/jpeg'
|
|
320
|
+
})
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Video Message
|
|
324
|
+
|
|
325
|
+
```js
|
|
326
|
+
await client.sendVideo('919634847671@s.whatsapp.net', './clip.mp4', { caption: 'Watch this' })
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Audio Message
|
|
330
|
+
|
|
331
|
+
```js
|
|
332
|
+
await client.sendAudio('919634847671@s.whatsapp.net', './song.mp3')
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Voice Note
|
|
336
|
+
|
|
337
|
+
```js
|
|
338
|
+
// ptt: true renders the audio as a push-to-talk voice note with waveform
|
|
339
|
+
await client.sendAudio('919634847671@s.whatsapp.net', './voice.ogg', { ptt: true })
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Document Message
|
|
343
|
+
|
|
344
|
+
```js
|
|
345
|
+
await client.sendDocument('919634847671@s.whatsapp.net', './report.pdf', {
|
|
346
|
+
fileName: 'Q1 Report.pdf'
|
|
347
|
+
})
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Sticker Message
|
|
96
351
|
|
|
97
|
-
|
|
352
|
+
```js
|
|
353
|
+
await client.sendSticker('919634847671@s.whatsapp.net', './sticker.webp')
|
|
354
|
+
```
|
|
98
355
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
356
|
+
## Status / Stories
|
|
357
|
+
|
|
358
|
+
```js
|
|
359
|
+
// post a text Status to status@broadcast
|
|
360
|
+
await client.sendStatus('Good morning!')
|
|
361
|
+
```
|
|
102
362
|
|
|
103
|
-
|
|
104
|
-
wa send <phone> --to <jid> --image ./photo.jpg --caption "Check this out"
|
|
363
|
+
## Send States in Chat
|
|
105
364
|
|
|
106
|
-
|
|
107
|
-
wa send <phone> --to <jid> --video ./clip.mp4 --caption "Watch this"
|
|
365
|
+
### Reading Messages
|
|
108
366
|
|
|
109
|
-
|
|
110
|
-
|
|
367
|
+
```js
|
|
368
|
+
// mark the last message in a chat as read
|
|
369
|
+
client.markChatRead('919634847671@s.whatsapp.net')
|
|
370
|
+
```
|
|
111
371
|
|
|
112
|
-
|
|
113
|
-
wa send <phone> --to <jid> --audio ./song.mp3
|
|
372
|
+
### Update Presence
|
|
114
373
|
|
|
115
|
-
|
|
116
|
-
|
|
374
|
+
```js
|
|
375
|
+
// set yourself as online / offline globally
|
|
376
|
+
client.setOnline(true)
|
|
377
|
+
client.setOnline(false)
|
|
378
|
+
|
|
379
|
+
// show typing or recording in a specific chat
|
|
380
|
+
client.setChatPresence('919634847671@s.whatsapp.net', 'composing') // typing
|
|
381
|
+
client.setChatPresence('919634847671@s.whatsapp.net', 'recording') // recording audio
|
|
382
|
+
client.setChatPresence('919634847671@s.whatsapp.net', 'paused') // stopped
|
|
383
|
+
```
|
|
117
384
|
|
|
118
|
-
|
|
119
|
-
wa send <phone> --to <jid> --sticker ./sticker.webp
|
|
385
|
+
## Modifying Chats
|
|
120
386
|
|
|
121
|
-
|
|
122
|
-
wa send <phone> --to <jid> --reaction 👍 --msg-id 3EB0ABCDEF123456
|
|
387
|
+
### Archive / Unarchive a Chat
|
|
123
388
|
|
|
124
|
-
|
|
125
|
-
|
|
389
|
+
```js
|
|
390
|
+
client.archiveChat('919634847671@s.whatsapp.net')
|
|
391
|
+
client.unarchiveChat('919634847671@s.whatsapp.net')
|
|
126
392
|
```
|
|
127
393
|
|
|
128
|
-
###
|
|
394
|
+
### Mute / Unmute a Chat
|
|
395
|
+
|
|
396
|
+
```js
|
|
397
|
+
client.muteChat('919634847671@s.whatsapp.net', 8 * 60 * 60 * 1000) // mute for 8 hours (ms)
|
|
398
|
+
client.muteChat('919634847671@s.whatsapp.net', 0) // mute indefinitely
|
|
399
|
+
client.unmuteChat('919634847671@s.whatsapp.net')
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### Mark a Chat Read / Unread
|
|
403
|
+
|
|
404
|
+
```js
|
|
405
|
+
client.markChatRead('919634847671@s.whatsapp.net')
|
|
406
|
+
client.markChatUnread('919634847671@s.whatsapp.net')
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### Pin / Unpin a Chat
|
|
410
|
+
|
|
411
|
+
```js
|
|
412
|
+
client.pinChat('919634847671@s.whatsapp.net')
|
|
413
|
+
client.unpinChat('919634847671@s.whatsapp.net')
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### Star / Unstar a Message
|
|
417
|
+
|
|
418
|
+
```js
|
|
419
|
+
client.starMessage('MSGID123', '919634847671@s.whatsapp.net')
|
|
420
|
+
client.unstarMessage('MSGID123', '919634847671@s.whatsapp.net')
|
|
421
|
+
```
|
|
129
422
|
|
|
130
|
-
|
|
423
|
+
### Disappearing Messages
|
|
424
|
+
|
|
425
|
+
| Duration | Seconds |
|
|
131
426
|
|---|---|
|
|
132
|
-
|
|
|
133
|
-
|
|
|
427
|
+
| Off | 0 |
|
|
428
|
+
| 24 hours | 86 400 |
|
|
429
|
+
| 7 days | 604 800 |
|
|
430
|
+
| 90 days | 7 776 000 |
|
|
134
431
|
|
|
135
|
-
|
|
432
|
+
```js
|
|
433
|
+
// set disappearing timer for a specific chat (DM or group)
|
|
434
|
+
await client.changeEphemeralTimer('919634847671@s.whatsapp.net', 86400)
|
|
435
|
+
await client.changeEphemeralTimer('120363000000000000@g.us', 604800)
|
|
136
436
|
|
|
137
|
-
|
|
437
|
+
// remove disappearing messages
|
|
438
|
+
await client.changeEphemeralTimer('919634847671@s.whatsapp.net', 0)
|
|
439
|
+
```
|
|
138
440
|
|
|
139
|
-
|
|
140
|
-
|---|---|---|
|
|
141
|
-
| `--session <dir>` | `~/.waSession` | Directory where session files are stored |
|
|
142
|
-
| `--method` | `sms` | Verification method: `sms`, `voice`, or `wa_old` |
|
|
143
|
-
| `--code` | — | Verification code received via SMS/voice |
|
|
144
|
-
| `--to` | — | Recipient JID |
|
|
145
|
-
| `--text` | — | Text message body |
|
|
146
|
-
| `--caption` | — | Caption for image or video |
|
|
147
|
-
| `--reaction` | — | Emoji to react with |
|
|
148
|
-
| `--msg-id` | — | Message ID to react to (required with `--reaction`) |
|
|
441
|
+
## User Queries
|
|
149
442
|
|
|
150
|
-
|
|
443
|
+
### Check If a Number Has WhatsApp
|
|
151
444
|
|
|
152
|
-
|
|
445
|
+
```js
|
|
446
|
+
const { checkNumberStatus } = require('whalibmob')
|
|
153
447
|
|
|
154
|
-
|
|
155
|
-
|
|
448
|
+
const result = await checkNumberStatus('919634847671')
|
|
449
|
+
// result.status: 'registered' | 'registered_blocked' | 'not_registered' | 'cooldown' | 'unknown'
|
|
450
|
+
console.log(result.status)
|
|
451
|
+
```
|
|
156
452
|
|
|
157
|
-
|
|
453
|
+
Check multiple numbers at once while connected:
|
|
158
454
|
|
|
159
|
-
```
|
|
160
|
-
|
|
455
|
+
```js
|
|
456
|
+
const results = await client.hasWhatsapp(['919634847671', '12345678901'])
|
|
457
|
+
// returns array of JIDs that have WhatsApp
|
|
161
458
|
```
|
|
162
459
|
|
|
163
|
-
|
|
460
|
+
### Fetch Profile About
|
|
164
461
|
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
|
|
462
|
+
```js
|
|
463
|
+
const about = await client.queryAbout('919634847671@s.whatsapp.net')
|
|
464
|
+
console.log(about)
|
|
168
465
|
```
|
|
169
466
|
|
|
170
|
-
|
|
467
|
+
### Fetch Profile Picture
|
|
468
|
+
|
|
469
|
+
```js
|
|
470
|
+
const url = await client.queryPicture('919634847671@s.whatsapp.net')
|
|
471
|
+
// also works for groups
|
|
472
|
+
const groupUrl = await client.queryPicture('120363000000000000@g.us')
|
|
473
|
+
```
|
|
171
474
|
|
|
172
|
-
|
|
475
|
+
### Subscribe to Presence
|
|
173
476
|
|
|
174
477
|
```js
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
} = require('whalibmob');
|
|
478
|
+
// triggers 'presence' events when the contact comes online or goes offline
|
|
479
|
+
client.subscribeToPresence('919634847671@s.whatsapp.net')
|
|
480
|
+
|
|
481
|
+
client.on('presence', ({ from, available, lastSeen }) => {
|
|
482
|
+
console.log(from, available ? 'online' : 'offline')
|
|
483
|
+
})
|
|
182
484
|
```
|
|
183
485
|
|
|
184
|
-
|
|
486
|
+
## Change Profile
|
|
487
|
+
|
|
488
|
+
### Change Display Name
|
|
185
489
|
|
|
186
490
|
```js
|
|
187
|
-
|
|
188
|
-
|
|
491
|
+
client.changeName('My Bot')
|
|
492
|
+
```
|
|
189
493
|
|
|
190
|
-
|
|
191
|
-
const store = loadStore('919634847671', sessionDir);
|
|
494
|
+
### Change About Text
|
|
192
495
|
|
|
193
|
-
|
|
496
|
+
```js
|
|
497
|
+
await client.changeAbout('Available 24/7')
|
|
498
|
+
```
|
|
194
499
|
|
|
195
|
-
|
|
196
|
-
await client.sendText('911234567890@s.whatsapp.net', 'Hello from whalibmob!');
|
|
197
|
-
});
|
|
500
|
+
### Change Profile Picture
|
|
198
501
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
502
|
+
```js
|
|
503
|
+
// groups are also supported
|
|
504
|
+
await client.changeProfilePicture('./avatar.jpg')
|
|
505
|
+
await client.changeGroupPicture('120363000000000000@g.us', './group.jpg')
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
## Privacy
|
|
202
509
|
|
|
203
|
-
|
|
204
|
-
console.log('Disconnected:', reason);
|
|
205
|
-
});
|
|
510
|
+
### Block / Unblock User
|
|
206
511
|
|
|
207
|
-
|
|
512
|
+
```js
|
|
513
|
+
await client.blockContact('919634847671@s.whatsapp.net')
|
|
514
|
+
await client.unblockContact('919634847671@s.whatsapp.net')
|
|
208
515
|
```
|
|
209
516
|
|
|
210
|
-
###
|
|
517
|
+
### Get Block List
|
|
211
518
|
|
|
212
519
|
```js
|
|
213
|
-
await client.
|
|
214
|
-
|
|
215
|
-
await client.sendPtt ('911234567890@s.whatsapp.net', './voice.ogg');
|
|
216
|
-
await client.sendAudio ('911234567890@s.whatsapp.net', './song.mp3');
|
|
217
|
-
await client.sendDocument('911234567890@s.whatsapp.net', './report.pdf');
|
|
218
|
-
await client.sendSticker ('911234567890@s.whatsapp.net', './sticker.webp');
|
|
520
|
+
const list = await client.queryBlockList()
|
|
521
|
+
console.log(list) // [ '919634847671@s.whatsapp.net', ... ]
|
|
219
522
|
```
|
|
220
523
|
|
|
221
|
-
###
|
|
524
|
+
### Update Privacy Settings
|
|
222
525
|
|
|
223
526
|
```js
|
|
224
|
-
|
|
527
|
+
// type: 'last_seen' | 'profile_picture' | 'status' | 'online' | 'read_receipts' | 'groups_add'
|
|
528
|
+
// value: 'all' | 'contacts' | 'contact_blacklist' | 'none' | 'match_last_seen'
|
|
529
|
+
|
|
530
|
+
await client.changePrivacySetting('last_seen', 'contacts')
|
|
531
|
+
await client.changePrivacySetting('profile_picture', 'contacts')
|
|
532
|
+
await client.changePrivacySetting('status', 'contacts')
|
|
533
|
+
await client.changePrivacySetting('online', 'match_last_seen')
|
|
534
|
+
await client.changePrivacySetting('read_receipts', 'none')
|
|
535
|
+
await client.changePrivacySetting('groups_add', 'contacts')
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
### Update Default Disappearing Mode
|
|
225
539
|
|
|
226
|
-
|
|
227
|
-
//
|
|
228
|
-
|
|
540
|
+
```js
|
|
541
|
+
// sets the default ephemeral timer for all new chats
|
|
542
|
+
await client.changeNewChatsEphemeralTimer(86400) // 1 day
|
|
543
|
+
await client.changeNewChatsEphemeralTimer(0) // off
|
|
229
544
|
```
|
|
230
545
|
|
|
231
|
-
|
|
546
|
+
## Groups
|
|
232
547
|
|
|
233
|
-
|
|
234
|
-
|---|---|---|
|
|
235
|
-
| `connected` | — | Session authenticated and ready |
|
|
236
|
-
| `disconnected` | `{ reason }` | Connection closed |
|
|
237
|
-
| `auth_failure` | `{ reason }` | Auth failed (banned or session revoked) |
|
|
238
|
-
| `message` | message object | Incoming message received |
|
|
239
|
-
| `message.sent` | message object | Outgoing message confirmed by server |
|
|
240
|
-
| `error` | Error | Unhandled transport error |
|
|
548
|
+
### Create a Group
|
|
241
549
|
|
|
242
|
-
|
|
550
|
+
```js
|
|
551
|
+
const group = await client.createGroup('My Group', [
|
|
552
|
+
'919634847671@s.whatsapp.net',
|
|
553
|
+
'12345678901@s.whatsapp.net'
|
|
554
|
+
])
|
|
555
|
+
console.log('created group', group)
|
|
556
|
+
```
|
|
243
557
|
|
|
244
|
-
|
|
558
|
+
### Add / Remove or Demote / Promote
|
|
245
559
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
- **SenderKey group encryption** — efficient group messaging with chain-key advance and SKDM distribution
|
|
249
|
-
- **Multi-device fanout** — messages delivered to every linked device of each recipient
|
|
250
|
-
- **All media types** — images, video, audio, voice notes, documents, stickers
|
|
251
|
-
- **Media encryption** — AES-256-CBC + HKDF-SHA256; files uploaded to WhatsApp CDN
|
|
252
|
-
- **Emoji reactions** — react to any message by its ID
|
|
253
|
-
- **Automatic reconnection** — exponential backoff (1 s → 2 → 4 → 8 → 15 → 30 s cap)
|
|
254
|
-
- **Pre-key replenishment** — automatic upload when supply drops below threshold
|
|
255
|
-
- **Persistent sessions** — JSON files on disk; no re-registration after restart
|
|
256
|
-
- **Zero native dependencies** — pure JavaScript; works on Linux, macOS, Windows, Termux (Android)
|
|
560
|
+
```js
|
|
561
|
+
const groupJid = '120363000000000000@g.us'
|
|
257
562
|
|
|
258
|
-
|
|
563
|
+
await client.addGroupParticipants(groupJid, ['919634847671@s.whatsapp.net'])
|
|
564
|
+
await client.removeGroupParticipants(groupJid, ['919634847671@s.whatsapp.net'])
|
|
565
|
+
await client.promoteGroupParticipants(groupJid, ['919634847671@s.whatsapp.net'])
|
|
566
|
+
await client.demoteGroupParticipants(groupJid, ['919634847671@s.whatsapp.net'])
|
|
567
|
+
```
|
|
259
568
|
|
|
260
|
-
|
|
569
|
+
### Change Subject
|
|
261
570
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
| 2 | 2 s |
|
|
266
|
-
| 3 | 4 s |
|
|
267
|
-
| 4 | 8 s |
|
|
268
|
-
| 5 | 15 s |
|
|
269
|
-
| 6+ | 30 s |
|
|
571
|
+
```js
|
|
572
|
+
await client.changeGroupSubject('120363000000000000@g.us', 'New Group Name')
|
|
573
|
+
```
|
|
270
574
|
|
|
271
|
-
|
|
575
|
+
### Change Description
|
|
272
576
|
|
|
273
|
-
|
|
577
|
+
```js
|
|
578
|
+
await client.changeGroupDescription('120363000000000000@g.us', 'This is the group description')
|
|
579
|
+
```
|
|
274
580
|
|
|
275
|
-
|
|
276
|
-
2. HKDF-SHA256 expands it into an IV, cipher key, and MAC key.
|
|
277
|
-
3. The file is encrypted with AES-256-CBC.
|
|
278
|
-
4. A 10-byte HMAC-SHA256 MAC is appended.
|
|
279
|
-
5. The ciphertext is uploaded to WhatsApp CDN.
|
|
280
|
-
6. The media key and CDN URL are embedded in the message envelope.
|
|
581
|
+
### Change Settings
|
|
281
582
|
|
|
282
|
-
|
|
583
|
+
```js
|
|
584
|
+
// setting: 'edit_group_info' | 'send_messages' | 'add_participants' | 'approve_participants'
|
|
585
|
+
// policy: 'admins' | 'all'
|
|
586
|
+
|
|
587
|
+
await client.changeGroupSetting('120363000000000000@g.us', 'send_messages', 'admins')
|
|
588
|
+
await client.changeGroupSetting('120363000000000000@g.us', 'edit_group_info', 'admins')
|
|
589
|
+
await client.changeGroupSetting('120363000000000000@g.us', 'add_participants', 'all')
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
### Leave a Group
|
|
593
|
+
|
|
594
|
+
```js
|
|
595
|
+
await client.leaveGroup('120363000000000000@g.us')
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
### Get Invite Code
|
|
599
|
+
|
|
600
|
+
```js
|
|
601
|
+
const link = await client.queryGroupInviteLink('120363000000000000@g.us')
|
|
602
|
+
// e.g. 'https://chat.whatsapp.com/AbCdEfGhIjK'
|
|
603
|
+
console.log(link)
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
### Revoke Invite Code
|
|
607
|
+
|
|
608
|
+
```js
|
|
609
|
+
await client.revokeGroupInvite('120363000000000000@g.us')
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
### Join Using Invitation Code
|
|
613
|
+
|
|
614
|
+
> [!NOTE]
|
|
615
|
+
> Pass only the code portion — do not include `https://chat.whatsapp.com/`
|
|
616
|
+
|
|
617
|
+
```js
|
|
618
|
+
const jid = await client.acceptGroupInvite('AbCdEfGhIjK')
|
|
619
|
+
console.log('joined', jid)
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
### Query Metadata
|
|
623
|
+
|
|
624
|
+
```js
|
|
625
|
+
const meta = await client.getGroupMetadata('120363000000000000@g.us')
|
|
626
|
+
console.log(meta)
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
### Get Request Join List
|
|
630
|
+
|
|
631
|
+
```js
|
|
632
|
+
const pending = await client.queryGroupPendingParticipants('120363000000000000@g.us')
|
|
633
|
+
console.log(pending)
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
### Approve / Reject Request Join
|
|
637
|
+
|
|
638
|
+
```js
|
|
639
|
+
await client.approveGroupParticipants('120363000000000000@g.us', [
|
|
640
|
+
'919634847671@s.whatsapp.net'
|
|
641
|
+
])
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
### Toggle Ephemeral in Group
|
|
645
|
+
|
|
646
|
+
```js
|
|
647
|
+
await client.changeEphemeralTimer('120363000000000000@g.us', 86400) // 1 day
|
|
648
|
+
await client.changeEphemeralTimer('120363000000000000@g.us', 0) // off
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
## CLI Reference
|
|
652
|
+
|
|
653
|
+
```sh
|
|
654
|
+
wa open interactive shell
|
|
655
|
+
wa connect <phone> connect and open interactive shell
|
|
656
|
+
wa listen <phone> connect and listen for messages (stay-alive)
|
|
657
|
+
wa registration --request-code <phone> request SMS verification code
|
|
658
|
+
wa registration --request-code <phone> --method voice
|
|
659
|
+
wa registration --request-code <phone> --method wa_old
|
|
660
|
+
wa registration --register <phone> --code <code>
|
|
661
|
+
wa registration --check <phone>
|
|
662
|
+
wa version
|
|
663
|
+
|
|
664
|
+
options:
|
|
665
|
+
--session <dir> session directory (default: ~/.waSession)
|
|
666
|
+
--method sms | voice | wa_old (default: sms)
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
> [!TIP]
|
|
670
|
+
> **The CLI shell never exits on its own.** It stays open after every command until you type `/quit` or press Ctrl+C. This includes after requesting or confirming a registration code.
|
|
671
|
+
|
|
672
|
+
### Interactive Shell
|
|
673
|
+
|
|
674
|
+
After connecting with `wa connect <phone>` a persistent prompt appears. All features of the library are available as commands:
|
|
675
|
+
|
|
676
|
+
```
|
|
677
|
+
/send <jid> <text> send text message
|
|
678
|
+
/image <jid> <file> [caption] send image
|
|
679
|
+
/video <jid> <file> [caption] send video
|
|
680
|
+
/audio <jid> <file> send audio file
|
|
681
|
+
/ptt <jid> <file> send voice note
|
|
682
|
+
/doc <jid> <file> [name] send document
|
|
683
|
+
/sticker <jid> <file> send sticker
|
|
684
|
+
/react <jid> <msgId> <emoji> react to message
|
|
685
|
+
/edit <jid> <msgId> <text> edit a sent message
|
|
686
|
+
/delete <jid> <msgId> [all] delete (add 'all' for everyone)
|
|
687
|
+
/status <text> post Status/Story
|
|
688
|
+
/online /offline set presence
|
|
689
|
+
/typing /recording /stop <jid> typing indicators
|
|
690
|
+
/read /unread <jid> mark chat
|
|
691
|
+
/mute /unmute <jid> mute / unmute
|
|
692
|
+
/pin /unpin <jid> pin / unpin
|
|
693
|
+
/archive /unarchive <jid> archive / unarchive
|
|
694
|
+
/star /unstar <jid> <msgId> star / unstar message
|
|
695
|
+
/ephemeral <jid> <seconds> set disappearing timer
|
|
696
|
+
/block /unblock <jid> block / unblock
|
|
697
|
+
/blocklist show blocked contacts
|
|
698
|
+
/group create|leave|add|remove
|
|
699
|
+
|promote|demote|subject|desc
|
|
700
|
+
|invite|revoke|join|meta|settings ...
|
|
701
|
+
/reg check|code|confirm ... registration commands
|
|
702
|
+
/privacy <type> <value> change privacy setting
|
|
703
|
+
/name <text> /about <text> update profile
|
|
704
|
+
/session show session info
|
|
705
|
+
/reconnect force reconnect
|
|
706
|
+
/help show all commands
|
|
707
|
+
/quit disconnect and exit
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
## WhatsApp IDs
|
|
711
|
+
|
|
712
|
+
- Individual contacts: `[countrycode][number]@s.whatsapp.net`
|
|
713
|
+
- Example: `919634847671@s.whatsapp.net`
|
|
714
|
+
- Groups: `[groupid]@g.us`
|
|
715
|
+
- Example: `120363000000000000@g.us`
|
|
716
|
+
- Status broadcast: `status@broadcast`
|
|
717
|
+
- Broadcast lists: `[timestamp]@broadcast`
|
|
718
|
+
|
|
719
|
+
> [!NOTE]
|
|
720
|
+
> Phone numbers must include the country code without the `+` prefix.
|
|
283
721
|
|
|
284
722
|
## Transport
|
|
285
723
|
|
|
286
|
-
|
|
724
|
+
whalibmob uses **Noise_XX_25519_AESGCM_SHA256** over TCP to `g.whatsapp.net:443`:
|
|
287
725
|
|
|
288
726
|
1. Client sends `ClientHello` with an ephemeral X25519 public key.
|
|
289
727
|
2. Server replies `ServerHello` (ephemeral + encrypted static + payload).
|
|
290
728
|
3. Three DH steps (EE, SE, SS) derive the final session keys.
|
|
291
729
|
4. Client sends `ClientFinish` (encrypted static + encrypted payload).
|
|
292
|
-
5.
|
|
730
|
+
5. The library waits for a `<success>` stanza before emitting `connected`, or `<failure>` for `auth_failure`.
|
|
731
|
+
|
|
732
|
+
Automatic reconnection uses exponential backoff:
|
|
733
|
+
|
|
734
|
+
| Attempt | Delay |
|
|
735
|
+
|---|---|
|
|
736
|
+
| 1 | 1 s |
|
|
737
|
+
| 2 | 2 s |
|
|
738
|
+
| 3 | 4 s |
|
|
739
|
+
| 4 | 8 s |
|
|
740
|
+
| 5 | 15 s |
|
|
741
|
+
| 6+ | 30 s |
|
|
742
|
+
|
|
743
|
+
## Media Encryption
|
|
293
744
|
|
|
294
|
-
|
|
745
|
+
1. A random 32-byte **media key** is generated.
|
|
746
|
+
2. HKDF-SHA256 expands it into IV, cipher key, and MAC key.
|
|
747
|
+
3. The file is encrypted with **AES-256-CBC**.
|
|
748
|
+
4. A 10-byte **HMAC-SHA256** MAC is appended.
|
|
749
|
+
5. The ciphertext is uploaded to the WhatsApp CDN.
|
|
750
|
+
6. The media key and CDN URL are embedded in the encrypted message envelope sent to the recipient.
|
|
295
751
|
|
|
296
752
|
## License
|
|
297
753
|
|