whatsapp api multidevice by ChatUnity

#### Responsibility and License Information
The developers of Baileys and its maintainers cannot be held responsible for misuse of the application, as indicated in the MIT License.
The team does not approve any use that violates WhatsApp's Terms of Service. Every user is invited to act responsibly and use the tool only for its intended purposes.
##
- Baileys does not require Selenium or any browser to work with WhatsApp Web: it uses a WebSocket directly.
- Avoiding Selenium or Chromium saves approximately half a gigabyte of RAM.
- Baileys supports both the multi-device version and the web version of WhatsApp.
> [!IMPORTANT]
> The original repository was removed by the main author – development continues officially in this new community-maintained version.
This project is based on Baileys by
@rexxhayanasi / elaina-baileys.
Special thanks for the open-source work and contributions.
You can check out and run the example available in example.ts to see practical usage of the library.
The script demonstrates the most common use cases.
To run it:
1. ``cd path/to/Baileys``
2. yarn``
3. yarn example`
Use the stable version:
``
yarn add @chatunitycenter/baileys
Use the edge version (no guarantee of stability, but latest fixes + features)
``
yarn add github:chatunitycenter/baileys
Then import in your code using:
`ts `
import makeWASocket from '@chatunitycenter/baileys'
WhatsApp provides a multi-device system that allows Baileys to authenticate as a second WhatsApp client via QR code or Pairing Code scanned from the app on your phone.
> [!NOTE]
> Here you'll find a simple event handling example
> [!TIP]
> You can view all supported socket configurations here (Recommended)
> [!TIP]
> If you connect via QR-CODE, you can customize the browser name using the Browser constant. Several predefined configurations are available, viewable here.
`ts
import makeWASocket from '@chatunitycenter/baileys'
const sock = makeWASocket({
browser: Browsers.ubuntu('My App'),
printQRInTerminal: true
})
`
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!
> [!IMPORTANT]
> Pairing Code is not Mobile API; it's a method to connect WhatsApp Web without QR-CODE. You can only connect with one device, see here
The phone number cannot have +, (), or -, only numbers. You must provide country code.
`ts
import makeWASocket from '@chatunitycenter/baileys'
const chatunity = makeWASocket({
printQRInTerminal: false // must be false
})
if (!chatunity.authState.creds.registered) {
const number = 'XXXXXXXXXXX'
const code = await chatunity.requestPairingCode(number)
console.log(code)
}
`
1. Set syncFullHistory to true
2. Use a desktop browser configuration to receive more message history:
`ts`
const chatunity = makeWASocket({
browser: Browsers.macOS('Desktop'),
syncFullHistory: true
})
If you use Baileys for groups, we recommend setting cachedGroupMetadata in socket config:
`ts
const groupCache = new NodeCache({stdTTL: 5 * 60, useClones: false})
const chatunity = makeWASocket({
cachedGroupMetadata: async (jid) => groupCache.get(jid)
})
chatunity.ev.on('groups.update', async ([event]) => {
const metadata = await chatunity.groupMetadata(event.id)
groupCache.set(event.id, metadata)
})
chatunity.ev.on('group-participants.update', async (event) => {
const metadata = await chatunity.groupMetadata(event.id)
groupCache.set(event.id, metadata)
})
`
To improve message sending, retrying on errors, and decrypt poll votes, set up a store with getMessage config:
`ts`
const chatunity = makeWASocket({
getMessage: async (key) => await getMessageFromStore(key)
})
To receive notifications in the WhatsApp app, set markOnlineOnConnect to false:
`ts`
const chatunity = makeWASocket({
markOnlineOnConnect: false
})
You don't need to scan the QR code every time you connect. Load credentials to log back in:
`ts
import makeWASocket, { useMultiFileAuthState } from '@chatunitycenter/baileys'
const { state, saveCreds } = await useMultiFileAuthState('auth_info_baileys')
const chatunity = makeWASocket({ auth: state })
chatunity.ev.on('creds.update', saveCreds)
`
> [!IMPORTANT]
> useMultiFileAuthState is a utility function to help save the auth state in a folder. This serves as a good guide for implementing auth & key states for SQL/NoSQL databases, which is recommended for production systems.
> [!NOTE]
> When messages are received/sent, auth keys need updating. You must save updated keys. The useMultiFileAuthState function handles this automatically, but for other implementations you must be careful with key state management.
`ts
import makeWASocket, { useSingleFileAuthState, useMongoFileAuthState } from '@chatunitycenter/baileys'
// Single File Auth
const { state, saveState } = await useSingleFileAuthState('./auth_info_baileys.json')
const chatunity = makeWASocket({ auth: state, printQRInTerminal: true })
chatunity.ev.on('creds.update', saveState)
// MongoDB Auth
import { MongoClient } from "mongodb"
const connectAuth = async() => {
const client = new MongoClient('mongoURL')
await client.connect()
const collection = client.db("@itchatunitychann").collection("sessions")
return collection
}
const Authentication = await connectAuth()
const { state, saveCreds } = await useMongoFileAuthState(Authentication)
const chatunity = makeWASocket({ auth: state, printQRInTerminal: true })
chatunity.ev.on('creds.update', saveCreds)
`
Baileys uses the EventEmitter syntax for events with full TypeScript support.
> [!IMPORTANT]
> See all available events here
`ts`
const chatunity = makeWASocket()
chatunity.ev.on('messages.upsert', ({ messages }) => {
console.log('got messages', messages)
})
`ts
import makeWASocket, { DisconnectReason, useMultiFileAuthState } from '@chatunitycenter/baileys'
import { Boom } from '@hapi/boom'
async function connectToWhatsApp () {
const { state, saveCreds } = await useMultiFileAuthState('./auth_info_baileys')
const chatunity = makeWASocket({
auth: state,
printQRInTerminal: true
})
chatunity.ev.on('connection.update', (update) => {
const { connection, lastDisconnect } = update
if(connection === 'close') {
const shouldReconnect = (lastDisconnect.error as Boom)?.output?.statusCode !== DisconnectReason.loggedOut
console.log('connection closed due to ', lastDisconnect.error, ', reconnecting ', shouldReconnect)
if(shouldReconnect) {
connectToWhatsApp()
}
} else if(connection === 'open') {
console.log('opened connection')
}
})
chatunity.ev.on('messages.upsert', event => {
for (const m of event.messages) {
console.log(JSON.stringify(m, undefined, 2))
console.log('replying to', m.key.remoteJid)
await chatunity.sendMessage(m.key.remoteJid!, { text: 'Hello World' })
}
})
chatunity.ev.on('creds.update', saveCreds)
}
connectToWhatsApp()
`
> [!IMPORTANT]
> In messages.upsert, use a loop like for (const message of event.messages) to handle all messages in the array.
Poll votes are encrypted by default and handled in messages.update:
`ts
import pino from "pino"
import { makeInMemoryStore, getAggregateVotesInPollMessage } from '@chatunitycenter/baileys'
const logger = pino({ timestamp: () => ,"time":"${new Date().toJSON()}" }).child({ class: "@Itchatunitychann" })
logger.level = "fatal"
const store = makeInMemoryStore({ logger })
async function getMessage(key){
if (store) {
const msg = await store.loadMessage(key.remoteJid, key.id)
return msg?.message
}
return { conversation: "Itchatunityi Kawaiii" }
}
chatunity.ev.on("messages.update", async (chatUpdate) => {
for(const { key, update } of chatUpdate) {
if(update.pollUpdates && key.fromMe) {
const pollCreation = await getMessage(key)
if(pollCreation) {
const pollUpdate = await getAggregateVotesInPollMessage({
message: pollCreation,
pollUpdates: update.pollUpdates,
})
const toCmd = pollUpdate.filter(v => v.voters.length !== 0)[0]?.name
if (toCmd == undefined) return
console.log(toCmd)
}
}
}
})
`
Event responses are encrypted by default and handled in messages.update:
`ts
import { jidNormalizedUser, getAggregateResponsesInEventMessage } from '@chatunitycenter/baileys'
chatunity.ev.on("messages.update", async ([chatUpdate]) => {
const eventResponses = chatUpdate.update?.eventResponses
const agregate = getAggregateResponsesInEventMessage({ eventResponses }, jidNormalizedUser(chatunity.user.lid))
console.log(agregate)
})
`
1. connection.update is fired requesting socket restartmessaging.history-set
2. History messages are received in
Baileys does not include built-in storage for chats, contacts, or messages. However, a simple in-memory implementation is provided:
> [!IMPORTANT]
> We highly recommend building your own data store, as storing entire chat history in memory wastes RAM.
`ts
import makeWASocket, { makeInMemoryStore } from '@chatunitycenter/baileys'
const store = makeInMemoryStore({ })
store.readFromFile('./baileys_store.json')
setInterval(() => {
store.writeToFile('./baileys_store.json')
}, 10_000)
const chatunity = makeWASocket({ })
store.bind(chatunity.ev)
chatunity.ev.on('chats.upsert', () => {
console.log('got chats', store.chats.all())
})
chatunity.ev.on('contacts.upsert', () => {
console.log('got contacts', Object.values(store.contacts))
})
`
- id (also called jid) is the WhatsApp ID of the person or group you're messaging.`
- Format for people: [country code][phone number]@s.whatsapp.net``
- Example: +19999999999@s.whatsapp.net``
- Format for groups: 123456789-123345@g.us `[timestamp of creation]@broadcast
- Broadcast lists: status@broadcast
- Stories:
- getContentType - returns the content type for any messagegetDevice
- - returns the device from a messagemakeCacheableSignalKeyStore
- - speeds up auth storedownloadContentFromMessage
- - downloads content from any message
Send all types of messages with a single function:
- All message contents
- All options
`ts`
await chatunity.sendMessage(jid, content, options)
#### Text Message
`ts`
await chatunity.sendMessage(jid, { text: 'hello world' })
#### Quote Message
`ts`
await chatunity.sendMessage(jid, { text: 'hello world' }, { quoted: message })
#### Mention User
`ts`
await chatunity.sendMessage(jid, {
text: '@12345678901',
mentions: ['12345678901@s.whatsapp.net']
})
#### Forward Messages
`ts`
const msg = getMessageFromStore()
await chatunity.sendMessage(jid, { forward: msg, force: true })
#### Location Message
`ts`
await chatunity.sendMessage(jid, {
location: {
degreesLatitude: 24.121231,
degreesLongitude: 55.1121221
}
})
#### Live Location Message
`ts`
await chatunity.sendMessage(jid, {
location: {
degreesLatitude: 24.121231,
degreesLongitude: 55.1121221
},
live: true
})
#### Contact Message
`ts
const vcard = 'BEGIN:VCARD\n'
+ 'VERSION:3.0\n'
+ 'FN:Jeff Singh\n'
+ 'ORG:Ashoka Uni\n'
+ 'TEL;type=CELL;type=VOICE;waid=911234567890:+91 12345 67890\n'
+ 'END:VCARD'
await chatunity.sendMessage(id, {
contacts: {
displayName: 'Itchatunitychann',
contacts: [{ vcard }]
}
})
`
#### Reaction Message
`ts`
await chatunity.sendMessage(jid, {
react: {
text: '💖',
key: message.key
}
})
#### Pin Message
`ts`
await chatunity.sendMessage(jid, {
pin: {
type: 1, // 2 to remove
time: 86400, // 24h in seconds
key: Key
}
})
#### Keep Message
`ts`
await chatunity.sendMessage(jid, {
keep: {
key: Key,
type: 1
}
})
#### Poll Message
`ts`
await chatunity.sendMessage(jid, {
poll: {
name: 'My Poll',
values: ['Option 1', 'Option 2'],
selectableCount: 1,
toAnnouncementGroup: false
}
})
#### Poll Result Message
`ts`
await chatunity.sendMessage(jid, {
pollResult: {
name: 'Hi',
values: [['Option 1', 1000], ['Option 2', 2000]]
}
})
#### Call Message
`ts`
await chatunity.sendMessage(jid, {
call: {
name: 'Hey',
type: 1 // 2 for video
}
})
#### Event Message
`ts`
await chatunity.sendMessage(jid, {
event: {
isCanceled: false,
name: 'Holiday together!',
description: 'Who wants to come along?',
location: {
degreesLatitude: 24.121231,
degreesLongitude: 55.1121221,
name: 'Location name'
},
call: 'audio',
startTime: number,
endTime: number,
extraGuestsAllowed: true
}
})
#### Order Message
`ts`
await chatunity.sendMessage(jid, {
order: {
orderId: '574xxx',
thumbnail: 'your_thumbnail',
itemCount: 'your_count',
status: 'INQUIRY',
surface: 'CATALOG',
message: 'your_caption',
orderTitle: "your_title",
sellerJid: 'your_jid',
token: 'your_token',
totalAmount1000: 'your_amount',
totalCurrencyCode: 'IDR'
}
})
#### Product Message
`ts`
await chatunity.sendMessage(jid, {
product: {
productImage: { url: 'your_url' },
productId: 'your_id',
title: 'your_title',
description: 'your_description',
currencyCode: 'IDR',
priceAmount1000: 'your_amount',
url: 'your_url',
productImageCount: 'your_imageCount'
},
businessOwnerJid: 'your_jid'
})
#### Payment Message
`ts`
await chatunity.sendMessage(jid, {
payment: {
note: 'Hi!',
currency: 'IDR',
amount: '10000',
expiry: 0
}
})
#### Payment Invite Message
`ts`
await chatunity.sendMessage(id, {
paymentInvite: {
type: 1,
expiry: 0
}
})
#### Admin Invite Message
`ts`
await chatunity.sendMessage(jid, {
adminInvite: {
jid: '123xxx@newsletter',
name: 'newsletter_name',
caption: 'Please be my channel admin',
expiration: 86400
}
})
#### Group Invite Message
`ts`
await chatunity.sendMessage(jid, {
groupInvite: {
jid: '123xxx@g.us',
name: 'group_name',
caption: 'Please Join My WhatsApp Group',
code: 'code_invite',
expiration: 86400
}
})
#### Sticker Pack Message
`ts`
await chatunity.sendMessage(jid, {
stickerPack: {
name: 'Hiii',
publisher: 'By Itchatunitychann',
description: 'Hello',
cover: Buffer,
stickers: [{
sticker: { url: 'https://example.com/1234kjd.webp' },
emojis: ['❤'],
isLottie: false,
isAnimated: false
}]
}
})
#### Share Phone Number Message
`ts`
await chatunity.sendMessage(jid, { sharePhoneNumber: {} })
#### Request Phone Number Message
`ts`
await chatunity.sendMessage(jid, { requestPhoneNumber: {} })
#### Button Reply Message
`ts
// List
await chatunity.sendMessage(jid, {
buttonReply: {
name: 'Hi',
description: 'description',
rowId: 'ID'
},
type: 'list'
})
// Plain
await chatunity.sendMessage(jid, {
buttonReply: {
displayText: 'Hi',
id: 'ID'
},
type: 'plain'
})
// Template
await chatunity.sendMessage(jid, {
buttonReply: {
displayText: 'Hi',
id: 'ID',
index: 'number'
},
type: 'template'
})
// Interactive
await chatunity.sendMessage(jid, {
buttonReply: {
body: 'Hi',
nativeFlows: {
name: 'menu_options',
paramsJson: JSON.stringify({ id: 'ID', description: 'description' }),
version: 1
}
},
type: 'interactive'
})
`
#### Buttons Message
`ts`
await chatunity.sendMessage(jid, {
text: 'This is a button message!',
footer: 'Hello World!',
buttons: [{
buttonId: 'Id1',
buttonText: { displayText: 'Button 1' }
}, {
buttonId: 'Id2',
buttonText: { displayText: 'Button 2' }
}]
})
#### Buttons List Message
`ts`
await chatunity.sendMessage(jid, {
text: 'This is a list!',
footer: 'Hello World!',
title: 'Amazing list title',
buttonText: 'View list',
sections: [{
title: 'Section 1',
rows: [{
title: 'Option 1',
rowId: 'option1'
}, {
title: 'Option 2',
rowId: 'option2',
description: 'Description'
}]
}]
})
#### Buttons Product List Message
`ts`
await chatunity.sendMessage(jid, {
text: 'This is a list!',
footer: 'Hello World!',
title: 'Product list',
buttonText: 'View list',
productList: [{
title: 'This is a title',
products: [{ productId: '1234' }, { productId: '5678' }]
}],
businessOwnerJid: '628xxx@s.whatsapp.net',
thumbnail: 'https://example.com/image.jpg'
})
#### Buttons Cards Message
`ts`
await chatunity.sendMessage(jid, {
text: 'Body Message',
title: 'Title Message',
cards: [{
image: { url: 'https://example.com/image.jpg' },
title: 'Card Title',
body: 'Card Body',
footer: 'Card Footer',
buttons: [{
name: 'quick_reply',
buttonParamsJson: JSON.stringify({
display_text: 'Button',
id: 'ID'
})
}]
}]
})
#### Buttons Interactive Message
`ts`
await chatunity.sendMessage(jid, {
text: 'Interactive message',
title: 'Title',
footer: 'Footer',
interactiveButtons: [
{
name: 'quick_reply',
buttonParamsJson: JSON.stringify({
display_text: 'Click Me!',
id: 'your_id'
})
},
{
name: 'cta_url',
buttonParamsJson: JSON.stringify({
display_text: 'Follow',
url: 'https://whatsapp.com/channel/0029Vag9VSI2ZjCocqa2lB1y'
})
},
{
name: 'cta_call',
buttonParamsJson: JSON.stringify({
display_text: 'Call',
phone_number: '628xxx'
})
},
{
name: 'open_webview',
buttonParamsJson: JSON.stringify({
title: 'Follow',
link: { url: 'https://example.com' }
})
}
]
})
#### Buttons Interactive Message PIX
`ts`
await chatunity.sendMessage(jid, {
text: '',
interactiveButtons: [{
name: 'payment_info',
buttonParamsJson: JSON.stringify({
payment_settings: [{
type: "pix_static_code",
pix_static_code: {
merchant_name: 'Your Name',
key: 'example@email.com',
key_type: 'EMAIL'
}
}]
})
}]
})
#### Buttons Interactive Message PAY
`ts`
await chatunity.sendMessage(jid, {
text: '',
interactiveButtons: [{
name: 'review_and_pay',
buttonParamsJson: JSON.stringify({
currency: 'IDR',
total_amount: { value: '999999999', offset: '100' },
reference_id: '45XXXXX',
type: 'physical-goods',
order: {
status: 'completed',
items: [{
name: 'Product',
amount: { value: '999999999', offset: '100' },
quantity: '1'
}]
}
})
}]
})
#### Status Mentions Message
`ts
const jids = ['123451679@g.us', '62689xxxx@s.whatsapp.net']
// Text
await chatunity.sendStatusMentions(
{
text: 'Hello Everyone :3',
font: 2
},
jids
)
// Image
await chatunity.sendStatusMentions(
{ image: { url: 'https://example.com/image.jpg' } },
jids
)
// Video
await chatunity.sendStatusMentions(
{ video: { url: 'https://example.com/video.mp4' } },
jids
)
`
#### Shop Message
`ts`
await chatunity.sendMessage(jid, {
text: 'Body',
title: 'Title',
footer: 'Footer',
shop: {
surface: 1,
id: 'https://example.com'
},
viewOnce: true
})
#### Collection Message
`ts`
await chatunity.sendMessage(jid, {
text: 'Body',
title: 'Title',
footer: 'Footer',
collection: {
bizJid: 'jid',
id: 'https://example.com',
version: 1
},
viewOnce: true
})
Sending media (video, stickers, images) is easier and more efficient.
> [!NOTE]
> You can pass { stream: Stream }, { url: Url }, or Buffer directly. See more here
> [!TIP]
> Use Stream or Url to save memory
#### GIF Message
`ts`
await chatunity.sendMessage(jid, {
video: fs.readFileSync('Media/gif.mp4'),
caption: 'hello world',
gifPlayback: true
})
#### Video Message
`ts`
await chatunity.sendMessage(id, {
video: { url: './Media/video.mp4' },
caption: 'hello world'
})
#### Video PTV Message
`ts`
await chatunity.sendMessage(id, {
video: { url: './Media/video.mp4' },
ptv: true
})
#### Audio Message
Audio needs to be converted to OGG format with ffmpeg:
`bash`
ffmpeg -i input.mp4 -avoid_negative_ts make_zero -ac 1 output.ogg
`ts`
await chatunity.sendMessage(jid, {
audio: { url: './Media/audio.mp3' },
mimetype: 'audio/mp4'
})
#### Image Message
`ts`
await chatunity.sendMessage(id, {
image: { url: './Media/image.png' },
caption: 'hello world'
})
#### Album Message
`ts`
await chatunity.sendMessage(id, {
album: [{
image: { url: 'https://example.com/image.jpg' },
caption: 'Caption'
}, {
video: { url: 'https://example.com/video.mp4' },
caption: 'Caption'
}]
})
#### View Once Message
`ts`
await chatunity.sendMessage(id, {
image: { url: './Media/image.png' },
viewOnce: true,
caption: 'hello world'
})
By default, WhatsApp does not generate link previews when sent from web. Baileys provides this functionality.
To enable link previews, add link-preview-js to your project:`bash`
yarn add link-preview-js
Then send a link:
`ts`
await chatunity.sendMessage(jid, {
text: 'Hi, this was sent using https://github.com/whiskeysockets/baileys'
})
ts
await chatunity.sendMessage(jid, { text: 'Hi' }, { ai: true })// With relay
await chatunity.relayMessage(jid, { extendedTextMessage: { text: 'Hi' } }, { AI: true })
`Modifying Messages
$3
`ts
const msg = await chatunity.sendMessage(jid, { text: 'hello world' })
await chatunity.sendMessage(jid, { delete: msg.key })
`$3
`ts
await chatunity.sendMessage(jid, { edit: msg.key, text: 'edited message' })
`Working with Media
$3
Thumbnails can be generated automatically for images & stickers if you add
jimp or sharp:
`bash
yarn add jimp
or
yarn add sharp
`For videos, install
ffmpeg on your system.$3
`ts
import { createWriteStream } from 'fs'
import { downloadMediaMessage, getContentType } from '@chatunitycenter/baileys'chatunity.ev.on('messages.upsert', async ({ messages }) => {
for (const m of messages) {
if (!m.message) return
const messageType = getContentType(m)
if (messageType === 'imageMessage') {
const stream = await downloadMediaMessage(m, 'stream', {}, {
logger,
reuploadRequest: chatunity.updateMediaMessage
})
stream.pipe(createWriteStream('./my-download.jpeg'))
}
}
})
`$3
`ts
const downloadedContent = await downloadMediaMessage(...)
const uploadedUrl = await chatunity.uploadMedia(downloadedContent)
``- Connecting Account
- Connect with QR-CODE
- Connect with Pairing Code
- Receive Full History
- Socket Configuration
- Cache Group Metadata
- Improve Retry System & Decrypt Poll Votes
- Receive Notifications in WhatsApp App
- Saving & Restoring Sessions
- Handling Events
- Example to Start
- Decrypt Poll Votes
- Decrypt Event Response
- Summary of Events on First Connection
- Implementing a Data Store
- WhatsApp IDs Explained
- Utility Functions
- Sending Messages
- Non-Media Messages
- Media Messages
- Link Previews
- Modifying Messages
- Delete Messages
- Edit Messages
- Working with Media
- Thumbnails
- Downloading Media
- Re-uploading Media
- Chat Management
- Read States
- Presence
- Modifying Chats
- User Queries
- Profile Management
- Groups
- Privacy
- Broadcast Lists & Stories
- Advanced Usage