@areumtecnologia/wasockets 1.0.3 → 1.1.1

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 CHANGED
@@ -1,2544 +1,666 @@
1
- # <div align='center'>WaSockets - Typescript/Javascript WhatsApp Web API</div>
2
-
3
- ### Important Note
4
-
5
- This library was originally a project for **CS-2362 at Ashoka University** and is in no way affiliated with or endorsed by WhatsApp. Use at your own discretion. Do not spam people with this. We discourage any stalkerware, bulk or automated messaging usage.
6
-
7
- #### Liability and License Notice
8
- Baileys and its maintainers cannot be held liable for misuse of this application, as stated in the [MIT license](https://github.com/WhiskeySockets/Baileys/blob/master/LICENSE).
9
- The maintainers of Baileys do not in any way condone the use of this application in practices that violate the Terms of Service of WhatsApp. The maintainers of this application call upon the personal responsibility of its users to use this application in a fair way, as it is intended to be used.
10
- ##
11
-
12
- ## Install
13
-
14
- Use the stable version:
15
- ```
16
- yarn add @areumtecnologia/wasockets
17
- ```
18
-
19
- Use the edge version (no guarantee of stability, but latest fixes + features)
20
- ```
21
- yarn add github:areumtecnologia/WaSockets
22
- ```
23
-
24
- Then import your code using:
25
- ```ts
26
- import makeWASocket from '@areumtecnologia/wasockets'
27
- ```
28
-
29
- # Index
30
-
31
- - [Connecting Account](#connecting-account)
32
- - [Connect with QR-CODE](#starting-socket-with-qr-code)
33
- - [Connect with Pairing Code](#starting-socket-with-pairing-code)
34
- - [Receive Full History](#receive-full-history)
35
- - [Important Notes About Socket Config](#important-notes-about-socket-config)
36
- - [Caching Group Metadata (Recommended)](#caching-group-metadata-recommended)
37
- - [Improve Retry System & Decrypt Poll Votes](#improve-retry-system--decrypt-poll-votes)
38
- - [Receive Notifications in Whatsapp App](#receive-notifications-in-whatsapp-app)
39
-
40
- - [Save Auth Info](#saving--restoring-sessions)
41
- - [Handling Events](#handling-events)
42
- - [Example to Start](#example-to-start)
43
- - [Decrypt Poll Votes](#decrypt-poll-votes)
44
- - [Decrypt Event Response](#decrypt-event-response)
45
- - [Summary of Events on First Connection](#summary-of-events-on-first-connection)
46
- - [Implementing a Data Store](#implementing-a-data-store)
47
- - [Whatsapp IDs Explain](#whatsapp-ids-explain)
48
- - [Utility Functions](#utility-functions)
49
- - [Sending Messages](#sending-messages)
50
- - [Non-Media Messages](#non-media-messages)
51
- - [Text Message](#text-message)
52
- - [Quote Message](#quote-message-works-with-all-types)
53
- - [Mention User](#mention-user-works-with-most-types)
54
- - [Forward Messages](#forward-messages)
55
- - [Location Message](#location-message)
56
- - [Live Location Message](#live-location-message)
57
- - [Contact Message](#contact-message)
58
- - [Reaction Message](#reaction-message)
59
- - [Pin Message](#pin-message)
60
- - [Keep Message](#keep-message)
61
- - [Poll Message](#poll-message)
62
- - [Poll Result Message](#poll-result-message)
63
- - [Call Message](#call-message)
64
- - [Event Message](#event-message)
65
- - [Order Message](#order-message)
66
- - [Product Message](#product-message)
67
- - [Payment Message](#payment-message)
68
- - [Payment Invite Message](#payment-invite-message)
69
- - [Admin Invite Message](#invite-admin-message)
70
- - [Group Invite Message](#group-invite-message)
71
- - [Sticker Pack Message](#sticker-pack-message)
72
- - [Share Phone Number Message](#share-phone-number-message)
73
- - [Request Phone Number Message](#request-phone-number-message)
74
- - [Buttons Reply Message](#buttons-reply-message)
75
- - [Buttons Message](#buttons-message)
76
- - [Buttons List Message](#buttons-list-message)
77
- - [Buttons Product List Message](#buttons-product-list-message)
78
- - [Buttons Cards Message](#buttons-cards-message)
79
- - [Buttons Template Message](#buttons-template-message)
80
- - [Buttons Interactive Message](#buttons-interactive-message)
81
- - [Buttons Interactive Message PIX](#buttons-interactive-message-pix)
82
- - [Buttons Interactive Message PAY](#buttons-interactive-message-PAY)
83
- - [Status Mentions Message](#status-mentions-message)
84
- - [Shop Message](#shop-message)
85
- - [Collection Message](#collection-message)
86
- - [AI Icon Feature](ai-icon-feature)
87
- - [Sending with Link Preview](#sending-messages-with-link-previews)
88
- - [Media Messages](#media-messages)
89
- - [Gif Message](#gif-message)
90
- - [Video Message](#video-message)
91
- - [Audio Message](#audio-message)
92
- - [Image Message](#image-message)
93
- - [Album Message](#album-message)
94
- - [Ptv Video Message](#ptv-video-message)
95
- - [ViewOnce Message](#view-once-message)
96
- - [Modify Messages](#modify-messages)
97
- - [Delete Messages (for everyone)](#deleting-messages-for-everyone)
98
- - [Edit Messages](#editing-messages)
99
- - [Manipulating Media Messages](#manipulating-media-messages)
100
- - [Thumbnail in Media Messages](#thumbnail-in-media-messages)
101
- - [Downloading Media Messages](#downloading-media-messages)
102
- - [Re-upload Media Message to Whatsapp](#re-upload-media-message-to-whatsapp)
103
- - [Reject Call](#reject-call)
104
- - [Send States in Chat](#send-states-in-chat)
105
- - [Reading Messages](#reading-messages)
106
- - [Update Presence](#update-presence)
107
- - [Modifying Chats](#modifying-chats)
108
- - [Archive a Chat](#archive-a-chat)
109
- - [Mute/Unmute a Chat](#muteunmute-a-chat)
110
- - [Mark a Chat Read/Unread](#mark-a-chat-readunread)
111
- - [Delete a Message for Me](#delete-a-message-for-me)
112
- - [Delete a Chat](#delete-a-chat)
113
- - [Star/Unstar a Message](#starunstar-a-message)
114
- - [Disappearing Messages](#disappearing-messages)
115
- - [Clear Messages](#clear-messages)
116
- - [User Querys](#user-querys)
117
- - [Check If ID Exists in Whatsapp](#check-if-id-exists-in-whatsapp)
118
- - [Query Chat History (groups too)](#query-chat-history-groups-too)
119
- - [Fetch Status](#fetch-status)
120
- - [Fetch Profile Picture (groups too)](#fetch-profile-picture-groups-too)
121
- - [Fetch Bussines Profile (such as description or category)](#fetch-bussines-profile-such-as-description-or-category)
122
- - [Fetch Someone's Presence (if they're typing or online)](#fetch-someones-presence-if-theyre-typing-or-online)
123
- - [Change Profile](#change-profile)
124
- - [Change Profile Status](#change-profile-status)
125
- - [Change Profile Name](#change-profile-name)
126
- - [Change Display Picture (groups too)](#change-display-picture-groups-too)
127
- - [Remove display picture (groups too)](#remove-display-picture-groups-too)
128
- - [Groups](#groups)
129
- - [Create a Group](#create-a-group)
130
- - [Add/Remove or Demote/Promote](#addremove-or-demotepromote)
131
- - [Change Subject (name)](#change-subject-name)
132
- - [Change Description](#change-description)
133
- - [Change Settings](#change-settings)
134
- - [Leave a Group](#leave-a-group)
135
- - [Get Invite Code](#get-invite-code)
136
- - [Revoke Invite Code](#revoke-invite-code)
137
- - [Join Using Invitation Code](#join-using-invitation-code)
138
- - [Get Group Info by Invite Code](#get-group-info-by-invite-code)
139
- - [Query Metadata (participants, name, description...)](#query-metadata-participants-name-description)
140
- - [Join using groupInviteMessage](#join-using-groupinvitemessage)
141
- - [Get Request Join List](#get-request-join-list)
142
- - [Approve/Reject Request Join](#approvereject-request-join)
143
- - [Get All Participating Groups Metadata](#get-all-participating-groups-metadata)
144
- - [Toggle Ephemeral](#toggle-ephemeral)
145
- - [Change Add Mode](#change-add-mode)
146
- - [Privacy](#privacy)
147
- - [Block/Unblock User](#blockunblock-user)
148
- - [Get Privacy Settings](#get-privacy-settings)
149
- - [Get BlockList](#get-blocklist)
150
- - [Update LastSeen Privacy](#update-lastseen-privacy)
151
- - [Update Online Privacy](#update-online-privacy)
152
- - [Update Profile Picture Privacy](#update-profile-picture-privacy)
153
- - [Update Status Privacy](#update-status-privacy)
154
- - [Update Read Receipts Privacy](#update-read-receipts-privacy)
155
- - [Update Groups Add Privacy](#update-groups-add-privacy)
156
- - [Update Default Disappearing Mode](#update-default-disappearing-mode)
157
- - [Broadcast Lists & Stories](#broadcast-lists--stories)
158
- - [Send Broadcast & Stories](#send-broadcast--stories)
159
- - [Query a Broadcast List's Recipients & Name](#query-a-broadcast-lists-recipients--name)
160
- - [Writing Custom Functionality](#writing-custom-functionality)
161
- - [Enabling Debug Level in Baileys Logs](#enabling-debug-level-in-baileys-logs)
162
- - [How Whatsapp Communicate With Us](#how-whatsapp-communicate-with-us)
163
- - [Register a Callback for Websocket Events](#register-a-callback-for-websocket-events)
164
-
165
- ## Connecting Account
166
-
167
- WhatsApp provides a multi-device API that allows Baileys to be authenticated as a second WhatsApp client by scanning a **QR code** or **Pairing Code** with WhatsApp on your phone.
168
-
169
- > [!NOTE]
170
- > **[Here](#example-to-start) is a simple example of event handling**
171
-
172
- > [!TIP]
173
- > **You can see all supported socket configs [here](https://baileys.whiskeysockets.io/types/SocketConfig.html) (Recommended)**
174
-
175
- ### Starting socket with **QR-CODE**
176
-
177
- > [!TIP]
178
- > You can customize browser name if you connect with **QR-CODE**, with `Browser` constant, we have some browsers config, **see [here](https://baileys.whiskeysockets.io/types/BrowsersMap.html)**
179
-
180
- ```ts
181
- import makeWASocket from '@areumtecnologia/wasockets'
182
-
183
- const sock = makeWASocket({
184
- // can provide additional config here
185
- browser: Browsers.ubuntu('My App'),
186
- printQRInTerminal: true
187
- })
188
- ```
189
-
190
- If the connection is successful, you will see a QR code printed on your terminal screen, scan it with WhatsApp on your phone and you'll be logged in!
191
-
192
- ### Starting socket with **Pairing Code**
193
-
194
-
195
- > [!IMPORTANT]
196
- > Pairing Code isn't Mobile API, it's a method to connect Whatsapp Web without QR-CODE, you can connect only with one device, see [here](https://faq.whatsapp.com/1324084875126592/?cms_platform=web)
197
-
198
- The phone number can't have `+` or `()` or `-`, only numbers, you must provide country code
199
-
200
- ```ts
201
- import makeWASocket from '@areumtecnologia/wasockets'
202
-
203
- const sock = makeWASocket({
204
- // can provide additional config here
205
- printQRInTerminal: false //need to be false
206
- })
207
-
208
- if (!sock.authState.creds.registered) {
209
- const number = 'XXXXXXXXXXX'
210
- const code = await sock.requestPairingCode(number) // or await sock.requestPairingCode(number, 'CODEOTPS') custom your pairing code
211
- console.log(code)
212
- }
213
- ```
214
-
215
- ### Receive Full History
216
-
217
- 1. Set `syncFullHistory` as `true`
218
- 2. Baileys, by default, use chrome browser config
219
- - If you'd like to emulate a desktop connection (and receive more message history), this browser setting to your Socket config:
220
-
221
- ```ts
222
- const sock = makeWASocket({
223
- ...otherOpts,
224
- // can use Windows, Ubuntu here too
225
- browser: Browsers.macOS('Desktop'),
226
- syncFullHistory: true
227
- })
228
- ```
229
-
230
- ## Important Notes About Socket Config
231
-
232
- ### Caching Group Metadata (Recommended)
233
- - If you use baileys for groups, we recommend you to set `cachedGroupMetadata` in socket config, you need to implement a cache like this:
234
-
235
- ```ts
236
- const groupCache = new NodeCache({stdTTL: 5 * 60, useClones: false})
237
-
238
- const sock = makeWASocket({
239
- cachedGroupMetadata: async (jid) => groupCache.get(jid)
240
- })
241
-
242
- sock.ev.on('groups.update', async ([event]) => {
243
- const metadata = await sock.groupMetadata(event.id)
244
- groupCache.set(event.id, metadata)
245
- })
246
-
247
- sock.ev.on('group-participants.update', async (event) => {
248
- const metadata = await sock.groupMetadata(event.id)
249
- groupCache.set(event.id, metadata)
250
- })
251
- ```
252
-
253
- ### Improve Retry System & Decrypt Poll Votes
254
- - If you want to improve sending message, retrying when error occurs and decrypt poll votes, you need to have a store and set `getMessage` config in socket like this:
255
- ```ts
256
- const sock = makeWASocket({
257
- getMessage: async (key) => await getMessageFromStore(key)
258
- })
259
- ```
260
-
261
- ### Receive Notifications in Whatsapp App
262
- - If you want to receive notifications in whatsapp app, set `markOnlineOnConnect` to `false`
263
- ```ts
264
- const sock = makeWASocket({
265
- markOnlineOnConnect: false
266
- })
267
- ```
268
- ## Saving & Restoring Sessions
269
-
270
- You obviously don't want to keep scanning the QR code every time you want to connect.
271
-
272
- So, you can load the credentials to log back in:
273
- ```ts
274
- import makeWASocket, { useMultiFileAuthState } from '@areumtecnologia/wasockets'
275
-
276
- const { state, saveCreds } = await useMultiFileAuthState('auth_info_baileys')
277
-
278
- // will use the given state to connect
279
- // so if valid credentials are available -- it'll connect without QR
280
- const sock = makeWASocket({ auth: state })
281
-
282
- // this will be called as soon as the credentials are updated
283
- sock.ev.on('creds.update', saveCreds)
284
- ```
285
-
286
- > [!IMPORTANT]
287
- > `useMultiFileAuthState` is a utility function to help save the auth state in a single folder, this function serves as a good guide to help write auth & key states for SQL/no-SQL databases, which I would recommend in any production grade system.
288
-
289
- > [!NOTE]
290
- > When a message is received/sent, due to signal sessions needing updating, the auth keys (`authState.keys`) will update. Whenever that happens, you must save the updated keys (`authState.keys.set()` is called). Not doing so will prevent your messages from reaching the recipient & cause other unexpected consequences. The `useMultiFileAuthState` function automatically takes care of that, but for any other serious implementation -- you will need to be very careful with the key state management.
291
-
292
- ## Handling Events
293
-
294
- - Baileys uses the EventEmitter syntax for events.
295
- They're all nicely typed up, so you shouldn't have any issues with an Intellisense editor like VS Code.
296
-
297
- > [!IMPORTANT]
298
- > **The events are [these](https://baileys.whiskeysockets.io/types/BaileysEventMap.html)**, it's important you see all events
299
-
300
- You can listen to these events like this:
301
- ```ts
302
- const sock = makeWASocket()
303
- sock.ev.on('messages.upsert', ({ messages }) => {
304
- console.log('got messages', messages)
305
- })
306
- ```
307
-
308
- ### Example to Start
309
-
310
- > [!NOTE]
311
- > This example includes basic auth storage too
312
-
313
- ```ts
314
- import makeWASocket, { DisconnectReason, useMultiFileAuthState } from '@areumtecnologia/wasockets'
315
- import { Boom } from '@hapi/boom'
316
-
317
- async function connectToWhatsApp () {
318
- const { state, saveCreds } = await useMultiFileAuthState('./auth_info_baileys')
319
- const sock = makeWASocket({
320
- // can provide additional config here
321
- auth: state,
322
- printQRInTerminal: true
323
- })
324
- sock.ev.on('connection.update', (update) => {
325
- const { connection, lastDisconnect } = update
326
- if(connection === 'close') {
327
- const shouldReconnect = (lastDisconnect.error as Boom)?.output?.statusCode !== DisconnectReason.loggedOut
328
- console.log('connection closed due to ', lastDisconnect.error, ', reconnecting ', shouldReconnect)
329
- // reconnect if not logged out
330
- if(shouldReconnect) {
331
- connectToWhatsApp()
332
- }
333
- } else if(connection === 'open') {
334
- console.log('opened connection')
335
- }
336
- })
337
- sock.ev.on('messages.upsert', event => {
338
- for (const m of event.messages) {
339
- console.log(JSON.stringify(m, undefined, 2))
340
-
341
- console.log('replying to', m.key.remoteJid)
342
- await sock.sendMessage(m.key.remoteJid!, { text: 'Hello Word' })
343
- }
344
- })
345
-
346
- // to storage creds (session info) when it updates
347
- sock.ev.on('creds.update', saveCreds)
348
- }
349
- // run in main file
350
- connectToWhatsApp()
351
- ```
352
-
353
- > [!IMPORTANT]
354
- > In `messages.upsert` it's recommended to use a loop like `for (const message of event.messages)` to handle all messages in array
355
-
356
- ### Decrypt Poll Votes
357
-
358
- - By default poll votes are encrypted and handled in `messages.update`
359
- ```ts
360
- import pino from "pino"
361
- import { makeInMemoryStore, getAggregateVotesInPollMessage } from '@areumtecnologia/wasockets'
362
-
363
- const logger = pino({ timestamp: () => `,"time":"${new Date().toJSON()}"` }).child({ class: "@Itsockchann" })
364
- logger.level = "fatal"
365
- const store = makeInMemoryStore({ logger })
366
-
367
- async function getMessage(key){
368
- if (store) {
369
- const msg = await store.loadMessage(key.remoteJid, key.id)
370
- return msg?.message
371
- }
372
- return {
373
- conversation: "Itsocki Kawaiii"
374
- }
375
- }
376
-
377
- sock.ev.on("messages.update", async (chatUpdate) => {
378
- for(const { key, update } of chatUpdate) {
379
- if(update.pollUpdates && key.fromMe) {
380
- const pollCreation = await getMessage(key)
381
- if(pollCreation) {
382
- const pollUpdate = await getAggregateVotesInPollMessage({
383
- message: pollCreation,
384
- pollUpdates: update.pollUpdates,
385
- })
386
- const toCmd = pollUpdate.filter(v => v.voters.length !== 0)[0]?.name
387
- if (toCmd == undefined) return
388
- console.log(toCmd)
389
- }
390
- }
391
- }
392
- })
393
- ```
394
-
395
- ### Decrypt Event Response
396
-
397
- - By default event response are encrypted and handled in `messages.update`
398
- ```ts
399
- import { jidNormalizedUser, getAggregateResponsesInEventMessage } from '@areumtecnologia/wasockets'
400
-
401
- sock.ev.on("messages.update", async ([chatUpdate]) => {
402
- const eventResponses = chatUpdate.update?.eventResponses
403
- const agregate = getAggregateResponsesInEventMessage({ eventResponses }, jidNormalizedUser(sock.user.lid))
404
- console.log(agregate)
405
- })
406
- ```
407
-
408
- ### Summary of Events on First Connection
409
-
410
- 1. When you connect first time, `connection.update` will be fired requesting you to restart sock
411
- 2. Then, history messages will be received in `messaging.history-set`
412
-
413
- ## Implementing a Data Store
414
-
415
- - Baileys does not come with a defacto storage for chats, contacts, or messages. However, a simple in-memory implementation has been provided. The store listens for chat updates, new messages, message updates, etc., to always have an up-to-date version of the data.
416
-
417
- > [!IMPORTANT]
418
- > I highly recommend building your own data store, as storing someone's entire chat history in memory is a terrible waste of RAM.
419
-
420
- It can be used as follows:
421
-
422
- ```ts
423
- import makeWASocket, { makeInMemoryStore } from '@areumtecnologia/wasockets'
424
- // the store maintains the data of the WA connection in memory
425
- // can be written out to a file & read from it
426
- const store = makeInMemoryStore({ })
427
- // can be read from a file
428
- store.readFromFile('./baileys_store.json')
429
- // saves the state to a file every 10s
430
- setInterval(() => {
431
- store.writeToFile('./baileys_store.json')
432
- }, 10_000)
433
-
434
- const sock = makeWASocket({ })
435
- // will listen from this socket
436
- // the store can listen from a new socket once the current socket outlives its lifetime
437
- store.bind(sock.ev)
438
-
439
- sock.ev.on('chats.upsert', () => {
440
- // can use 'store.chats' however you want, even after the socket dies out
441
- // 'chats' => a KeyedDB instance
442
- console.log('got chats', store.chats.all())
443
- })
444
-
445
- sock.ev.on('contacts.upsert', () => {
446
- console.log('got contacts', Object.values(store.contacts))
447
- })
448
-
449
- ```
450
-
451
- The store also provides some simple functions such as `loadMessages` that utilize the store to speed up data retrieval.
452
-
453
- ## Whatsapp IDs Explain
454
-
455
- - `id` is the WhatsApp ID, called `jid` too, of the person or group you're sending the message to.
456
- - It must be in the format ```[country code][phone number]@s.whatsapp.net```
457
- - Example for people: ```+19999999999@s.whatsapp.net```.
458
- - For groups, it must be in the format ``` 123456789-123345@g.us ```.
459
- - For broadcast lists, it's `[timestamp of creation]@broadcast`.
460
- - For stories, the ID is `status@broadcast`.
461
-
462
- ## Utility Functions
463
-
464
- - `getContentType`, returns the content type for any message
465
- - `getDevice`, returns the device from message
466
- - `makeCacheableSignalKeyStore`, make auth store more fast
467
- - `downloadContentFromMessage`, download content from any message
468
-
469
- ## Sending Messages
470
-
471
- - Send all types of messages with a single function
472
- - **[Here](https://baileys.whiskeysockets.io/types/AnyMessageContent.html) you can see all message contents supported, like text message**
473
- - **[Here](https://baileys.whiskeysockets.io/types/MiscMessageGenerationOptions.html) you can see all options supported, like quote message**
474
-
475
- ```ts
476
- const jid: string
477
- const content: AnyMessageContent
478
- const options: MiscMessageGenerationOptions
479
-
480
- sock.sendMessage(jid, content, options)
481
- ```
482
-
483
- ### Non-Media Messages
484
-
485
- #### Text Message
486
- ```ts
487
- await sock.sendMessage(jid, { text: 'hello word' })
488
- ```
489
-
490
- #### Quote Message (works with all types)
491
- ```ts
492
- await sock.sendMessage(jid, { text: 'hello word' }, { quoted: message })
493
- ```
494
-
495
- #### Mention User (works with most types)
496
- - @number is to mention in text, it's optional
497
- ```ts
498
- await sock.sendMessage(
499
- jid,
500
- {
501
- text: '@12345678901',
502
- mentions: ['12345678901@s.whatsapp.net']
503
- }
504
- )
505
- ```
506
-
507
- #### Forward Messages
508
- - You need to have message object, can be retrieved from [store](#implementing-a-data-store) or use a [message](https://baileys.whiskeysockets.io/types/WAMessage.html) object
509
- ```ts
510
- const msg = getMessageFromStore() // implement this on your end
511
- await sock.sendMessage(jid, { forward: msg, force: true or number }) // WA forward the message!
512
- ```
513
-
514
- #### Location Message
515
- ```ts
516
- await sock.sendMessage(
517
- jid,
518
- {
519
- location: {
520
- degreesLatitude: 24.121231,
521
- degreesLongitude: 55.1121221
522
- }
523
- }
524
- )
525
- ```
526
-
527
- #### Live Location Message
528
- ```ts
529
- await sock.sendMessage(
530
- jid,
531
- {
532
- location: {
533
- degreesLatitude: 24.121231,
534
- degreesLongitude: 55.1121221
535
- },
536
- live: true
537
- }
538
- )
539
- ```
540
- #### Contact Message
541
- ```ts
542
- const vcard = 'BEGIN:VCARD\n' // metadata of the contact card
543
- + 'VERSION:3.0\n'
544
- + 'FN:Jeff Singh\n' // full name
545
- + 'ORG:Ashoka Uni\n' // the organization of the contact
546
- + 'TELtype=CELLtype=VOICEwaid=911234567890:+91 12345 67890\n' // WhatsApp ID + phone number
547
- + 'END:VCARD'
548
-
549
- await sock.sendMessage(
550
- id,
551
- {
552
- contacts: {
553
- displayName: 'Itsockchann',
554
- contacts: [{ vcard }]
555
- }
556
- }
557
- )
558
- ```
559
-
560
- #### Reaction Message
561
- - You need to pass the key of message, you can retrieve from [store](#implementing-a-data-store) or use a [key](https://baileys.whiskeysockets.io/types/WAMessageKey.html) object
562
- ```ts
563
- await sock.sendMessage(
564
- jid,
565
- {
566
- react: {
567
- text: '💖', // use an empty string to remove the reaction
568
- key: message.key
569
- }
570
- }
571
- )
572
- ```
573
-
574
- #### Pin Message
575
- - You need to pass the key of message, you can retrieve from [store](#implementing-a-data-store) or use a [key](https://baileys.whiskeysockets.io/types/WAMessageKey.html) object
576
-
577
- - Time can be:
578
-
579
- | Time | Seconds |
580
- |-------|----------------|
581
- | 24h | 86.400 |
582
- | 7d | 604.800 |
583
- | 30d | 2.592.000 |
584
-
585
- ```ts
586
- await sock.sendMessage(
587
- jid,
588
- {
589
- pin: {
590
- type: 1, // 2 to remove
591
- time: 86400,
592
- key: Key
593
- }
594
- }
595
- )
596
- ```
597
-
598
- ### Keep Message
599
- ```ts
600
- await sock.sendMessage(
601
- jid,
602
- {
603
- keep: {
604
- key: Key,
605
- type: 1 // or 2
606
- }
607
- }
608
- )
609
- ```
610
-
611
- #### Poll Message
612
- ```ts
613
- await sock.sendMessage(
614
- jid,
615
- {
616
- poll: {
617
- name: 'My Poll',
618
- values: ['Option 1', 'Option 2', ...],
619
- selectableCount: 1,
620
- toAnnouncementGroup: false // or true
621
- }
622
- }
623
- )
624
- ```
625
-
626
- #### Poll Result Message
627
- ```ts
628
- await sock.sendMessage(
629
- jid,
630
- {
631
- pollResult: {
632
- name: 'Hi',
633
- values: [
634
- [
635
- 'Option 1',
636
- 1000
637
- ],
638
- [
639
- 'Option 2',
640
- 2000
641
- ]
642
- ]
643
- }
644
- }
645
- )
646
- ```
647
-
648
- ### Call Message
649
- ```ts
650
- await sock.sendMessage(
651
- jid,
652
- {
653
- call: {
654
- name: 'Hay',
655
- type: 1 // 2 for video
656
- }
657
- }
658
- )
659
- ```
660
-
661
- ### Event Message
662
- ```ts
663
- await sock.sendMessage(
664
- jid,
665
- {
666
- event: {
667
- isCanceled: false, // or true
668
- name: 'holiday together!',
669
- description: 'who wants to come along?',
670
- location: {
671
- degreesLatitude: 24.121231,
672
- degreesLongitude: 55.1121221,
673
- name: 'name'
674
- },
675
- call: 'audio', // or 'video'
676
- startTime: number,
677
- endTime: number,
678
- extraGuestsAllowed: true // or false
679
- }
680
- }
681
- )
682
- ```
683
-
684
- ### Order Message
685
- ```ts
686
- await sock.sendMessage(
687
- jid,
688
- {
689
- order: {
690
- orderId: '574xxx',
691
- thumbnail: 'your_thumbnail',
692
- itemCount: 'your_count',
693
- status: 'your_status', // INQUIRY || ACCEPTED || DECLINED
694
- surface: 'CATALOG',
695
- message: 'your_caption',
696
- orderTitle: "your_title",
697
- sellerJid: 'your_jid'',
698
- token: 'your_token',
699
- totalAmount1000: 'your_amount',
700
- totalCurrencyCode: 'IDR'
701
- }
702
- }
703
- )
704
- ```
705
-
706
- ### Product Message
707
- ```ts
708
- await sock.sendMessage(
709
- jid,
710
- {
711
- product: {
712
- productImage: { // for using buffer >> productImage: your_buffer
713
- url: your_url
714
- },
715
- productId: 'your_id',
716
- title: 'your_title',
717
- description: 'your_description',
718
- currencyCode: 'IDR',
719
- priceAmount1000: 'your_amount',
720
- retailerId: 'your_reid', // optional use if needed
721
- url: 'your_url', // optional use if needed
722
- productImageCount: 'your_imageCount',
723
- firstImageId: 'your_image', // optional use if needed
724
- salePriceAmount1000: 'your_priceSale',
725
- signedUrl: 'your_url' // optional use if needed
726
- },
727
- businessOwnerJid: 'your_jid'
728
- }
729
- )
730
- ```
731
-
732
- ### Payment Message
733
- ```ts
734
- await sock.sendMessage(
735
- jid,
736
- {
737
- payment: {
738
- note: 'Hi!',
739
- currency: 'IDR', // optional
740
- offset: 0, // optional
741
- amount: '10000', // optional
742
- expiry: 0, // optional
743
- from: '628xxxx@s.whatsapp.net', // optional
744
- image: { // optional
745
- placeholderArgb: "your_background", // optional
746
- textArgb: "your_text", // optional
747
- subtextArgb: "your_subtext" // optional
748
- }
749
- }
750
- }
751
- )
752
- ```
753
-
754
- #### Payment Invite Message
755
- ```ts
756
- await sock.sendMessage(
757
- id,
758
- {
759
- paymentInvite: {
760
- type: number, // 1 || 2 || 3
761
- expiry: 0
762
- }
763
- }
764
- )
765
- ```
766
-
767
- ### Admin Invite Message
768
- ```ts
769
- await sock.sendMessage(
770
- jid,
771
- {
772
- adminInvite: {
773
- jid: '123xxx@newsletter',
774
- name: 'newsletter_name',
775
- caption: 'Please be my channel admin',
776
- expiration: 86400,
777
- jpegThumbnail: Buffer // optional
778
- }
779
- }
780
- )
781
- ```
782
-
783
- ### Group Invite Message
784
- ```ts
785
- await sock.sendMessage(
786
- jid,
787
- {
788
- groupInvite: {
789
- jid: '123xxx@g.us',
790
- name: 'group_name',
791
- caption: 'Please Join My Whatsapp Group',
792
- code: 'code_invite',
793
- expiration: 86400,
794
- jpegThumbnail: Buffer, // optional
795
- }
796
- }
797
- )
798
- ```
799
-
800
- ### Sticker Pack Message
801
- ```ts
802
- // I don't know why the sticker doesn't appear
803
- await sock.sendMessage(
804
- jid,
805
- {
806
- stickerPack: {
807
- name: 'Hiii',
808
- publisher: 'By Itsockchann',
809
- description: 'Hello',
810
- cover: Buffer, // Image buffer
811
- stickers: [{
812
- sticker: { url: 'https://example.com/1234kjd.webp' },
813
- emojis: ['❤'], // optional
814
- accessibilityLabel: '', // optional
815
- isLottie: Boolean, // optional
816
- isAnimated: Boolean // optional
817
- },
818
- {
819
- sticker: Buffer,
820
- emojis: ['❤'], // optional
821
- accessibilityLabel: '', // optional
822
- isLottie: Boolean, // optional
823
- isAnimated: Boolean // optional
824
- }]
825
- }
826
- }
827
- )
828
- ```
829
-
830
- ### Share Phone Number Message
831
- ```ts
832
- await sock.sendMessage(
833
- jid,
834
- {
835
- sharePhoneNumber: {
836
- }
837
- }
838
- )
839
- ```
840
-
841
- ### Request Phone Number Message
842
- ```ts
843
- await sock.sendMessage(
844
- jid,
845
- {
846
- requestPhoneNumber: {
847
- }
848
- }
849
- )
850
- ```
851
-
852
- ### Buttons Reply Message
853
- ```ts
854
- // List
855
- await sock.sendMessage(
856
- jid,
857
- {
858
- buttonReply: {
859
- name: 'Hii',
860
- description: 'description',
861
- rowId: 'ID'
862
- },
863
- type: 'list'
864
- }
865
- )
866
- // Plain
867
- await sock.sendMessage(
868
- jid,
869
- {
870
- buttonReply: {
871
- displayText: 'Hii',
872
- id: 'ID'
873
- },
874
- type: 'plain'
875
- }
876
- )
877
-
878
- // Template
879
- await sock.sendMessage(
880
- jid,
881
- {
882
- buttonReply: {
883
- displayText: 'Hii',
884
- id: 'ID',
885
- index: 'number'
886
- },
887
- type: 'template'
888
- }
889
- )
890
-
891
- // Interactive
892
- await sock.sendMessage(
893
- jid,
894
- {
895
- buttonReply: {
896
- body: 'Hii',
897
- nativeFlows: {
898
- name: 'menu_options',
899
- paramsJson: JSON.stringify({ id: 'ID', description: 'description' })
900
- version: 1 // 2 | 3
901
- }
902
- },
903
- type: 'interactive'
904
- }
905
- )
906
- ```
907
-
908
- ### Buttons Message
909
- ```ts
910
- await sock.sendMessage(
911
- jid,
912
- {
913
- text: 'This is a button message!', // image: buffer or // image: { url: url } If you want to use images
914
- caption: 'caption', // Use this if you are using an image or video
915
- footer: 'Hello World!',
916
- buttons: [{
917
- buttonId: 'Id1',
918
- buttonText: {
919
- displayText: 'Button 1'
920
- }
921
- },
922
- {
923
- buttonId: 'Id2',
924
- buttonText: {
925
- displayText: 'Button 2'
926
- }
927
- },
928
- {
929
- buttonId: 'Id3',
930
- buttonText: {
931
- displayText: 'Button 3'
932
- }
933
- }]
934
- }
935
- )
936
- ```
937
-
938
- ### Buttons List Message
939
- ```ts
940
- // Just working in a private chat
941
- await sock.sendMessage(
942
- jid,
943
- {
944
- text: 'This is a list!',
945
- footer: 'Hello World!',
946
- title: 'Amazing boldfaced list title',
947
- buttonText: 'Required, text on the button to view the list',
948
- sections: [
949
- {
950
- title: 'Section 1',
951
- rows: [{
952
- title: 'Option 1',
953
- rowId: 'option1'
954
- },
955
- {
956
- title: 'Option 2',
957
- rowId: 'option2',
958
- description: 'This is a description'
959
- }]
960
- },
961
- {
962
- title: 'Section 2',
963
- rows: [{
964
- title: 'Option 3',
965
- rowId: 'option3'
966
- },
967
- {
968
- title: 'Option 4',
969
- rowId: 'option4',
970
- description: 'This is a description V2'
971
- }]
972
- }]
973
- }
974
- )
975
- ```
976
-
977
- ### Buttons Product List Message
978
- ```ts
979
- // Just working in a private chat
980
- await sock.sendMessage(
981
- jid,
982
- {
983
- text: 'This is a list!',
984
- footer: 'Hello World!',
985
- title: 'Amazing boldfaced list title',
986
- buttonText: 'Required, text on the button to view the list',
987
- productList: [{
988
- title: 'This is a title',
989
- products: [
990
- {
991
- productId: '1234'
992
- },
993
- {
994
- productId: '5678'
995
- }
996
- ]
997
- }],
998
- businessOwnerJid: '628xxx@s.whatsapp.net',
999
- thumbnail: 'https://example.com/jdbenkksjs.jpg' // or buffer
1000
- }
1001
- )
1002
- ```
1003
-
1004
- ### Buttons Cards Message
1005
- ```ts
1006
- await sock.sendMessage(
1007
- jid,
1008
- {
1009
- text: 'Body Message',
1010
- title: 'Title Message',
1011
- subtile: 'Subtitle Message',
1012
- footer: 'Footer Message',
1013
- cards: [
1014
- {
1015
- image: { url: 'https://example.com/jdbenkksjs.jpg' }, // or buffer
1016
- title: 'Title Cards',
1017
- body: 'Body Cards',
1018
- footer: 'Footer Cards',
1019
- buttons: [
1020
- {
1021
- name: 'quick_reply',
1022
- buttonParamsJson: JSON.stringify({
1023
- display_text: 'Display Button',
1024
- id: 'ID'
1025
- })
1026
- },
1027
- {
1028
- name: 'cta_url',
1029
- buttonParamsJson: JSON.stringify({
1030
- display_text: 'Display Button',
1031
- url: 'https://www.example.com'
1032
- })
1033
- }
1034
- ]
1035
- },
1036
- {
1037
- video: { url: 'https://example.com/jdbenkksjs.mp4' }, // or buffer
1038
- title: 'Title Cards',
1039
- body: 'Body Cards',
1040
- footer: 'Footer Cards',
1041
- buttons: [
1042
- {
1043
- name: 'quick_reply',
1044
- buttonParamsJson: JSON.stringify({
1045
- display_text: 'Display Button',
1046
- id: 'ID'
1047
- })
1048
- },
1049
- {
1050
- name: 'cta_url',
1051
- buttonParamsJson: JSON.stringify({
1052
- display_text: 'Display Button',
1053
- url: 'https://www.example.com'
1054
- })
1055
- }
1056
- ]
1057
- }
1058
- ]
1059
- }
1060
- )
1061
- ```
1062
-
1063
- ### Buttons Template Message
1064
- ```ts
1065
- // This no longer works
1066
- await sock.sendMessage(
1067
- jid,
1068
- {
1069
- text: 'This is a template message!',
1070
- footer: 'Hello World!',
1071
- templateButtons: [{
1072
- index: 1,
1073
- urlButton: {
1074
- displayText: 'Follow Me',
1075
- url: 'https://whatsapp.com/channel/0029Vag9VSI2ZjCocqa2lB1y'
1076
- },
1077
- },
1078
- {
1079
- index: 2,
1080
- callButton: {
1081
- displayText: 'Call Me!',
1082
- phoneNumber: '628xxx'
1083
- },
1084
- },
1085
- {
1086
- index: 3,
1087
- quickReplyButton: {
1088
- displayText: 'This is a reply, just like normal buttons!',
1089
- id: 'id-like-buttons-message'
1090
- },
1091
- }]
1092
- }
1093
- )
1094
- ```
1095
-
1096
- ### Buttons Interactive Message
1097
- ```ts
1098
- await sock.sendMessage(
1099
- jid,
1100
- {
1101
- text: 'This is an Interactive message!',
1102
- title: 'Hiii',
1103
- subtitle: 'There is a subtitle',
1104
- footer: 'Hello World!',
1105
- interactiveButtons: [
1106
- {
1107
- name: 'quick_reply',
1108
- buttonParamsJson: JSON.stringify({
1109
- display_text: 'Click Me!',
1110
- id: 'your_id'
1111
- })
1112
- },
1113
- {
1114
- name: 'cta_url',
1115
- buttonParamsJson: JSON.stringify({
1116
- display_text: 'Follow Me',
1117
- url: 'https://whatsapp.com/channel/0029Vag9VSI2ZjCocqa2lB1y',
1118
- merchant_url: 'https://whatsapp.com/channel/0029Vag9VSI2ZjCocqa2lB1y'
1119
- })
1120
- },
1121
- {
1122
- name: 'cta_copy',
1123
- buttonParamsJson: JSON.stringify({
1124
- display_text: 'Click Me!',
1125
- copy_code: 'https://whatsapp.com/channel/0029Vag9VSI2ZjCocqa2lB1y'
1126
- })
1127
- },
1128
- {
1129
- name: 'cta_call',
1130
- buttonParamsJson: JSON.stringify({
1131
- display_text: 'Call Me!',
1132
- phone_number: '628xxx'
1133
- })
1134
- },
1135
- {
1136
- name: 'cta_catalog',
1137
- buttonParamsJson: JSON.stringify({
1138
- business_phone_number: '628xxx'
1139
- })
1140
- },
1141
- {
1142
- name: 'cta_reminder',
1143
- buttonParamsJson: JSON.stringify({
1144
- display_text: '...'
1145
- })
1146
- },
1147
- {
1148
- name: 'cta_cancel_reminder',
1149
- buttonParamsJson: JSON.stringify({
1150
- display_text: '...'
1151
- })
1152
- },
1153
- {
1154
- name: 'address_message',
1155
- buttonParamsJson: JSON.stringify({
1156
- display_text: '...'
1157
- })
1158
- },
1159
- {
1160
- name: 'send_location',
1161
- buttonParamsJson: JSON.stringify({
1162
- display_text: '...'
1163
- })
1164
- },
1165
- {
1166
- name: 'open_webview',
1167
- buttonParamsJson: JSON.stringify({
1168
- title: 'Follow Me!',
1169
- link: {
1170
- in_app_webview: true, // or false
1171
- url: 'https://whatsapp.com/channel/0029Vag9VSI2ZjCocqa2lB1y'
1172
- }
1173
- })
1174
- },
1175
- {
1176
- name: 'mpm',
1177
- buttonParamsJson: JSON.stringify({
1178
- product_id: '8816262248471474'
1179
- })
1180
- },
1181
- {
1182
- name: 'wa_payment_transaction_details',
1183
- buttonParamsJson: JSON.stringify({
1184
- transaction_id: '12345848'
1185
- })
1186
- },
1187
- {
1188
- name: 'automated_greeting_message_view_catalog',
1189
- buttonParamsJson: JSON.stringify({
1190
- business_phone_number: '628xxx',
1191
- catalog_product_id: '12345'
1192
- })
1193
- },
1194
- {
1195
- name: 'galaxy_message',
1196
- buttonParamsJson: JSON.stringify({
1197
- mode: 'published',
1198
- flow_message_version: '3',
1199
- flow_token: '1:1307913409923914:293680f87029f5a13d1ec5e35e718af3',
1200
- flow_id: '1307913409923914',
1201
- flow_cta: 'Itsockchann kawaii >\\<',
1202
- flow_action: 'navigate',
1203
- flow_action_payload: {
1204
- screen: 'QUESTION_ONE',
1205
- params: {
1206
- user_id: '123456789',
1207
- referral: 'campaign_xyz'
1208
- }
1209
- },
1210
- flow_metadata: {
1211
- flow_json_version: '201',
1212
- data_api_protocol: 'v2',
1213
- flow_name: 'Lead Qualification [en]',
1214
- data_api_version: 'v2',
1215
- categories: ['Lead Generation', 'Sales']
1216
- }
1217
- })
1218
- },
1219
- {
1220
- name: 'single_select',
1221
- buttonParamsJson: JSON.stringify({
1222
- title: 'Click Me!',
1223
- sections: [
1224
- {
1225
- title: 'Title 1',
1226
- highlight_label: 'Highlight label 1',
1227
- rows: [
1228
- {
1229
- header: 'Header 1',
1230
- title: 'Title 1',
1231
- description: 'Description 1',
1232
- id: 'Id 1'
1233
- },
1234
- {
1235
- header: 'Header 2',
1236
- title: 'Title 2',
1237
- description: 'Description 2',
1238
- id: 'Id 2'
1239
- }
1240
- ]
1241
- }
1242
- ]
1243
- })
1244
- }
1245
- ]
1246
- }
1247
- )
1248
-
1249
- // If you want to use an image
1250
- await sock.sendMessage(
1251
- jid,
1252
- {
1253
- image: {
1254
- url: 'https://example.com/jdbenkksjs.jpg'
1255
- },
1256
- caption: 'Body',
1257
- title: 'Title',
1258
- subtitle: 'Subtitle',
1259
- footer: 'Footer',
1260
- interactiveButtons: [
1261
- {
1262
- name: 'quick_reply',
1263
- buttonParamsJson: JSON.stringify({
1264
- display_text: 'DisplayText',
1265
- id: 'ID1'
1266
- })
1267
- }
1268
- ],
1269
- hasMediaAttachment: false // or true
1270
- }
1271
- )
1272
-
1273
- // If you want to use an video
1274
- await sock.sendMessage(
1275
- jid,
1276
- {
1277
- video: {
1278
- url: 'https://example.com/jdbenkksjs.mp4'
1279
- },
1280
- caption: 'Body',
1281
- title: 'Title',
1282
- subtitle: 'Subtitle',
1283
- footer: 'Footer',
1284
- interactiveButtons: [
1285
- {
1286
- name: 'quick_reply',
1287
- buttonParamsJson: JSON.stringify({
1288
- display_text: 'DisplayText',
1289
- id: 'ID1'
1290
- })
1291
- }
1292
- ],
1293
- hasMediaAttachment: false // or true
1294
- }
1295
- )
1296
-
1297
- // If you want to use an document
1298
- await sock.sendMessage(
1299
- jid,
1300
- {
1301
- document: {
1302
- url: 'https://example.com/jdbenkksjs.jpg'
1303
- },
1304
- mimetype: 'image/jpeg',
1305
- jpegThumbnail: await sock.resize('https://example.com/jdbenkksjs.jpg', 320, 320),
1306
- caption: 'Body',
1307
- title: 'Title',
1308
- subtitle: 'Subtitle',
1309
- footer: 'Footer',
1310
- interactiveButtons: [
1311
- {
1312
- name: 'quick_reply',
1313
- buttonParamsJson: JSON.stringify({
1314
- display_text: 'DisplayText',
1315
- id: 'ID1'
1316
- })
1317
- }
1318
- ],
1319
- hasMediaAttachment: false // or true
1320
- }
1321
- )
1322
-
1323
- // If you want to use an location
1324
- await sock.sendMessage(
1325
- jid,
1326
- {
1327
- location: {
1328
- degressLatitude: -0,
1329
- degressLongitude: 0,
1330
- name: 'Hi'
1331
- },
1332
- caption: 'Body',
1333
- title: 'Title',
1334
- subtitle: 'Subtitle',
1335
- footer: 'Footer',
1336
- interactiveButtons: [
1337
- {
1338
- name: 'quick_reply',
1339
- buttonParamsJson: JSON.stringify({
1340
- display_text: 'DisplayText',
1341
- id: 'ID1'
1342
- })
1343
- }
1344
- ],
1345
- hasMediaAttachment: false // or true
1346
- }
1347
- )
1348
-
1349
- // if you want to use an product
1350
- await sock.sendMessage(
1351
- jid,
1352
- {
1353
- product: {
1354
- productImage: {
1355
- url: 'https://example.com/jdbenkksjs.jpg'
1356
- },
1357
- productId: '836xxx',
1358
- title: 'Title',
1359
- description: 'Description',
1360
- currencyCode: 'IDR',
1361
- priceAmount1000: '283xxx',
1362
- retailerId: 'Itsockchann',
1363
- url: 'https://example.com',
1364
- productImageCount: 1
1365
- },
1366
- businessOwnerJid: '628xxx@s.whatsapp.net',
1367
- caption: 'Body',
1368
- title: 'Title',
1369
- subtitle: 'Subtitle',
1370
- footer: 'Footer',
1371
- interactiveButtons: [
1372
- {
1373
- name: 'quick_reply',
1374
- buttonParamsJson: JSON.stringify({
1375
- display_text: 'DisplayText',
1376
- id: 'ID1'
1377
- })
1378
- }
1379
- ],
1380
- hasMediaAttachment: false // or true
1381
- }
1382
- )
1383
- ```
1384
-
1385
- ### Buttons Interactive Message PIX
1386
- ```ts
1387
- await sock.sendMessage(
1388
- jid,
1389
- {
1390
- text: '', // This string is required. Even it's empty.
1391
- interactiveButtons: [
1392
- {
1393
- name: 'payment_info',
1394
- buttonParamsJson: JSON.stringify({
1395
- payment_settings: [{
1396
- type: "pix_static_code",
1397
- pix_static_code: {
1398
- merchant_name: 'itsockchann kawaii >\\\\\\<',
1399
- key: 'example@itsockchan.com',
1400
- key_type: 'EMAIL' // PHONE || EMAIL || CPF || EVP
1401
- }
1402
- }]
1403
- })
1404
- }
1405
- ],
1406
- }
1407
- )
1408
- ```
1409
-
1410
- ### Buttons Interactive Message PAY
1411
- ```ts
1412
- await sock.sendMessage(
1413
- jid,
1414
- {
1415
- text: '', // This string is required. Even it's empty.
1416
- interactiveButtons: [
1417
- {
1418
- name: 'review_and_pay',
1419
- buttonParamsJson: JSON.stringify({
1420
- currency: 'IDR',
1421
- payment_configuration: '',
1422
- payment_type: '',
1423
- total_amount: {
1424
- value: '999999999',
1425
- offset: '100'
1426
- },
1427
- reference_id: '45XXXXX',
1428
- type: 'physical-goods',
1429
- payment_method: 'confirm',
1430
- payment_status: 'captured',
1431
- payment_timestamp: Math.floor(Date.now() / 1000),
1432
- order: {
1433
- status: 'completed',
1434
- description: '',
1435
- subtotal: {
1436
- value: '0',
1437
- offset: '100'
1438
- },
1439
- order_type: 'PAYMENT_REQUEST',
1440
- items: [{
1441
- retailer_id: 'your_retailer_id',
1442
- name: 'Itsockchann Kawaii >\\\<',
1443
- amount: {
1444
- value: '999999999',
1445
- offset: '100'
1446
- },
1447
- quantity: '1',
1448
- }]
1449
- },
1450
- additional_note: 'Itsockchann Kawaii >\\\<',
1451
- native_payment_methods: [],
1452
- share_payment_status: false
1453
- })
1454
- }
1455
- ],
1456
- }
1457
- )
1458
- ```
1459
-
1460
- ### Status Mentions Message
1461
- ```ts
1462
- const jidat = [
1463
- '123451679@g.us',
1464
- '124848899@g.us',
1465
- '111384848@g.us',
1466
- '62689xxxx@s.whatsapp.net',
1467
- '62xxxxxxx@s.whatsapp.net'
1468
- ]
1469
- // Text
1470
- await sock.sendStatusMentions(
1471
- {
1472
- text: 'Hello Everyone :3',
1473
- font: 2, // optional
1474
- textColor: 'FF0000', // optional
1475
- backgroundColor: '#000000' // optional
1476
- },
1477
- jids // Limit to 5 mentions per status
1478
- )
1479
-
1480
- // Image
1481
- await sock.sendStatusMentions(
1482
- {
1483
- Image: { url: 'https://example.com/ruriooe.jpg' }, or image buffer
1484
- caption: 'Hello Everyone :3' // optional
1485
- },
1486
- jids // Limit to 5 mentions per status
1487
- )
1488
-
1489
- // Video
1490
- await sock.sendStatusMentions(
1491
- {
1492
- video: { url: 'https://example.com/ruriooe.mp4' }, or video buffer
1493
- caption: 'Hello Everyone :3' // optional
1494
- },
1495
- jids // Limit to 5 mentions per status
1496
- )
1497
-
1498
- // Audio
1499
- await sock.sendStatusMentions(
1500
- {
1501
- audio: { url: 'https://example.com/ruriooe.mp3' }, or audio buffer
1502
- backgroundColor: '#000000', // optional
1503
- mimetype: 'audio/mp4',
1504
- ppt: true
1505
- },
1506
- jids // Limit to 5 mentions per status
1507
- )
1508
- ```
1509
-
1510
- ### Shop Message
1511
- ```ts
1512
- await sock.sendMessage(
1513
- jid,
1514
- {
1515
- text: 'Body',
1516
- title: 'Title',
1517
- subtitle: 'Subtitle',
1518
- footer: 'Footer',
1519
- shop: {
1520
- surface: 1, // 2 | 3 | 4
1521
- id: 'https://example.com'
1522
- },
1523
- viewOnce: true
1524
- }
1525
- )
1526
-
1527
- // Image
1528
- await sock.sendMessage(
1529
- jid,
1530
- {
1531
- image: {
1532
- url: 'https://example.com/jdbenkksjs.jpg'
1533
- },
1534
- caption: 'Body',
1535
- title: 'Title',
1536
- subtitle: 'Subtitle',
1537
- footer: 'Footer',
1538
- shop: {
1539
- surface: 1, // 2 | 3 | 4
1540
- id: 'https://example.com'
1541
- },
1542
- hasMediaAttachment: false, // or true
1543
- viewOnce: true
1544
- }
1545
- )
1546
-
1547
- // Video
1548
- await sock.sendMessage(
1549
- jid,
1550
- {
1551
- video: {
1552
- url: 'https://example.com/jdbenkksjs.jpg'
1553
- },
1554
- caption: 'Body',
1555
- title: 'Title',
1556
- subtitle: 'Subtitle',
1557
- footer: 'Footer',
1558
- shop: {
1559
- surface: 1, // 2 | 3 | 4
1560
- id: 'https://example.com'
1561
- },
1562
- hasMediaAttachment: false, // or true
1563
- viewOnce: true
1564
- }
1565
- )
1566
-
1567
- // Document
1568
- await sock.sendMessage(
1569
- jid,
1570
- {
1571
- document: {
1572
- url: 'https://example.com/jdbenkksjs.jpg'
1573
- },
1574
- mimetype: 'image/jpeg',
1575
- jpegThumbnail: await sock.resize('https://example.com/jdbenkksjs.jpg', 320, 320),
1576
- caption: 'Body',
1577
- title: 'Title',
1578
- subtitle: 'Subtitle',
1579
- footer: 'Footer',
1580
- shop: {
1581
- surface: 1, // 2 | 3 | 4
1582
- id: 'https://example.com'
1583
- },
1584
- hasMediaAttachment: false, // or true,
1585
- viewOnce: true
1586
- }
1587
- )
1588
-
1589
- // Location
1590
- await sock.sendMessage(
1591
- jid,
1592
- {
1593
- location: {
1594
- degressLatitude: -0,
1595
- degressLongitude: 0,
1596
- name: 'Hi'
1597
- },
1598
- caption: 'Body',
1599
- title: 'Title',
1600
- subtitle: 'Subtitle',
1601
- footer: 'Footer',
1602
- shop: {
1603
- surface: 1, // 2 | 3 | 4
1604
- id: 'https://example.com'
1605
- },
1606
- hasMediaAttachment: false, // or true
1607
- viewOnce: true
1608
- }
1609
- )
1610
-
1611
- // Product
1612
- await sock.sendMessage(
1613
- jid,
1614
- {
1615
- product: {
1616
- productImage: {
1617
- url: 'https://example.com/jdbenkksjs.jpg'
1618
- },
1619
- productId: '836xxx',
1620
- title: 'Title',
1621
- description: 'Description',
1622
- currencyCode: 'IDR',
1623
- priceAmount1000: '283xxx',
1624
- retailerId: 'Itsockchann',
1625
- url: 'https://example.com',
1626
- productImageCount: 1
1627
- },
1628
- businessOwnerJid: '628xxx@s.whatsapp.net',
1629
- caption: 'Body',
1630
- title: 'Title',
1631
- subtitle: 'Subtitle',
1632
- footer: 'Footer',
1633
- shop: {
1634
- surface: 1, // 2 | 3 | 4
1635
- id: 'https://example.com'
1636
- },
1637
- hasMediaAttachment: false, // or true
1638
- viewOnce: true
1639
- }
1640
- )
1641
- ```
1642
- ### Collection Message
1643
- ```ts
1644
- await sock.sendMessage(
1645
- jid,
1646
- {
1647
- text: 'Body',
1648
- title: 'Title',
1649
- subtitle: 'Subtitle',
1650
- footer: 'Footer',
1651
- collection: {
1652
- bizJid: 'jid',
1653
- id: 'https://example.com',
1654
- version: 1
1655
- },
1656
- viewOnce: true
1657
- }
1658
- )
1659
-
1660
- // Image
1661
- await sock.sendMessage(
1662
- jid,
1663
- {
1664
- image: {
1665
- url: 'https://example.com/jdbenkksjs.jpg'
1666
- },
1667
- caption: 'Body',
1668
- title: 'Title',
1669
- subtitle: 'Subtitle',
1670
- footer: 'Footer',
1671
- collection: {
1672
- bizJid: 'jid',
1673
- id: 'https://example.com',
1674
- version: 1
1675
- },
1676
- hasMediaAttachment: false, // or true
1677
- viewOnce: true
1678
- }
1679
- )
1680
-
1681
- // Video
1682
- await sock.sendMessage(
1683
- jid,
1684
- {
1685
- video: {
1686
- url: 'https://example.com/jdbenkksjs.jpg'
1687
- },
1688
- caption: 'Body',
1689
- title: 'Title',
1690
- subtitle: 'Subtitle',
1691
- footer: 'Footer',
1692
- collection: {
1693
- bizJid: 'jid',
1694
- id: 'https://example.com',
1695
- version: 1
1696
- },
1697
- hasMediaAttachment: false, // or true
1698
- viewOnce: true
1699
- }
1700
- )
1701
-
1702
- // Document
1703
- await sock.sendMessage(
1704
- jid,
1705
- {
1706
- document: {
1707
- url: 'https://example.com/jdbenkksjs.jpg'
1708
- },
1709
- mimetype: 'image/jpeg',
1710
- jpegThumbnail: await sock.resize('https://example.com/jdbenkksjs.jpg', 320, 320),
1711
- caption: 'Body',
1712
- title: 'Title',
1713
- subtitle: 'Subtitle',
1714
- footer: 'Footer',
1715
- collection: {
1716
- bizJid: 'jid',
1717
- id: 'https://example.com',
1718
- version: 1
1719
- },
1720
- hasMediaAttachment: false, // or true,
1721
- viewOnce: true
1722
- }
1723
- )
1724
-
1725
- // Location
1726
- await sock.sendMessage(
1727
- jid,
1728
- {
1729
- location: {
1730
- degressLatitude: -0,
1731
- degressLongitude: 0,
1732
- name: 'Hi'
1733
- },
1734
- caption: 'Body',
1735
- title: 'Title',
1736
- subtitle: 'Subtitle',
1737
- footer: 'Footer',
1738
- collection: {
1739
- bizJid: 'jid',
1740
- id: 'https://example.com',
1741
- version: 1
1742
- },
1743
- hasMediaAttachment: false, // or true
1744
- viewOnce: true
1745
- }
1746
- )
1747
-
1748
- // Product
1749
- await sock.sendMessage(
1750
- jid,
1751
- {
1752
- product: {
1753
- productImage: {
1754
- url: 'https://example.com/jdbenkksjs.jpg'
1755
- },
1756
- productId: '836xxx',
1757
- title: 'Title',
1758
- description: 'Description',
1759
- currencyCode: 'IDR',
1760
- priceAmount1000: '283xxx',
1761
- retailerId: 'Itsockchann',
1762
- url: 'https://example.com',
1763
- productImageCount: 1
1764
- },
1765
- businessOwnerJid: '628xxx@s.whatsapp.net',
1766
- caption: 'Body',
1767
- title: 'Title',
1768
- subtitle: 'Subtitle',
1769
- footer: 'Footer',
1770
- collection: {
1771
- bizJid: 'jid',
1772
- id: 'https://example.com',
1773
- version: 1
1774
- },
1775
- hasMediaAttachment: false, // or true
1776
- viewOnce: true
1777
- }
1778
- )
1779
- ```
1780
-
1781
- ### AI Icon Feature
1782
- ```ts
1783
- await sock.sendMessage(
1784
- jid,
1785
- {
1786
- text: 'Hi'
1787
- }, {
1788
- ai: true // Add ai usage and change it to true
1789
- }
1790
- )
1791
-
1792
- // If using relay
1793
- await sock.relayMessage(
1794
- jid,
1795
- {
1796
- extendedTextMessage: {
1797
- text: 'Hi'
1798
- }
1799
- }, {
1800
- AI: true // Use capital letters
1801
- }
1802
- )
1803
- ```
1804
-
1805
- ### Sending Messages with Link Previews
1806
-
1807
- 1. By default, wa does not have link generation when sent from the web
1808
- 2. Baileys has a function to generate the content for these link previews
1809
- 3. To enable this function's usage, add `unfurl.js` as a dependency to your project with `yarn add unfurl.js`
1810
- 4. Send a link:
1811
- ```ts
1812
- await sock.sendMessage(
1813
- jid,
1814
- {
1815
- text: 'Hi, this was sent using https://github.com/whiskeysockets/baileys'
1816
- }
1817
- )
1818
- ```
1819
-
1820
- ### Media Messages
1821
-
1822
- Sending media (video, stickers, images) is easier & more efficient than ever.
1823
-
1824
- > [!NOTE]
1825
- > In media messages, you can pass `{ stream: Stream }` or `{ url: Url }` or `Buffer` directly, you can see more [here](https://baileys.whiskeysockets.io/types/WAMediaUpload.html)
1826
-
1827
- - When specifying a media url, Baileys never loads the entire buffer into memory it even encrypts the media as a readable stream.
1828
-
1829
- > [!TIP]
1830
- > It's recommended to use Stream or Url to save memory
1831
-
1832
- #### Gif Message
1833
- - Whatsapp doesn't support `.gif` files, that's why we send gifs as common `.mp4` video with `gifPlayback` flag
1834
- ```ts
1835
- await sock.sendMessage(
1836
- jid,
1837
- {
1838
- video: fs.readFileSync('Media/ma_gif.mp4'),
1839
- caption: 'hello word',
1840
- gifPlayback: true
1841
- }
1842
- )
1843
- ```
1844
-
1845
- #### Video Message
1846
- ```ts
1847
- await sock.sendMessage(
1848
- id,
1849
- {
1850
- video: {
1851
- url: './Media/ma_gif.mp4'
1852
- },
1853
- caption: 'hello word',
1854
- }
1855
- )
1856
- ```
1857
-
1858
- #### Video Ptv Message
1859
- ```ts
1860
- await sock.sendMessage(
1861
- id,
1862
- {
1863
- video: {
1864
- url: './Media/ma_gif.mp4'
1865
- },
1866
- ptv: true
1867
- }
1868
- )
1869
- ```
1870
-
1871
- #### Audio Message
1872
- - To audio message work in all devices you need to convert with some tool like `ffmpeg` with this flags:
1873
- ```bash
1874
- codec: libopus //ogg file
1875
- ac: 1 //one channel
1876
- avoid_negative_ts
1877
- make_zero
1878
- ```
1879
- - Example:
1880
- ```bash
1881
- ffmpeg -i input.mp4 -avoid_negative_ts make_zero -ac 1 output.ogg
1882
- ```
1883
- ```ts
1884
- await sock.sendMessage(
1885
- jid,
1886
- {
1887
- audio: {
1888
- url: './Media/audio.mp3'
1889
- },
1890
- mimetype: 'audio/mp4'
1891
- }
1892
- )
1893
- ```
1894
-
1895
- #### Image Message
1896
- ```ts
1897
- await sock.sendMessage(
1898
- id,
1899
- {
1900
- image: {
1901
- url: './Media/ma_img.png'
1902
- },
1903
- caption: 'hello word'
1904
- }
1905
- )
1906
- ```
1907
-
1908
- ### Album Message
1909
- ```ts
1910
- await sock.sendMessage(
1911
- id,
1912
- {
1913
- album: [{
1914
- image: {
1915
- url: 'https://example.com/itsockchan.jpg'
1916
- },
1917
- caption: 'Hay'
1918
- }, {
1919
- image: Buffer,
1920
- caption: 'Hay'
1921
- }, {
1922
- video: {
1923
- url: 'https://example.com/itsockchan.mp4'
1924
- },
1925
- caption: 'Hay'
1926
- }, {
1927
- video: Buffer,
1928
- caption: 'Hay'
1929
- }
1930
- }
1931
- )
1932
- ```
1933
-
1934
- #### View Once Message
1935
-
1936
- - You can send all messages above as `viewOnce`, you only need to pass `viewOnce: true` in content object
1937
-
1938
- ```ts
1939
- await sock.sendMessage(
1940
- id,
1941
- {
1942
- image: {
1943
- url: './Media/ma_img.png'
1944
- },
1945
- viewOnce: true, //works with video, audio too
1946
- caption: 'hello word'
1947
- }
1948
- )
1949
- ```
1950
-
1951
- ## Modify Messages
1952
-
1953
- ### Deleting Messages (for everyone)
1954
-
1955
- ```ts
1956
- const msg = await sock.sendMessage(jid, { text: 'hello word' })
1957
- await sock.sendMessage(jid, { delete: msg.key })
1958
- ```
1959
-
1960
- **Note:** deleting for oneself is supported via `chatModify`, see in [this section](#modifying-chats)
1961
-
1962
- ### Editing Messages
1963
-
1964
- - You can pass all editable contents here
1965
- ```ts
1966
- await sock.sendMessage(jid, {
1967
- text: 'updated text goes here',
1968
- edit: response.key,
1969
- })
1970
- ```
1971
-
1972
- ## Manipulating Media Messages
1973
-
1974
- ### Thumbnail in Media Messages
1975
- - For media messages, the thumbnail can be generated automatically for images & stickers provided you add `jimp` or `sharp` as a dependency in your project using `yarn add jimp` or `yarn add sharp`.
1976
- - Thumbnails for videos can also be generated automatically, though, you need to have `ffmpeg` installed on your system.
1977
-
1978
- ### Downloading Media Messages
1979
-
1980
- If you want to save the media you received
1981
- ```ts
1982
- import { createWriteStream } from 'fs'
1983
- import { downloadMediaMessage, getContentType } from '@areumtecnologia/wasockets'
1984
-
1985
- sock.ev.on('messages.upsert', async ({ [m] }) => {
1986
- if (!m.message) return // if there is no text or media message
1987
- const messageType = getContentType(m) // get what type of message it is (text, image, video...)
1988
-
1989
- // if the message is an image
1990
- if (messageType === 'imageMessage') {
1991
- // download the message
1992
- const stream = await downloadMediaMessage(
1993
- m,
1994
- 'stream', // can be 'buffer' too
1995
- { },
1996
- {
1997
- logger,
1998
- // pass this so that baileys can request a reupload of media
1999
- // that has been deleted
2000
- reuploadRequest: sock.updateMediaMessage
2001
- }
2002
- )
2003
- // save to file
2004
- const writeStream = createWriteStream('./my-download.jpeg')
2005
- stream.pipe(writeStream)
2006
- }
2007
- }
2008
- ```
2009
-
2010
- ### Re-upload Media Message to Whatsapp
2011
-
2012
- - WhatsApp automatically removes old media from their servers. For the device to access said media -- a re-upload is required by another device that has it. This can be accomplished using:
2013
- ```ts
2014
- await sock.updateMediaMessage(msg)
2015
- ```
2016
-
2017
- ## Reject Call
2018
-
2019
- - You can obtain `callId` and `callFrom` from `call` event
2020
-
2021
- ```ts
2022
- await sock.rejectCall(callId, callFrom)
2023
- ```
2024
-
2025
- ## Send States in Chat
2026
-
2027
- ### Reading Messages
2028
- - A set of message [keys](https://baileys.whiskeysockets.io/types/WAMessageKey.html) must be explicitly marked read now.
2029
- - You cannot mark an entire 'chat' read as it were with Baileys Web.
2030
- This means you have to keep track of unread messages.
2031
-
2032
- ```ts
2033
- const key: WAMessageKey
2034
- // can pass multiple keys to read multiple messages as well
2035
- await sock.readMessages([key])
2036
- ```
2037
-
2038
- The message ID is the unique identifier of the message that you are marking as read.
2039
- On a `WAMessage`, the `messageID` can be accessed using ```messageID = message.key.id```.
2040
-
2041
- ### Update Presence
2042
-
2043
- - ``` presence ``` can be one of [these](https://baileys.whiskeysockets.io/types/WAPresence.html)
2044
- - The presence expires after about 10 seconds.
2045
- - This lets the person/group with `jid` know whether you're online, offline, typing etc.
2046
-
2047
- ```ts
2048
- await sock.sendPresenceUpdate('available', jid)
2049
- ```
2050
-
2051
- > [!NOTE]
2052
- > If a desktop client is active, WA doesn't send push notifications to the device. If you would like to receive said notifications -- mark your Baileys client offline using `sock.sendPresenceUpdate('unavailable')`
2053
-
2054
- ## Modifying Chats
2055
-
2056
- WA uses an encrypted form of communication to send chat/app updates. This has been implemented mostly and you can send the following updates:
2057
-
2058
- > [!IMPORTANT]
2059
- > If you mess up one of your updates, WA can log you out of all your devices and you'll have to log in again.
2060
-
2061
- ### Archive a Chat
2062
- ```ts
2063
- const lastMsgInChat = await getLastMessageInChat(jid) // implement this on your end
2064
- await sock.chatModify({ archive: true, lastMessages: [lastMsgInChat] }, jid)
2065
- ```
2066
- ### Mute/Unmute a Chat
2067
-
2068
- - Supported times:
2069
-
2070
- | Time | Miliseconds |
2071
- |-------|-----------------|
2072
- | Remove | null |
2073
- | 8h | 86.400.000 |
2074
- | 7d | 604.800.000 |
2075
-
2076
- ```ts
2077
- // mute for 8 hours
2078
- await sock.chatModify({ mute: 8 * 60 * 60 * 1000 }, jid)
2079
- // unmute
2080
- await sock.chatModify({ mute: null }, jid)
2081
- ```
2082
- ### Mark a Chat Read/Unread
2083
- ```ts
2084
- const lastMsgInChat = await getLastMessageInChat(jid) // implement this on your end
2085
- // mark it unread
2086
- await sock.chatModify({ markRead: false, lastMessages: [lastMsgInChat] }, jid)
2087
- ```
2088
-
2089
- ### Delete a Message for Me
2090
- ```ts
2091
- await sock.chatModify(
2092
- {
2093
- clear: {
2094
- messages: [
2095
- {
2096
- id: 'ATWYHDNNWU81732J',
2097
- fromMe: true,
2098
- timestamp: '1654823909'
2099
- }
2100
- ]
2101
- }
2102
- },
2103
- jid
2104
- )
2105
-
2106
- ```
2107
- ### Delete a Chat
2108
- ```ts
2109
- const lastMsgInChat = await getLastMessageInChat(jid) // implement this on your end
2110
- await sock.chatModify({
2111
- delete: true,
2112
- lastMessages: [
2113
- {
2114
- key: lastMsgInChat.key,
2115
- messageTimestamp: lastMsgInChat.messageTimestamp
2116
- }
2117
- ]
2118
- },
2119
- jid
2120
- )
2121
- ```
2122
- ### Pin/Unpin a Chat
2123
- ```ts
2124
- await sock.chatModify({
2125
- pin: true // or `false` to unpin
2126
- },
2127
- jid
2128
- )
2129
- ```
2130
- ### Star/Unstar a Message
2131
- ```ts
2132
- await sock.chatModify({
2133
- star: {
2134
- messages: [
2135
- {
2136
- id: 'messageID',
2137
- fromMe: true // or `false`
2138
- }
2139
- ],
2140
- star: true // - true: Star Message false: Unstar Message
2141
- }
2142
- },
2143
- jid
2144
- )
2145
- ```
2146
-
2147
- ### Disappearing Messages
2148
-
2149
- - Ephemeral can be:
2150
-
2151
- | Time | Seconds |
2152
- |-------|----------------|
2153
- | Remove | 0 |
2154
- | 24h | 86.400 |
2155
- | 7d | 604.800 |
2156
- | 90d | 7.776.000 |
2157
-
2158
- - You need to pass in **Seconds**, default is 7 days
2159
-
2160
- ```ts
2161
- // turn on disappearing messages
2162
- await sock.sendMessage(
2163
- jid,
2164
- // this is 1 week in seconds -- how long you want messages to appear for
2165
- { disappearingMessagesInChat: WA_DEFAULT_EPHEMERAL }
2166
- )
2167
-
2168
- // will send as a disappearing message
2169
- await sock.sendMessage(jid, { text: 'hello' }, { ephemeralExpiration: WA_DEFAULT_EPHEMERAL })
2170
-
2171
- // turn off disappearing messages
2172
- await sock.sendMessage(
2173
- jid,
2174
- { disappearingMessagesInChat: false }
2175
- )
2176
- ```
2177
-
2178
- ### Clear Messages
2179
- ```ts
2180
- await sock.clearMessage(jid, key, timestamps)
2181
- ```
2182
-
2183
- ## User Querys
2184
-
2185
- ### Check If ID Exists in Whatsapp
2186
- ```ts
2187
- const [result] = await sock.onWhatsApp(jid)
2188
- if (result.exists) console.log (`${jid} exists on WhatsApp, as jid: ${result.jid}`)
2189
- ```
2190
-
2191
- ### Query Chat History (groups too)
2192
-
2193
- - You need to have oldest message in chat
2194
- ```ts
2195
- const msg = await getOldestMessageInChat(jid)
2196
- await sock.fetchMessageHistory(
2197
- 50, //quantity (max: 50 per query)
2198
- msg.key,
2199
- msg.messageTimestamp
2200
- )
2201
- ```
2202
- - Messages will be received in `messaging.history-set` event
2203
-
2204
- ### Fetch Status
2205
- ```ts
2206
- const status = await sock.fetchStatus(jid)
2207
- console.log('status: ' + status)
2208
- ```
2209
-
2210
- ### Fetch Profile Picture
2211
- - To get the display picture of some person, group and channel
2212
- ```ts
2213
- // for low res picture
2214
- const ppUrl = await sock.profilePictureUrl(jid)
2215
- console.log(ppUrl)
2216
- ```
2217
-
2218
- ### Fetch Bussines Profile (such as description or category)
2219
- ```ts
2220
- const profile = await sock.getBusinessProfile(jid)
2221
- console.log('business description: ' + profile.description + ', category: ' + profile.category)
2222
- ```
2223
-
2224
- ### Fetch Someone's Presence (if they're typing or online)
2225
- ```ts
2226
- // the presence update is fetched and called here
2227
- sock.ev.on('presence.update', console.log)
2228
-
2229
- // request updates for a chat
2230
- await sock.presenceSubscribe(jid)
2231
- ```
2232
-
2233
- ## Change Profile
2234
-
2235
- ### Change Profile Status
2236
- ```ts
2237
- await sock.updateProfileStatus('Hello World!')
2238
- ```
2239
- ### Change Profile Name
2240
- ```ts
2241
- await sock.updateProfileName('My name')
2242
- ```
2243
- ### Change Display Picture (groups too)
2244
- - To change your display picture or a group's
2245
-
2246
- > [!NOTE]
2247
- > Like media messages, you can pass `{ stream: Stream }` or `{ url: Url }` or `Buffer` directly, you can see more [here](https://baileys.whiskeysockets.io/types/WAMediaUpload.html)
2248
-
2249
- ```ts
2250
- await sock.updateProfilePicture(jid, { url: './new-profile-picture.jpeg' })
2251
- ```
2252
- ### Remove display picture (groups too)
2253
- ```ts
2254
- await sock.removeProfilePicture(jid)
2255
- ```
2256
-
2257
- ## Groups
2258
-
2259
- - To change group properties you need to be admin
2260
-
2261
- ### Create a Group
2262
- ```ts
2263
- // title & participants
2264
- const group = await sock.groupCreate('My Fab Group', ['1234@s.whatsapp.net', '4564@s.whatsapp.net'])
2265
- console.log('created group with id: ' + group.gid)
2266
- await sock.sendMessage(group.id, { text: 'hello there' }) // say hello to everyone on the group
2267
- ```
2268
- ### Add/Remove or Demote/Promote
2269
- ```ts
2270
- // id & people to add to the group (will throw error if it fails)
2271
- await sock.groupParticipantsUpdate(
2272
- jid,
2273
- ['abcd@s.whatsapp.net', 'efgh@s.whatsapp.net'],
2274
- 'add' // replace this parameter with 'remove' or 'demote' or 'promote'
2275
- )
2276
- ```
2277
- ### Change Subject (name)
2278
- ```ts
2279
- await sock.groupUpdateSubject(jid, 'New Subject!')
2280
- ```
2281
- ### Change Description
2282
- ```ts
2283
- await sock.groupUpdateDescription(jid, 'New Description!')
2284
- ```
2285
- ### Change Settings
2286
- ```ts
2287
- // only allow admins to send messages
2288
- await sock.groupSettingUpdate(jid, 'announcement')
2289
- // allow everyone to send messages
2290
- await sock.groupSettingUpdate(jid, 'not_announcement')
2291
- // allow everyone to modify the group's settings -- like display picture etc.
2292
- await sock.groupSettingUpdate(jid, 'unlocked')
2293
- // only allow admins to modify the group's settings
2294
- await sock.groupSettingUpdate(jid, 'locked')
2295
- ```
2296
- ### Leave a Group
2297
- ```ts
2298
- // will throw error if it fails
2299
- await sock.groupLeave(jid)
2300
- ```
2301
- ### Get Invite Code
2302
- - To create link with code use `'https://chat.whatsapp.com/' + code`
2303
- ```ts
2304
- const code = await sock.groupInviteCode(jid)
2305
- console.log('group code: ' + code)
2306
- ```
2307
- ### Revoke Invite Code
2308
- ```ts
2309
- const code = await sock.groupRevokeInvite(jid)
2310
- console.log('New group code: ' + code)
2311
- ```
2312
- ### Join Using Invitation Code
2313
- - Code can't have `https://chat.whatsapp.com/`, only code
2314
- ```ts
2315
- const response = await sock.groupAcceptInvite(code)
2316
- console.log('joined to: ' + response)
2317
- ```
2318
- ### Get Group Info by Invite Code
2319
- ```ts
2320
- const response = await sock.groupGetInviteInfo(code)
2321
- console.log('group information: ' + response)
2322
- ```
2323
- ### Query Metadata (participants, name, description...)
2324
- ```ts
2325
- const metadata = await sock.groupMetadata(jid)
2326
- console.log(metadata.id + ', title: ' + metadata.subject + ', description: ' + metadata.desc)
2327
- ```
2328
- ### Join using `groupInviteMessage`
2329
- ```ts
2330
- const response = await sock.groupAcceptInviteV4(jid, groupInviteMessage)
2331
- console.log('joined to: ' + response)
2332
- ```
2333
- ### Get Request Join List
2334
- ```ts
2335
- const response = await sock.groupRequestParticipantsList(jid)
2336
- console.log(response)
2337
- ```
2338
- ### Approve/Reject Request Join
2339
- ```ts
2340
- const response = await sock.groupRequestParticipantsUpdate(
2341
- jid, // group id
2342
- ['abcd@s.whatsapp.net', 'efgh@s.whatsapp.net'],
2343
- 'approve' // or 'reject'
2344
- )
2345
- console.log(response)
2346
- ```
2347
- ### Get All Participating Groups Metadata
2348
- ```ts
2349
- const response = await sock.groupFetchAllParticipating()
2350
- console.log(response)
2351
- ```
2352
- ### Toggle Ephemeral
2353
-
2354
- - Ephemeral can be:
2355
-
2356
- | Time | Seconds |
2357
- |-------|----------------|
2358
- | Remove | 0 |
2359
- | 24h | 86.400 |
2360
- | 7d | 604.800 |
2361
- | 90d | 7.776.000 |
2362
-
2363
- ```ts
2364
- await sock.groupToggleEphemeral(jid, 86400)
2365
- ```
2366
-
2367
- ### Change Add Mode
2368
- ```ts
2369
- await sock.groupMemberAddMode(
2370
- jid,
2371
- 'all_member_add' // or 'admin_add'
2372
- )
2373
- ```
2374
-
2375
- ## Privacy
2376
-
2377
- ### Block/Unblock User
2378
- ```ts
2379
- await sock.updateBlockStatus(jid, 'block') // Block user
2380
- await sock.updateBlockStatus(jid, 'unblock') // Unblock user
2381
- ```
2382
- ### Get Privacy Settings
2383
- ```ts
2384
- const privacySettings = await sock.fetchPrivacySettings(true)
2385
- console.log('privacy settings: ' + privacySettings)
2386
- ```
2387
- ### Get BlockList
2388
- ```ts
2389
- const response = await sock.fetchBlocklist()
2390
- console.log(response)
2391
- ```
2392
- ### Update LastSeen Privacy
2393
- ```ts
2394
- const value = 'all' // 'contacts' | 'contact_blacklist' | 'none'
2395
- await sock.updateLastSeenPrivacy(value)
2396
- ```
2397
- ### Update Online Privacy
2398
- ```ts
2399
- const value = 'all' // 'match_last_seen'
2400
- await sock.updateOnlinePrivacy(value)
2401
- ```
2402
- ### Update Profile Picture Privacy
2403
- ```ts
2404
- const value = 'all' // 'contacts' | 'contact_blacklist' | 'none'
2405
- await sock.updateProfilePicturePrivacy(value)
2406
- ```
2407
- ### Update Status Privacy
2408
- ```ts
2409
- const value = 'all' // 'contacts' | 'contact_blacklist' | 'none'
2410
- await sock.updateStatusPrivacy(value)
2411
- ```
2412
- ### Update Read Receipts Privacy
2413
- ```ts
2414
- const value = 'all' // 'none'
2415
- await sock.updateReadReceiptsPrivacy(value)
2416
- ```
2417
- ### Update Groups Add Privacy
2418
- ```ts
2419
- const value = 'all' // 'contacts' | 'contact_blacklist'
2420
- await sock.updateGroupsAddPrivacy(value)
2421
- ```
2422
- ### Update Default Disappearing Mode
2423
-
2424
- - Like [this](#disappearing-messages), ephemeral can be:
2425
-
2426
- | Time | Seconds |
2427
- |-------|----------------|
2428
- | Remove | 0 |
2429
- | 24h | 86.400 |
2430
- | 7d | 604.800 |
2431
- | 90d | 7.776.000 |
2432
-
2433
- ```ts
2434
- const ephemeral = 86400
2435
- await sock.updateDefaultDisappearingMode(ephemeral)
2436
- ```
2437
-
2438
- ## Broadcast Lists & Stories
2439
-
2440
- ### Send Broadcast & Stories
2441
- - Messages can be sent to broadcasts & stories. You need to add the following message options in sendMessage, like this:
2442
- ```ts
2443
- await sock.sendMessage(
2444
- jid,
2445
- {
2446
- image: {
2447
- url: url
2448
- },
2449
- caption: caption
2450
- },
2451
- {
2452
- backgroundColor: backgroundColor,
2453
- font: font,
2454
- statusJidList: statusJidList,
2455
- broadcast: true
2456
- }
2457
- )
2458
- ```
2459
- - Message body can be a `extendedTextMessage` or `imageMessage` or `videoMessage` or `voiceMessage`, see [here](https://baileys.whiskeysockets.io/types/AnyRegularMessageContent.html)
2460
- - You can add `backgroundColor` and other options in the message options, see [here](https://baileys.whiskeysockets.io/types/MiscMessageGenerationOptions.html)
2461
- - `broadcast: true` enables broadcast mode
2462
- - `statusJidList`: a list of people that you can get which you need to provide, which are the people who will get this status message.
2463
-
2464
- - You can send messages to broadcast lists the same way you send messages to groups & individual chats.
2465
- - Right now, WA Web does not support creating broadcast lists, but you can still delete them.
2466
- - Broadcast IDs are in the format `12345678@broadcast`
2467
- ### Query a Broadcast List's Recipients & Name
2468
- ```ts
2469
- const bList = await sock.getBroadcastListInfo('1234@broadcast')
2470
- console.log (`list name: ${bList.name}, recps: ${bList.recipients}`)
2471
- ```
2472
-
2473
- ## Writing Custom Functionality
2474
- Baileys is written with custom functionality in mind. Instead of forking the project & re-writing the internals, you can simply write your own extensions.
2475
-
2476
- ### Enabling Debug Level in Baileys Logs
2477
- First, enable the logging of unhandled messages from WhatsApp by setting:
2478
- ```ts
2479
- const sock = makeWASocket({
2480
- logger: P({ level: 'debug' }),
2481
- })
2482
- ```
2483
- This will enable you to see all sorts of messages WhatsApp sends in the console.
2484
-
2485
- ### How Whatsapp Communicate With Us
2486
-
2487
- > [!TIP]
2488
- > If you want to learn whatsapp protocol, we recommend to study about Libsignal Protocol and Noise Protocol
2489
-
2490
- - **Example:** Functionality to track the battery percentage of your phone. You enable logging and you'll see a message about your battery pop up in the console:
2491
- ```
2492
- {
2493
- "level": 10,
2494
- "fromMe": false,
2495
- "frame": {
2496
- "tag": "ib",
2497
- "attrs": {
2498
- "from": "@s.whatsapp.net"
2499
- },
2500
- "content": [
2501
- {
2502
- "tag": "edge_routing",
2503
- "attrs": {},
2504
- "content": [
2505
- {
2506
- "tag": "routing_info",
2507
- "attrs": {},
2508
- "content": {
2509
- "type": "Buffer",
2510
- "data": [8,2,8,5]
2511
- }
2512
- }
2513
- ]
2514
- }
2515
- ]
2516
- },
2517
- "msg":"communication"
2518
- }
2519
- ```
2520
-
2521
- The `'frame'` is what the message received is, it has three components:
2522
- - `tag` -- what this frame is about (eg. message will have 'message')
2523
- - `attrs` -- a string key-value pair with some metadata (contains ID of the message usually)
2524
- - `content` -- the actual data (eg. a message node will have the actual message content in it)
2525
- - read more about this format [here](/src/WABinary/readme.md)
2526
-
2527
- ### Register a Callback for Websocket Events
2528
-
2529
- > [!TIP]
2530
- > Recommended to see `onMessageReceived` function in `socket.ts` file to understand how websockets events are fired
2531
-
2532
- ```ts
2533
- // for any message with tag 'edge_routing'
2534
- sock.ws.on('CB:edge_routing', (node: BinaryNode) => { })
2535
-
2536
- // for any message with tag 'edge_routing' and id attribute = abcd
2537
- sock.ws.on('CB:edge_routing,id:abcd', (node: BinaryNode) => { })
2538
-
2539
- // for any message with tag 'edge_routing', id attribute = abcd & first content node routing_info
2540
- sock.ws.on('CB:edge_routing,id:abcd,routing_info', (node: BinaryNode) => { })
2541
- ```
2542
-
2543
- > [!NOTE]
2544
- > Also, this repo is now licenced under GPL 3 since it uses [libsignal-node](https://git.questbook.io/backend/service-coderunner/-/merge_requests/1)
1
+ # WaSockets - API do WhatsApp Web em TypeScript/JavaScript
2
+
3
+ <div align="center">
4
+ <p><strong>Uma modificação otimizada e de alta performance da API do WhatsApp (baseada no Baileys), mantida e aprimorada pela Áreum Tecnologia.</strong></p>
5
+ </div>
6
+
7
+ ---
8
+
9
+ ### ⚠️ Nota Importante e Licença
10
+
11
+ Esta biblioteca é uma modificação independente e não é de forma alguma afiliada, endossada ou associada ao WhatsApp ou à Meta Inc. O uso desta ferramenta é de sua inteira responsabilidade. Desencorajamos fortemente o uso para spam, envio em massa não solicitado ou qualquer prática que viole os Termos de Serviço do WhatsApp.
12
+
13
+ O projeto é licenciado sob a licença **MIT** e incorpora componentes sob a licença **GPL-3.0** (devido ao uso de criptografia do `libsignal`).
14
+
15
+ ---
16
+
17
+ ## 🚀 Diferenciais e Correções da Áreum Tecnologia
18
+
19
+ O **WaSockets** foi criado para resolver problemas crônicos de estabilidade e adicionar recursos ausentes na versão original do Baileys. Abaixo estão as principais melhorias implementadas:
20
+
21
+ | Categoria | Recurso / Correção | Descrição |
22
+ | :--- | :--- | :--- |
23
+ | **Criptografia & Sessão** | Correção de descriptografia em grupos (`pn/lid mismatch`) | Corrige a falha crítica que impedia a descriptografia correta de mensagens quando a identidade de um participante alternava entre o número de telefone (PN) e o ID interno (LID). |
24
+ | **Criptografia & Sessão** | Descriptografia robusta de Enquetes/Eventos | Resolve o erro AES-GCM `Unsupported state or unable to authenticate data` garantindo que o autor original seja extraído do objeto de mensagem persistido. |
25
+ | **Estabilidade** | Versão Web Estabilizada | Integração com o protocolo Web `v2.3000.1038819500` e restauração da função `fetchLatestWaWebVersion` para buscar sempre a versão de compatibilidade mais recente e funcional do WhatsApp. |
26
+ | **Eventos** | Buffer de Eventos Corrigido | Adicionada a propriedade `shouldIncrementChatUnread` no buffer de eventos para garantir um controle preciso e confiável de mensagens não lidas no chat. |
27
+ | **Segurança** | Sessões de Autenticação Seguras | Remoção de adaptadores de autenticação inseguros/obsoletos (arquivo único ou MongoDB que causavam corrupção de estado), unificando e otimizando o uso do `useMultiFileAuthState`. |
28
+ | **Comunidades** | Suporte a Comunidades | Implementação nativa para escutar e processar comentários em canais de comunidades (`handle comment message`) e reações em comunidades. |
29
+ | **Eventos do WhatsApp** | Manipulação de Eventos e Respostas | Suporte a reações de edição de eventos (`handle event edit`) e decodificação das respostas de presença em eventos (`getAggregateResponsesInEventMessage`). |
30
+ | **Mídia** | Correções de Miniaturas e Status | Correção de falhas na extração de miniaturas (`extractImageThumb`), na geração de previews de links, no envio de mídias em álbuns/vídeos e na publicação de mídias em status de grupos. |
31
+ | **Newsletters (Canais)** | Consulta de Canais Inscritos | Adicionado o método exclusivo `newsletterSubscribed` que lista todos os canais de transmissão (Newsletters) aos quais o usuário está inscrito. |
32
+ | **Mensagens de Negócios** | Botões Interativos & PIX | Suporte avançado para layouts de botões interativos, botões Cards (com imagem/vídeo), suporte para botões PIX estáticos e fluxos completos de checkout e pagamento (`review_and_pay`). |
33
+
34
+ ---
35
+
36
+ ## 📌 Índice
37
+
38
+ - [Instalação](#-instalação)
39
+ - [Conectando a Conta](#-conectando-a-conta)
40
+ - [Conexão via QR Code](#conexão-via-qr-code)
41
+ - [Conexão via Código de Emparelhamento (Pairing Code)](#conexão-via-código-de-emparelhamento-pairing-code)
42
+ - [Recebendo Histórico Completo](#recebendo-histórico-completo)
43
+ - [Salvando e Restaurando Sessões](#-salvando-e-restaurando-sessões)
44
+ - [Configurações Importantes do Socket](#-configurações-importantes-do-socket)
45
+ - [Exemplo Prático Inicial (Bootstrap)](#-exemplo-prático-inicial-bootstrap)
46
+ - [Tratamento de Eventos](#-tratamento-de-eventos)
47
+ - [Decifrar Votos de Enquetes](#decifrar-votos-de-enquetes)
48
+ - [Decifrar Respostas de Eventos](#decifrar-respostas-de-eventos)
49
+ - [Enviando Mensagens](#-enviando-mensagens)
50
+ - [Mensagens de Texto e Menções](#mensagens-de-texto-e-menções)
51
+ - [Mensagens de Mídia](#mensagens-de-mídia)
52
+ - [Botões Interativos](#botões-interativos)
53
+ - [Botão de Pagamento PIX](#botão-de-pagamento-pix)
54
+ - [Fluxos de Checkout (PAY)](#fluxos-de-checkout-pay)
55
+ - [Menção em Status](#menção-em-status)
56
+ - [Modificando Mensagens e Chats](#-modificando-mensagens-e-chats)
57
+ - [Gerenciamento de Grupos](#-gerenciamento-de-grupos)
58
+ - [Newsletters (Canais)](#-newsletters-canais)
59
+ - [Configurações de Privacidade](#-configurações-de-privacidade)
60
+ - [Logs e Protocolo](#-logs-e-protocolo)
61
+
62
+ ---
63
+
64
+ ## 📦 Instalação
65
+
66
+ Adicione o pacote ao seu projeto via Yarn ou NPM:
67
+
68
+ **Versão Estável (Recomendado):**
69
+ ```bash
70
+ yarn add @areumtecnologia/wasockets
71
+ # ou
72
+ npm install @areumtecnologia/wasockets
73
+ ```
74
+
75
+ **Versão de Desenvolvimento (Edge):**
76
+ ```bash
77
+ yarn add github:areumtecnologia/WaSockets
78
+ ```
79
+
80
+ ---
81
+
82
+ ## 🔑 Conectando a Conta
83
+
84
+ O WhatsApp fornece uma API multi-dispositivo que permite ao **WaSockets** se autenticar como um segundo cliente web. Isso pode ser feito via **QR Code** ou **Código de Emparelhamento**.
85
+
86
+ ### Conexão via QR Code
87
+
88
+ ```javascript
89
+ const { default: makeWASocket, Browsers } = require('@areumtecnologia/wasockets')
90
+
91
+ const sock = makeWASocket({
92
+ // Configurações do navegador exibidas no WhatsApp do celular
93
+ browser: Browsers.ubuntu('Chrome'),
94
+ printQRInTerminal: true
95
+ })
96
+ ```
97
+
98
+ ### Conexão via Código de Emparelhamento (Pairing Code)
99
+
100
+ Ideal para servidores sem interface gráfica ou fluxos onde você não deseja escanear o QR Code, usando apenas o número do telefone. O número deve conter o código do país (ex: `55` para Brasil) e DDD, apenas com números.
101
+
102
+ ```javascript
103
+ const { default: makeWASocket } = require('@areumtecnologia/wasockets')
104
+
105
+ const sock = makeWASocket({
106
+ printQRInTerminal: false // Deve ser false
107
+ })
108
+
109
+ if (!sock.authState.creds.registered) {
110
+ const numeroTelefone = '5511999999999' // Insira o número completo
111
+ const codigo = await sock.requestPairingCode(numeroTelefone)
112
+ console.log(`Digite este código no seu WhatsApp: ${codigo}`)
113
+ }
114
+ ```
115
+
116
+ ### Recebendo Histórico Completo
117
+
118
+ Por padrão, a conexão emula um cliente leve. Para receber um histórico maior de mensagens anteriores, configure o navegador para emular um Desktop (macOS ou Windows) e ative a sincronização:
119
+
120
+ ```javascript
121
+ const sock = makeWASocket({
122
+ browser: Browsers.macOS('Desktop'),
123
+ syncFullHistory: true
124
+ })
125
+ ```
126
+
127
+ ---
128
+
129
+ ## 💾 Salvando e Restaurando Sessões
130
+
131
+ Para evitar a necessidade de escanear o QR Code a cada reinicialização, utilize a função `useMultiFileAuthState` para salvar as chaves de criptografia e credenciais em uma pasta local.
132
+
133
+ ```javascript
134
+ const { default: makeWASocket, useMultiFileAuthState } = require('@areumtecnologia/wasockets')
135
+
136
+ async function iniciar() {
137
+ // Carrega o estado da pasta especificada
138
+ const { state, saveCreds } = await useMultiFileAuthState('auth_info_baileys')
139
+
140
+ const sock = makeWASocket({
141
+ auth: state
142
+ })
143
+
144
+ // Salva as credenciais sempre que forem atualizadas
145
+ sock.ev.on('creds.update', saveCreds)
146
+ }
147
+ iniciar()
148
+ ```
149
+
150
+ > [!IMPORTANT]
151
+ > Quando mensagens são enviadas ou recebidas, as chaves de criptografia são atualizadas para segurança. É crucial que o evento `creds.update` chame a função `saveCreds` para persistir o novo estado. Caso contrário, a sessão será desconectada e as mensagens falharão.
152
+
153
+ ---
154
+
155
+ ## ⚙️ Configurações Importantes do Socket
156
+
157
+ ### 1. Cache de Metadados de Grupo (Altamente Recomendado)
158
+ Se a sua aplicação gerencia grupos, buscar metadados diretamente no WhatsApp para cada mensagem recebida causa lentidão e risco de banimento por limite de requisições. Implemente um cache temporário:
159
+
160
+ ```javascript
161
+ const NodeCache = require('@cacheable/node-cache') // ou similar
162
+ const groupCache = new NodeCache({ stdTTL: 5 * 60, useClones: false })
163
+
164
+ const sock = makeWASocket({
165
+ cachedGroupMetadata: async (jid) => groupCache.get(jid)
166
+ })
167
+
168
+ sock.ev.on('groups.update', async ([event]) => {
169
+ const metadata = await sock.groupMetadata(event.id)
170
+ groupCache.set(event.id, metadata)
171
+ })
172
+
173
+ sock.ev.on('group-participants.update', async (event) => {
174
+ const metadata = await sock.groupMetadata(event.id)
175
+ groupCache.set(event.id, metadata)
176
+ })
177
+ ```
178
+
179
+ ### 2. Recuperação de Mensagens e Enquetes
180
+ Para descriptografar respostas de enquetes antigas ou gerenciar tentativas de reenvio automáticas do WhatsApp, configure a função `getMessage`:
181
+
182
+ ```javascript
183
+ const sock = makeWASocket({
184
+ getMessage: async (key) => {
185
+ // Busque a mensagem salva no seu banco de dados ou store local
186
+ return await buscarMensagemSalva(key.id)
187
+ }
188
+ })
189
+ ```
190
+
191
+ ---
192
+
193
+ ## 🚀 Exemplo Prático Inicial (Bootstrap)
194
+
195
+ Aqui está um arquivo funcional completo em JavaScript (CommonJS) para iniciar a sua integração:
196
+
197
+ ```javascript
198
+ const { default: makeWASocket, DisconnectReason, useMultiFileAuthState } = require('@areumtecnologia/wasockets')
199
+ const { Boom } = require('@hapi/boom')
200
+
201
+ async function connectToWhatsApp() {
202
+ // 1. Inicializa o estado de autenticação baseado em arquivos
203
+ const { state, saveCreds } = await useMultiFileAuthState('./auth_info_baileys')
204
+
205
+ // 2. Cria o Socket de Conexão
206
+ const sock = makeWASocket({
207
+ auth: state,
208
+ printQRInTerminal: true
209
+ })
210
+
211
+ // 3. Monitora o status da conexão
212
+ sock.ev.on('connection.update', (update) => {
213
+ const { connection, lastDisconnect } = update
214
+
215
+ if (connection === 'close') {
216
+ const shouldReconnect = (lastDisconnect.error instanceof Boom)
217
+ ? lastDisconnect.error.output.statusCode !== DisconnectReason.loggedOut
218
+ : true
219
+
220
+ console.log('Conexão fechada devido a:', lastDisconnect.error, '. Reconectando:', shouldReconnect)
221
+
222
+ if (shouldReconnect) {
223
+ connectToWhatsApp() // Reconexão automática se não tiver feito logout
224
+ }
225
+ } else if (connection === 'open') {
226
+ console.log('Conexão com o WhatsApp estabelecida com sucesso!')
227
+ }
228
+ })
229
+
230
+ // 4. Salva credenciais atualizadas
231
+ sock.ev.on('creds.update', saveCreds)
232
+
233
+ // 5. Escuta e responde a novas mensagens recebidas
234
+ sock.ev.on('messages.upsert', async (event) => {
235
+ for (const m of event.messages) {
236
+ // Ignora mensagens que não sejam do tipo padrão ou geradas pelo próprio bot
237
+ if (!m.message || m.key.fromMe) continue
238
+
239
+ console.log('Mensagem recebida de:', m.key.remoteJid)
240
+ console.log('Conteúdo:', JSON.stringify(m, null, 2))
241
+
242
+ // Responde à mensagem
243
+ await sock.sendMessage(m.key.remoteJid, { text: 'Olá! Recebi sua mensagem com sucesso.' })
244
+ }
245
+ })
246
+ }
247
+
248
+ // Inicia o processo
249
+ connectToWhatsApp()
250
+ ```
251
+
252
+ ---
253
+
254
+ ## 📡 Tratamento de Eventos
255
+
256
+ O **WaSockets** utiliza um sistema de eventos tipado baseado no `EventEmitter`.
257
+
258
+ ```javascript
259
+ sock.ev.on('messages.upsert', ({ messages, type }) => {
260
+ // type pode ser 'notify' (nova notificação) ou 'append' (carregamento histórico)
261
+ console.log('Novas mensagens:', messages)
262
+ })
263
+ ```
264
+
265
+ ### Decifrar Votos de Enquetes
266
+
267
+ Os votos em enquetes chegam como mensagens criptografadas no evento `messages.update`. É preciso usar o helper `getAggregateVotesInPollMessage` passando a mensagem original da enquete.
268
+
269
+ ```javascript
270
+ const { getAggregateVotesInPollMessage } = require('@areumtecnologia/wasockets')
271
+
272
+ sock.ev.on('messages.update', async (updates) => {
273
+ for (const { key, update } of updates) {
274
+ if (update.pollUpdates) {
275
+ // 1. Busca a mensagem original da enquete que foi criada anteriormente
276
+ const pollCreationMessage = await obterMensagemSalva(key)
277
+ if (pollCreationMessage) {
278
+ // 2. Agrega os votos
279
+ const pollVotes = await getAggregateVotesInPollMessage({
280
+ message: pollCreationMessage,
281
+ pollUpdates: update.pollUpdates
282
+ })
283
+
284
+ // 3. Exibe as opções votadas e os respectivos eleitores
285
+ console.log('Resultado da Enquete Atualizado:', pollVotes)
286
+ }
287
+ }
288
+ }
289
+ })
290
+ ```
291
+
292
+ ### Decifrar Respostas de Eventos
293
+
294
+ A mesma lógica se aplica a eventos criados no chat (como convites de reuniões). O **WaSockets** fornece o helper `getAggregateResponsesInEventMessage` para analisar as presenças.
295
+
296
+ ```javascript
297
+ const { getAggregateResponsesInEventMessage } = require('@areumtecnologia/wasockets')
298
+
299
+ sock.ev.on('messages.update', async (updates) => {
300
+ for (const { key, update } of updates) {
301
+ if (update.eventResponses) {
302
+ const eventCreationMessage = await obterMensagemSalva(key)
303
+ if (eventCreationMessage) {
304
+ const responses = await getAggregateResponsesInEventMessage({
305
+ message: eventCreationMessage,
306
+ eventResponses: update.eventResponses
307
+ })
308
+ console.log('Respostas ao evento atualizadas:', responses)
309
+ }
310
+ }
311
+ }
312
+ })
313
+ ```
314
+
315
+ ---
316
+
317
+ ## ✉️ Enviando Mensagens
318
+
319
+ ### Mensagens de Texto e Menções
320
+
321
+ ```javascript
322
+ // Mensagem de texto simples
323
+ await sock.sendMessage(jid, { text: 'Olá Mundo!' })
324
+
325
+ // Mensagem citando (respondendo a) outra mensagem
326
+ await sock.sendMessage(jid, { text: 'Esta é uma resposta.' }, { quoted: mensagemOriginal })
327
+
328
+ // Mensagem mencionando contatos no grupo
329
+ await sock.sendMessage(jid, {
330
+ text: 'Olá @5511999999999 e @5511888888888!',
331
+ mentions: ['5511999999999@s.whatsapp.net', '5511888888888@s.whatsapp.net']
332
+ })
333
+ ```
334
+
335
+ ### Mensagens de Mídia
336
+
337
+ É possível passar caminhos de arquivos locais (`url`), links da internet (`url`), buffers ou streams de leitura.
338
+
339
+ ```javascript
340
+ const fs = require('fs')
341
+
342
+ // Imagem com legenda
343
+ await sock.sendMessage(jid, {
344
+ image: { url: './foto.jpg' }, // ou { url: 'https://example.com/foto.jpg' } ou Buffer
345
+ caption: 'Minha foto legal!'
346
+ })
347
+
348
+ // Álbum de mídias (Múltiplas fotos/vídeos no mesmo bloco)
349
+ await sock.sendMessage(jid, {
350
+ album: [
351
+ { image: { url: './foto1.jpg' }, caption: 'Foto 1' },
352
+ { image: { url: './foto2.jpg' }, caption: 'Foto 2' },
353
+ { video: { url: './video.mp4' }, caption: 'Vídeo do Álbum' }
354
+ ]
355
+ })
356
+
357
+ // GIF (vídeo mp4 simulado como reprodução contínua)
358
+ await sock.sendMessage(jid, {
359
+ video: fs.readFileSync('./video-gif.mp4'),
360
+ gifPlayback: true,
361
+ caption: 'Olha esse gif!'
362
+ })
363
+
364
+ // Áudio Gravado (Simula o gravador de voz do WhatsApp - PTT)
365
+ await sock.sendMessage(jid, {
366
+ audio: { url: './audio.ogg' },
367
+ mimetype: 'audio/mp4', // obrigatório
368
+ ptt: true // Define como mensagem de voz
369
+ })
370
+
371
+ // Mensagem de Visualização Única (View Once)
372
+ await sock.sendMessage(jid, {
373
+ image: { url: './foto.jpg' },
374
+ viewOnce: true,
375
+ caption: 'Esta foto desaparecerá após ser aberta!'
376
+ })
377
+ ```
378
+
379
+ > [!TIP]
380
+ > Para mensagens de áudio funcionarem perfeitamente em todos os dispositivos móveis e web, converta o áudio original para o formato OGG Opus (codec `libopus`) usando a ferramenta FFMpeg:
381
+ > `ffmpeg -i input.mp3 -c:a libopus -ac 1 -avoid_negative_ts make_zero output.ogg`
382
+
383
+ ---
384
+
385
+ ### Botões Interativos
386
+
387
+ Os botões nativos do WhatsApp são suportados através da propriedade `interactiveButtons`.
388
+
389
+ ```javascript
390
+ await sock.sendMessage(jid, {
391
+ text: 'Olá! Escolha uma das opções abaixo:',
392
+ title: 'Painel Interativo',
393
+ subtitle: 'Selecione com um clique',
394
+ footer: 'Áreum Tecnologia',
395
+ interactiveButtons: [
396
+ {
397
+ name: 'quick_reply',
398
+ buttonParamsJson: JSON.stringify({
399
+ display_text: 'Suporte Técnico',
400
+ id: 'btn_suporte'
401
+ })
402
+ },
403
+ {
404
+ name: 'cta_url',
405
+ buttonParamsJson: JSON.stringify({
406
+ display_text: 'Acessar Site',
407
+ url: 'https://areum.com.br',
408
+ merchant_url: 'https://areum.com.br'
409
+ })
410
+ },
411
+ {
412
+ name: 'cta_call',
413
+ buttonParamsJson: JSON.stringify({
414
+ display_text: 'Ligar Agora',
415
+ phone_number: '5511999999999'
416
+ })
417
+ }
418
+ ]
419
+ })
420
+ ```
421
+
422
+ ---
423
+
424
+ ### Botão de Pagamento PIX
425
+
426
+ O **WaSockets** permite o envio de chaves estáticas de PIX diretamente integradas na interface de pagamento nativa do WhatsApp pelo botão `payment_info`.
427
+
428
+ ```javascript
429
+ await sock.sendMessage(jid, {
430
+ text: 'Efetue o pagamento do pedido abaixo clicando em Pagar:',
431
+ interactiveButtons: [
432
+ {
433
+ name: 'payment_info',
434
+ buttonParamsJson: JSON.stringify({
435
+ payment_settings: [{
436
+ type: 'pix_static_code',
437
+ pix_static_code: {
438
+ merchant_name: 'Áreum Tecnologia LTDA',
439
+ key: 'financeiro@areum.com.br', // Chave PIX (E-mail, CPF/CNPJ, Telefone ou EVP)
440
+ key_type: 'EMAIL' // Tipos suportados: PHONE, EMAIL, CPF, EVP
441
+ }
442
+ }]
443
+ })
444
+ }
445
+ ]
446
+ })
447
+ ```
448
+
449
+ ---
450
+
451
+ ### Fluxos de Checkout (PAY)
452
+
453
+ É possível enviar solicitações de checkout com itens detalhados de faturamento para pagamentos eletrônicos integrados no aplicativo através da ação `review_and_pay`.
454
+
455
+ ```javascript
456
+ await sock.sendMessage(jid, {
457
+ text: 'Fatura gerada com sucesso!',
458
+ interactiveButtons: [
459
+ {
460
+ name: 'review_and_pay',
461
+ buttonParamsJson: JSON.stringify({
462
+ currency: 'BRL',
463
+ payment_type: 'physical-goods',
464
+ total_amount: {
465
+ value: '15000', // R$ 150,00 (representado sem decimais, multiplicado pelo offset)
466
+ offset: '100'
467
+ },
468
+ reference_id: 'REF_PEDIDO_12345',
469
+ payment_method: 'confirm',
470
+ payment_status: 'captured',
471
+ payment_timestamp: Math.floor(Date.now() / 1000),
472
+ order: {
473
+ status: 'completed',
474
+ order_type: 'PAYMENT_REQUEST',
475
+ subtotal: { value: '15000', offset: '100' },
476
+ items: [{
477
+ retailer_id: 'item_01',
478
+ name: 'Licença Anual WaSockets',
479
+ amount: { value: '15000', offset: '100' },
480
+ quantity: '1'
481
+ }]
482
+ },
483
+ additional_note: 'Agradecemos a sua preferência!'
484
+ })
485
+ }
486
+ ]
487
+ })
488
+ ```
489
+
490
+ ---
491
+
492
+ ### Menção em Status
493
+
494
+ Permite publicar status (stories) e marcar diretamente contatos/grupos específicos (máximo de 5 menções por status).
495
+
496
+ ```javascript
497
+ const contatosParaMencionar = [
498
+ '5511999999999@s.whatsapp.net',
499
+ '5511888888888@s.whatsapp.net'
500
+ ]
501
+
502
+ // Envia um status em formato de texto mencionando os contatos acima
503
+ await sock.sendStatusMentions(
504
+ {
505
+ text: 'Novidade incrível para vocês! 🚀',
506
+ backgroundColor: '#1c1c1c',
507
+ textColor: '#ffffff'
508
+ },
509
+ contatosParaMencionar
510
+ )
511
+ ```
512
+
513
+ ---
514
+
515
+ ## 📝 Modificando Mensagens e Chats
516
+
517
+ ```javascript
518
+ // Apagar uma mensagem para todos
519
+ const msg = await sock.sendMessage(jid, { text: 'Mensagem enviada com erro!' })
520
+ await sock.sendMessage(jid, { delete: msg.key })
521
+
522
+ // Editar uma mensagem enviada
523
+ await sock.sendMessage(jid, {
524
+ text: 'Esta é a mensagem com o texto corrigido.',
525
+ edit: msg.key
526
+ })
527
+
528
+ // Arquivar um chat
529
+ await sock.chatModify({ archive: true, lastMessages: [msg] }, jid)
530
+
531
+ // Silenciar um chat por 8 horas
532
+ await sock.chatModify({ mute: 8 * 60 * 60 * 1000 }, jid)
533
+
534
+ // Remover silenciamento de um chat
535
+ await sock.chatModify({ mute: null }, jid)
536
+
537
+ // Marcar chat como Não Lido
538
+ await sock.chatModify({ markRead: false, lastMessages: [msg] }, jid)
539
+
540
+ // Fixar chat na lista
541
+ await sock.chatModify({ pin: true }, jid)
542
+ ```
543
+
544
+ ---
545
+
546
+ ## 👥 Gerenciamento de Grupos
547
+
548
+ As operações de alteração estrutural em grupos requerem que a conta conectada seja administradora do grupo correspondente.
549
+
550
+ ```javascript
551
+ // Criar um novo grupo
552
+ const grupo = await sock.groupCreate('Equipe de Suporte Áreum', ['5511999999999@s.whatsapp.net'])
553
+ console.log('Grupo criado com ID:', grupo.id)
554
+
555
+ // Adicionar/Remover/Promover participantes
556
+ // Parâmetros de ação: 'add' | 'remove' | 'promote' | 'demote'
557
+ await sock.groupParticipantsUpdate(grupo.id, ['5511888888888@s.whatsapp.net'], 'add')
558
+
559
+ // Obter o código/link de convite do grupo
560
+ const codigoConvite = await sock.groupInviteCode(grupo.id)
561
+ console.log(`Link: https://chat.whatsapp.com/${codigoConvite}`)
562
+
563
+ // Revogar link de convite anterior e gerar um novo
564
+ const novoCodigo = await sock.groupRevokeInvite(grupo.id)
565
+
566
+ // Entrar em um grupo usando um código de convite (apenas o código, sem o domínio completo)
567
+ const resposta = await sock.groupAcceptInvite('ABcdEFghIJklMnOpQrStUv')
568
+
569
+ // Obter a lista de pessoas aguardando aprovação para entrar no grupo
570
+ const solicitacoes = await sock.groupRequestParticipantsList(grupo.id)
571
+ console.log(solicitacoes)
572
+
573
+ // Aprovar entrada pendente
574
+ await sock.groupRequestParticipantsUpdate(grupo.id, ['5511777777777@s.whatsapp.net'], 'approve') // ou 'reject'
575
+
576
+ // Obter metadados do grupo (participantes, título, regras, descrição)
577
+ const metadados = await sock.groupMetadata(grupo.id)
578
+ console.log(`Título: ${metadados.subject}, Membros: ${metadados.participants.length}`)
579
+ ```
580
+
581
+ ---
582
+
583
+ ## 📢 Newsletters (Canais)
584
+
585
+ O **WaSockets** traz suporte avançado para a criação e monitoramento de Newsletters (Canais de Transmissão públicos do WhatsApp).
586
+
587
+ ```javascript
588
+ // Criar uma Newsletter (Canal)
589
+ const canal = await sock.newsletterCreate('Notícias Tecnológicas Áreum', 'Canal oficial de novidades')
590
+ console.log('Canal criado com ID:', canal.id)
591
+
592
+ // Obter metadados de um Canal público pelo ID
593
+ const metadadosCanal = await sock.newsletterMetadata('JID', canal.id)
594
+ console.log('Nome do Canal:', metadadosCanal.name)
595
+
596
+ // Listar todas as Newsletters em que a conta atual está inscrita (Exclusivo Áreum!)
597
+ const canaisInscritos = await sock.newsletterSubscribed()
598
+ console.log('Canais que eu sigo:', canaisInscritos)
599
+
600
+ // Seguir / Parar de Seguir um canal
601
+ await sock.newsletterFollow(canal.id)
602
+ await sock.newsletterUnfollow(canal.id)
603
+
604
+ // Silenciar / Ativar notificações de um canal
605
+ await sock.newsletterMute(canal.id)
606
+ await sock.newsletterUnmute(canal.id)
607
+ ```
608
+
609
+ ---
610
+
611
+ ## 🔒 Configurações de Privacidade
612
+
613
+ ```javascript
614
+ // Bloquear ou desbloquear um usuário
615
+ await sock.updateBlockStatus('5511999999999@s.whatsapp.net', 'block') // ou 'unblock'
616
+
617
+ // Obter lista de usuários bloqueados
618
+ const listaBloqueados = await sock.fetchBlocklist()
619
+
620
+ // Atualizar privacidade do "Visto por Último"
621
+ // Valores aceitos: 'all' | 'contacts' | 'contact_blacklist' | 'none'
622
+ await sock.updateLastSeenPrivacy('contacts')
623
+
624
+ // Atualizar privacidade do "Visto Online"
625
+ // Valores aceitos: 'all' | 'match_last_seen'
626
+ await sock.updateOnlinePrivacy('match_last_seen')
627
+
628
+ // Atualizar privacidade das confirmações de leitura (ticks azuis)
629
+ // Valores aceitos: 'all' | 'none'
630
+ await sock.updateReadReceiptsPrivacy('none')
631
+ ```
632
+
633
+ ---
634
+
635
+ ## 🛡️ Logs e Protocolo
636
+
637
+ Para habilitar a depuração detalhada e ver o tráfego bruto do Websocket trocado com o WhatsApp, inicialize o logger no nível `debug` ou `trace`. O **WaSockets** usa a biblioteca estruturada `pino` para logs ultra rápidos:
638
+
639
+ ```javascript
640
+ const pino = require('pino')
641
+
642
+ const sock = makeWASocket({
643
+ logger: pino({ level: 'debug' })
644
+ })
645
+ ```
646
+
647
+ ### Como o WhatsApp se comunica (BinaryNodes)
648
+
649
+ As mensagens são trocadas em formato binário encapsuladas em estruturas chamadas `BinaryNode`. Cada nó possui três atributos:
650
+ - **`tag`**: Nome da ação (ex: `message`, `ib`, `presence`, `iq`)
651
+ - **`attrs`**: Objeto contendo propriedades em string/chave-valor (ID, timestamp, remetente, etc.)
652
+ - **`content`**: O corpo de dados do nó (geralmente outro array de nós ou um buffer criptografado)
653
+
654
+ Você pode interagir diretamente com o tráfego do Websocket do WhatsApp registrando callbacks específicos:
655
+
656
+ ```javascript
657
+ // Monitora todos os pacotes recebidos que possuem a tag 'edge_routing'
658
+ sock.ws.on('CB:edge_routing', (node) => {
659
+ console.log('Recebido nó de roteamento:', node)
660
+ })
661
+
662
+ // Monitora pacotes 'message' específicos
663
+ sock.ws.on('CB:message', (node) => {
664
+ console.log('Mensagem de protocolo bruta:', node)
665
+ })
666
+ ```