@chatunity/baileys
v3.0.10
Published
whatsapp api multidevice by ChatUnity
Maintainers
Readme
ChatUnity Baileys - TypeScript & Node.js Based
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.
🚀 Features
- No Selenium/Chromium - Uses WebSocket directly, saving ~500MB RAM
- Multi-device Support - Works with both WhatsApp Web and multi-device versions
- Production Ready - 7 defensive systems for stability, security, and performance
- Zero Breaking Changes - 100% backward compatible with Baileys v1.0.5
- TypeScript Support - Fully typed with complete .d.ts files
- Zero Dependencies - Uses only Node.js native modules
[!IMPORTANT]
This is the official ChatUnity-maintained community version. The original repository was archived – development continues here.
[!WARNING]
Starting from 3.0.10,key.fromMeis no longer used for authentication, owner, sudo, or admin checks. Use the identity helpers andserializeMessageinstead. See SECURITY_IDENTITY.md.
✨ What's New in 3.0.10
Identity & LID/Username Fix
- Centralized identity layer in
lib/Utils/whatsapp-identity.{js,d.ts}. fromMeis no longer used for owner, sudo, admin, or self authorization.- Fixed the bug where
areJidsSameUser(undefined, undefined) === truecould grant false privileges. - Corrected LID fallback that previously replaced an unknown participant with
authState.creds.me.id. - Added verified LID↔PN mappings with TTL, provenance, and rejection of ambiguous mappings.
- Unmapped or ambiguous LIDs fail closed for privileged commands.
Native-Flow Interactive Buttons
- New helpers in
lib/Utils/interactive.{js,d.ts}:btn.url,btn.reply,btn.copy,btn.call,btn.listsendNativeFlowButtons(sock, jid, options)sendCompatibleInteractive(sock, jid, options)with plain-text fallback.
- URL, phone number (E.164), and JSON validation; no
javascript:/data:/file:URLs. - Quick-reply and list IDs are treated as untrusted input and validated against an allowlist.
Reliability & Anti-Abuse
OutboundQueue– per-chat queue with limited concurrency, backoff, and retry limits.MessageDeduplicator– deduplication bymessage.key.id+ chat + sender with TTL.CommandRateLimiter– per-sender, per-chat, and global rate limits with cooldowns.- No aggressive reconnect loops; explicit backoff with a cap.
Tooling & Docs
test/identity.test.js,test/interactive.test.js.env.example,SECURITY_IDENTITY.mdtsconfig.json,typedoc.json,jest.config.cjs,eslint.config.cjspackage.jsonupdated;yarn.lockcreated.- Decoder, receiver, serializer, JID utilities, quoting, and chat management updated to use the new identity layer.
📦 Installation
Stable Version
yarn add @chatunity/baileys
# or
npm install @chatunity/baileysEdge Version (Latest Features)
yarn add github:chatunitycenter/baileysImport
import makeWASocket from '@chatunity/baileys'⚡ Quick Start - The 7 Systems
1. 🚫 Anti-Ban System
Prevents WhatsApp bans through pattern recognition and adaptive pausing.
const { makeAntiBanSystem } = require('@chatunity/baileys')
const antiBan = makeAntiBanSystem(logger)
antiBan.reportError(error, { context: 'message_send' })
const delay = antiBan.getAdaptiveDelay()
const stats = antiBan.getStats()2. 💥 Crash Prevention System
Handles crashes, memory leaks, and implements graceful shutdown.
const { makeCrashPreventionSystem } = require('@chatunity/baileys')
const cp = makeCrashPreventionSystem(logger)
cp.registerRecoveryStrategy('high_memory', async () => { if(global.gc) global.gc() })
const result = await cp.protectedExecute(async () => await risky(), { timeout: 30000 })
cp.onExit(async () => await socket.end())3. 📝 Message Builder & Validator
Type-safe fluent API for all message types.
const { createMessageBuilder } = require('@chatunity/baileys')
const msg = createMessageBuilder()
.text('Hello')
.build()
const buttons = createMessageBuilder()
.buttons('Choose:', [
{ buttonId: '1', buttonText: 'Option 1' },
{ buttonId: '2', buttonText: 'Option 2' }
])
.build()4. ⚡ Advanced Rate Limiter
Intelligent throttling with +20% more throughput.
const { makeAdvancedRateLimiter } = require('@chatunity/baileys')
const limiter = makeAdvancedRateLimiter({ tokensPerSecond: 1, enableAdaptive: true })
await limiter.add(async () => {
return await socket.sendMessage(jid, msg)
}, { priority: 1, timeout: 30000 })5. 📊 Metrics System
Real-time monitoring and performance tracking.
const { makeMetricsSystem } = require('@chatunity/baileys')
const metrics = makeMetricsSystem(logger)
const timerId = metrics.startTimer('operation')
metrics.endTimer(timerId)
metrics.recordMessageSent()
const report = metrics.getReport()6. 🛡️ Error Handler
Intelligent error categorization and auto-recovery.
const { makeCentralizedErrorHandler } = require('@chatunity/baileys')
const eh = makeCentralizedErrorHandler(logger)
const result = await eh.handleError(error, { maxRetries: 3 })
if(result.recovered) console.log('Fixed!')7. 🔒 Security Layer
Input validation, encryption, and IP rate limiting.
const { makeSecurityLayer } = require('@chatunity/baileys')
const security = makeSecurityLayer(logger)
const validation = security.validateInput(userInput)
const encrypted = security.encryptSensitiveData(sensitiveData)🎯 Complete Example (with Identity Layer)
import makeWASocket, { useMultiFileAuthState, serializeMessage } from '@chatunity/baileys'
import { makeAntiBanSystem, makeCrashPreventionSystem, makeAdvancedRateLimiter, makeMetricsSystem } from '@chatunity/baileys'
async function start() {
const { state, saveCreds } = await useMultiFileAuthState('./auth_info')
const sock = makeWASocket({
auth: state,
printQRInTerminal: true
})
// Enable safety systems
const antiBan = makeAntiBanSystem()
const cp = makeCrashPreventionSystem()
const limiter = makeAdvancedRateLimiter({ tokensPerSecond: 1 })
const metrics = makeMetricsSystem()
sock.ev.on('messages.upsert', async (m) => {
for (const msg of m.messages) {
const incoming = serializeMessage(msg, { socket: sock })
// NEVER use msg.key.fromMe for owner/sudo/admin checks
if (!incoming.isAuthenticatedSelf) {
try {
await limiter.add(async () => {
await sock.sendMessage(msg.key.remoteJid, {
text: `Hello! You sent: ${msg.body}`
})
antiBan.reportSuccess()
metrics.recordMessageSent()
})
} catch (error) {
antiBan.reportError(error)
metrics.recordError(error.message)
}
}
}
})
sock.ev.on('creds.update', saveCreds)
}
start()🔧 Configuration
See CONFIG_EXAMPLES.md for detailed configuration examples.
Quick Setup
const config = {
antiBan: { maxConsecutiveErrors: 5 },
limiter: { tokensPerSecond: 1, enableAdaptive: true },
crashPrevention: { memoryThreshold: 512 * 1024 * 1024 },
security: { enableEncryption: true, maxMessageLength: 4096 }
}📚 Additional Documentation
- QUICKSTART.md - 5-minute quick start guide
- CONFIG_EXAMPLES.md - Detailed configuration examples
- SECURITY_IDENTITY.md - Identity layer, LID/username,
fromMefix, native-flow buttons, rollback, and manual test checklist
📝 Sending Messages
Text Message
await sock.sendMessage(jid, { text: 'hello world' })Image Message
await sock.sendMessage(jid, {
image: { url: './image.png' },
caption: 'hello world'
})Button Message (Legacy)
await sock.sendMessage(jid, {
text: 'Choose:',
footer: 'Select one',
buttons: [{
buttonId: 'id1',
buttonText: { displayText: 'Option 1' }
}]
})List Message (Legacy)
await sock.sendMessage(jid, {
text: 'Menu',
footer: 'Select',
sections: [{
title: 'Section 1',
rows: [{
title: 'Option 1',
rowId: 'option1'
}]
}]
})Poll Message
await sock.sendMessage(jid, {
poll: {
name: 'Favorite?',
values: ['A', 'B', 'C'],
selectableCount: 1
}
})Location Message
await sock.sendMessage(jid, {
location: {
degreesLatitude: 24.121231,
degreesLongitude: 55.1121221
}
})🎓 Connecting Your Account
QR Code Connection
import makeWASocket from '@chatunity/baileys'
const sock = makeWASocket({
printQRInTerminal: true
})Pairing Code Connection
const sock = makeWASocket({ printQRInTerminal: false })
if (!sock.authState.creds.registered) {
const code = await sock.requestPairingCode('1234567890')
console.log(`Pairing code: ${code}`)
}Save & Restore Sessions
import { useMultiFileAuthState } from '@chatunity/baileys'
const { state, saveCreds } = await useMultiFileAuthState('./auth_info')
const sock = makeWASocket({ auth: state })
sock.ev.on('creds.update', saveCreds)📊 WhatsApp IDs
- User (PN):
[country code][phone number]@s.whatsapp.net(e.g.,[email protected]) - User (LID):
xxxxxxxxxx@lid(anonymized identifier, not always reversible to PN) - Group:
[timestamp]-[random]@g.us(e.g.,[email protected]) - Broadcast:
[timestamp]@broadcast - Status:
status@broadcast
[!NOTE]
Starting from 3.0.10, treat PN, LID, and username-based contacts as distinct identities. Use the identity helpers to decideisAuthenticatedSelfandisOwner. Never rely onkey.fromMefor authorization.
🐛 Troubleshooting
High Memory Usage
Enable Crash Prevention system - automatically triggers GC when needed.
Frequent delivery errors
Use the outbound queue and conservative rate limits. No helper bypasses WhatsApp enforcement.
Connection Issues
Check network. Use syncFullHistory: true for better message sync.
Message Formatting
Use Message Builder for type-safe message construction.
Users with usernames or LID appear as “self”
Update to 3.0.10+ and use serializeMessage, isAuthenticatedSelf, and the allowlist helpers. See SECURITY_IDENTITY.md.
🤝 Contributing
Contributions are welcome! Feel free to submit issues or pull requests.
📄 License
Security Identity Update
The package now separates the raw transport flag key.fromMe from verified
sender identity. Never use fromMe for owner, sudo, admin, or self
authorization. Use serializeMessage, isAuthenticatedSelf, and the explicit
allowlist helpers exported by the package. Group senders come from the
participant; PN, LID, and privacy identifiers remain distinct. Unmapped or
ambiguous LIDs fail closed for privileged commands.
See SECURITY_IDENTITY.md for the 3.0.10 patch
details, rollback, native-flow buttons, plain-text fallback, rate limiting, and
manual verification guidance. The npm audit found 3.0.9 as the current
registry version, so 3.0.10 is a local patched release until published.
Version: 3.0.10
Status: ✅ Production Ready (after live tests)
Owner: ChatUnity
Last Updated: 2026-08-28
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:
cd path/to/Baileysyarnyarn example
Installation
Use the stable version: yarn add @chatunity/baileys
Use the edge version (no guarantee of stability, but latest fixes + features)
Then import in your code using:
import makeWASocket from '@chatunity/baileys'Connecting Account
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)
Connect with QR-CODE
[!TIP] If you connect via QR-CODE, you can customize the browser name using the
Browserconstant. Several predefined configurations are available, viewable here.
import makeWASocket from '@chatunity/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!
Connect with Pairing Code
[!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.
import makeWASocket from '@chatunity/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)
}Receive Full History
- Set
syncFullHistorytotrue - Use a desktop browser configuration to receive more message history:
const chatunity = makeWASocket({
browser: Browsers.macOS('Desktop'),
syncFullHistory: true
})Socket Configuration
Cache Group Metadata
If you use Baileys for groups, we recommend setting cachedGroupMetadata in socket config:
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)
})Improve Retry System & Decrypt Poll Votes
To improve message sending, retrying on errors, and decrypt poll votes, set up a store with getMessage config:
const chatunity = makeWASocket({
getMessage: async (key) => await getMessageFromStore(key)
})Receive Notifications in WhatsApp App
To receive notifications in the WhatsApp app, set markOnlineOnConnect to false:
const chatunity = makeWASocket({
markOnlineOnConnect: false
})Saving & Restoring Sessions
You don't need to scan the QR code every time you connect. Load credentials to log back in:
import makeWASocket, { useMultiFileAuthState } from '@chatunity/baileys'
const { state, saveCreds } = await useMultiFileAuthState('auth_info_baileys')
const chatunity = makeWASocket({ auth: state })
chatunity.ev.on('creds.update', saveCreds)[!IMPORTANT]
useMultiFileAuthStateis 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
useMultiFileAuthStatefunction handles this automatically, but for other implementations you must be careful with key state management.
Alternative Auth Methods
import makeWASocket, { useSingleFileAuthState, useMongoFileAuthState } from '@chatunity/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)Handling Events
Baileys uses the EventEmitter syntax for events with full TypeScript support.
[!IMPORTANT] See all available events here
const chatunity = makeWASocket()
chatunity.ev.on('messages.upsert', ({ messages }) => {
console.log('got messages', messages)
})Example to Start
import makeWASocket, { DisconnectReason, useMultiFileAuthState } from '@chatunity/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 likefor (const message of event.messages)to handle all messages in the array.
Decrypt Poll Votes
Poll votes are encrypted by default and handled in messages.update:
import pino from "pino"
import { makeInMemoryStore, getAggregateVotesInPollMessage } from '@chatunity/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)?.name
if (toCmd == undefined) return
console.log(toCmd)
}
}
}
})Decrypt Event Response
Event responses are encrypted by default and handled in messages.update:
import { jidNormalizedUser, getAggregateResponsesInEventMessage } from '@chatunity/baileys'
chatunity.ev.on("messages.update", async ([chatUpdate]) => {
const eventResponses = chatUpdate.update?.eventResponses
const agregate = getAggregateResponsesInEventMessage({ eventResponses }, jidNormalizedUser(chatunity.user.lid))
console.log(agregate)
})Summary of Events on First Connection
connection.updateis fired requesting socket restart- History messages are received in
messaging.history-set
Implementing a Data Store
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.
import makeWASocket, { makeInMemoryStore } from '@chatunity/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))
})WhatsApp IDs Explained
id(also calledjid) is the WhatsApp ID of the person or group you're messaging.- Format for people (PN):
[country code][phone number]@s.whatsapp.net- Example:
[email protected]
- Example:
- Format for people (LID):
xxxxxxxxxx@lid(privacy-preserving, may not be reversible to PN) - Format for groups:
[email protected] - Broadcast lists:
[timestamp of creation]@broadcast - Stories:
status@broadcast
- Format for people (PN):
Utility Functions
getContentType- returns the content type for any messagegetDevice- returns the device from a messagemakeCacheableSignalKeyStore- speeds up auth storedownloadContentFromMessage- downloads content from any messageserializeMessage- returns a message withtransportFromMe,sender,isAuthenticatedSelf,isOwner, etc.isAuthenticatedSelf- checks if an identity matches the authenticated socketisAuthorizedOwner- checks if an identity is in the owner/sudo allowlist
Sending Messages
Send all types of messages with a single function:
await chatunity.sendMessage(jid, content, options)Non-Media Messages
Text Message
await chatunity.sendMessage(jid, { text: 'hello world' })Quote Message
await chatunity.sendMessage(jid, { text: 'hello world' }, { quoted: message })Mention User
await chatunity.sendMessage(jid, {
text: '@12345678901',
mentions: ['[email protected]']
})Forward Messages
const msg = getMessageFromStore()
await chatunity.sendMessage(jid, { forward: msg, force: true })Location Message
await chatunity.sendMessage(jid, {
location: {
degreesLatitude: 24.121231,
degreesLongitude: 55.1121221
}
})Live Location Message
await chatunity.sendMessage(jid, {
location: {
degreesLatitude: 24.121231,
degreesLongitude: 55.1121221
},
live: true
})Contact Message
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
await chatunity.sendMessage(jid, {
react: {
text: '💖',
key: message.key
}
})Pin Message
await chatunity.sendMessage(jid, {
pin: {
type: 1, // 2 to remove
time: 86400, // 24h in seconds
key: Key
}
})Keep Message
await chatunity.sendMessage(jid, {
keep: {
key: Key,
type: 1
}
})Poll Message
await chatunity.sendMessage(jid, {
poll: {
name: 'My Poll',
values: ['Option 1', 'Option 2'],
selectableCount: 1,
toAnnouncementGroup: false
}
})Poll Result Message
await chatunity.sendMessage(jid, {
pollResult: {
name: 'Hi',
values: [['Option 1', 1000], ['Option 2', 2000]]
}
})Call Message
await chatunity.sendMessage(jid, {
call: {
name: 'Hey',
type: 1 // 2 for video
}
})Event Message
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
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
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
await chatunity.sendMessage(jid, {
payment: {
note: 'Hi!',
currency: 'IDR',
amount: '10000',
expiry: 0
}
})Payment Invite Message
await chatunity.sendMessage(id, {
paymentInvite: {
type: 1,
expiry: 0
}
})Admin Invite Message
await chatunity.sendMessage(jid, {
adminInvite: {
jid: '123xxx@newsletter',
name: 'newsletter_name',
caption: 'Please be my channel admin',
expiration: 86400
}
})Group Invite Message
await chatunity.sendMessage(jid, {
groupInvite: {
jid: '[email protected]',
name: 'group_name',
caption: 'Please Join My WhatsApp Group',
code: 'code_invite',
expiration: 86400
}
})Sticker Pack Message
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
await chatunity.sendMessage(jid, { sharePhoneNumber: {} })Request Phone Number Message
await chatunity.sendMessage(jid, { requestPhoneNumber: {} })Button Reply Message
// 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
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
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
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: '[email protected]',
thumbnail: 'https://example.com/image.jpg'
})Buttons Cards Message
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 (Native Flow)
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'
})
}
]
})[!TIP] For new projects, prefer the helpers in
lib/Utils/interactive(sendNativeFlowButtons,sendCompatibleInteractive) which add validation, allowlists, and fallback.
Buttons Interactive Message PIX
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: '[email protected]',
key_type: 'EMAIL'
}
}]
})
}]
})Buttons Interactive Message PAY
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
const jids = ['[email protected]', '[email protected]']
// 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
await chatunity.sendMessage(jid, {
text: 'Body',
title: 'Title',
footer: 'Footer',
shop: {
surface: 1,
id: 'https://example.com'
},
viewOnce: true
})Collection Message
await chatunity.sendMessage(jid, {
text: 'Body',
title: 'Title',
footer: 'Footer',
collection: {
bizJid: 'jid',
id: 'https://example.com',
version: 1
},
viewOnce: true
})Media Messages
Sending media (video, stickers, images) is easier and more efficient.
[!NOTE] You can pass
{ stream: Stream },{ url: Url }, orBufferdirectly. See more here
[!TIP] Use Stream or Url to save memory
GIF Message
await chatunity.sendMessage(jid, {
video: fs.readFileSync('Media/gif.mp4'),
caption: 'hello world',
gifPlayback: true
})Video Message
await chatunity.sendMessage(id, {
video: { url: './Media/video.mp4' },
caption: 'hello world'
})Video PTV Message
await chatunity.sendMessage(id, {
video: { url: './Media/video.mp4' },
ptv: true
})Audio Message
Audio needs to be converted to OGG format with ffmpeg:
ffmpeg -i input.mp4 -avoid_negative_ts make_zero -ac 1 output.oggawait chatunity.sendMessage(jid, {
audio: { url: './Media/audio.mp3' },
mimetype: 'audio/mp4'
})Image Message
await chatunity.sendMessage(id, {
image: { url: './Media/image.png' },
caption: 'hello world'
})Album Message
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
await chatunity.sendMessage(id, {
image: { url: './Media/image.png' },
viewOnce: true,
caption: 'hello world'
})Link Previews
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:
yarn add link-preview-jsThen send a link:
await chatunity.sendMessage(jid, {
text: 'Hi, this was sent using https://github.com/whiskeysockets/baileys'
})AI Icon Feature
await chatunity.sendMessage(jid, { text: 'Hi' }, { ai: true })
// With relay
await chatunity.relayMessage(jid, { extendedTextMessage: { text: 'Hi' } }, { AI: true })Modifying Messages
Delete Messages (for everyone)
const msg = await chatunity.sendMessage(jid, { text: 'hello world' })
await chatunity.sendMessage(jid, { delete: msg.key })Editing Messages
await chatunity.sendMessage(jid, { edit: msg.key, text: 'edited message' })Working with Media
Thumbnail in Media Messages
Thumbnails can be generated automatically for images & stickers if you add jimp or sharp:
yarn add jimp
# or
yarn add sharpFor videos, install ffmpeg on your system.
Downloading Media Messages
import { createWriteStream } from 'fs'
import { downloadMediaMessage, getContentType } from '@chatunity/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'))
}
}
})Re-upload Media Message to WhatsApp
const downloadedContent = await downloadMediaMessage(...)
const uploadedUrl = await chatunity.uploadMedia(downloadedContent)