cloud-baileys
v1.1.36
Published
Modded Baileys v7 with interactive message, album, newsletter, and VoIP support
Maintainers
Readme
Modded Baileys — Interactive Messages, AI Rich Responses, Albums & More
A modded build of WhiskeySockets/Baileys with native support for interactive messages, album messages, unified rich responses, newsletter helpers, status mentions, and additional business/community utilities.
This repository is a distribution/build repo for cloud-baileys.
It ships compiled runtime files in lib/ and protobuf artifacts in WAProto/, and is intended to be consumed directly from npm or as a vendored dependency inside the Cloud-MD ecosystem.
🆕 Changelog / Updates
Unreleased
v1.1.35
- Fixed:
additionalNodesfor poll/event messages was silently dropped insendMessage(). The<meta polltype="creation">(poll) and<meta event_type="creation">(event) nodes built internally were only actually sent for AI-bot messages (isAiMsg) — for regular polls/events they were discarded and replaced withoptions.additionalNodes(usuallyundefined) due to a faulty ternary. Internal nodes (meta/bot) and any user-suppliedoptions.additionalNodesare now merged instead of overwriting each other, so polls and events carry their meta node again and customadditionalNodescan still be used alongside them. - Fixed: LID↔PN mapping was never persisted on group notifications.
handleGroupNotificationinmessages-recv.js(triggered by add/remove/promote/demote/leave events) only readphone_number/lidoff the stanza when present, without ever saving the pair tosignalRepository.lidMapping— so if a stanza only carriedlid(nophone_number),phoneNumberwas alwaysundefined, which is why numbers never showed up in LID-based welcome/goodbye notifications. Every lid/pn pair seen in a notification is now saved to the mapping store, and if a stanza only carrieslid, the library now automatically tries to resolvephoneNumberfrom previously-learned mappings (chat history, group metadata, etc.). - Fixed:
groupFetchAllParticipating()didn't populate the LID/PN mapping store. Every call now bulk-saves all lid/pn pairs found in the participant list tosignalRepository.lidMapping, so the mapping cache is populated early (e.g. at startup) before individual group notifications arrive. - Fixed:
extractCommunityMetadata(incommunities.js) didn't fill inphoneNumber/lidper participant at all, unlikeextractGroupMetadatawhich already did this correctly. Behavior is now consistent between the two.
v1.1.34
- Added:
specificRecipientoption insendMessage()/relayMessage()—sock.sendMessage(jid, content, { specificRecipient: [...] })for group messages: instead of sending to all members, the message is only encrypted/sent to the jids listed inspecificRecipient(a targeted "whisper" message to a subset of the group). If the target isstatus@broadcast, it's used as an additional viewer list plus anaudience: "only"attribute on the stanza. Has no effect for 1:1 chats since the destination jid is already the sole recipient.
v1.1.33
- Added: Smoke tests for the interactive message builders (
Button,ButtonV2,Carousel) attest/interactive-builders.test.js, run vianpm test(uses Node's built-innode:test, no extra dependency needed). These specifically guard against the v1.1.2 regressions —Button.build()throwingReferenceError: message is not defined, andcarousel.card(cb)never draining its builders into_cards— so a similar bug failing silently before release is less likely going forward. TheCarouseltest stubsButton.prototype.toCardso it runs withoutsharp/ffmpegor network access. - Added:
"test": "node --test test/"script inpackage.json.
v1.1.3
- Added: Auto-compress image & video before upload.
prepareWAMessageMedianow checks file size automatically — images over 4MB are downscaled (max 1920px) and re-encoded as JPEG at progressively lower quality (viasharp) until they fit; videos over 16MB (WhatsApp's hard limit) are downscaled (max 1280px) and re-encoded to H.264 with an auto-calculated target bitrate (viaffmpeg/ffprobe) based on the source duration. If a file is already small, or compression fails (e.g.sharp/ffmpegunavailable), the original media is sent as-is — this step never causes a send to fail outright. New exports:compressImageIfNeeded(),compressVideoIfNeeded()(both accept an optionalmaxBytesoverride). - Fixed: Audio sent with
ptt: trueoften didn't render as a native voice note (VN) bubble. Previously the file was uploaded as-is with only theaudio/ogg; codecs=opusmimetype label attached, without actually being encoded that way — so non-opus sources (mp3/wav/m4a) could show up as a regular audio file instead of a playable VN bubble with waveform.prepareWAMessageMedianow automatically transcodes to mono 48kHz OGG/Opus viaffmpegbefore upload wheneverptt: trueand the source isn't already ogg/opus, so PTT audio always plays back like a real voice note. New export:transcodeAudioToOggOpus().
v1.1.2
- Fixed interactive message (Button) always failing to send:
Button.build()referenced an undefinedmessagevariable, throwingReferenceError: message is not definedon every send.build()now correctly callsthis.toCard()to construct the payload. - Fixed carousel card-processing logic being misplaced inside
Button.build()instead of theCarouselclass, where.addCard()actually lives. Moved to the correct location. - Fixed carousels built via
carousel.card(cb)always sending empty: cards added through the builder were never processed into_cards.Carousel.build()is nowasyncand processes_cardBuildersbefore sending. - Fixed QR pairing codes that could never be scanned:
buildPairingQRData()was wrapping the QR payload as a URL (https://wa.me/settings/linked_devices#...) with an extra platform ID field, but WhatsApp's multi-device protocol expects a plainref,noiseKey,identityKey,advSecretcomma-separated string. QR generation now matches spec. - Fixed an install-time dependency conflict:
protobufjs-cli@^2.0.1(devDependency) required a peer ofprotobufjs@^8, while the project usesprotobufjs@^7, causingnpm installto fail withERESOLVE. Downgradedprotobufjs-clito^1.3.3, compatible withprotobufjs@^7.6.2.
v1.1.1
- Security fix: added guard against spoofed
protocolMessagetypes (history sync notification, app state key share, LID migration mapping, PDO response) — these are now dropped unless they originate from your own device (fromMe), closing the message-spoofing/state-corruption exposure also patched upstream as GHSA-qvv5-jq5g-4cgg. - Updated QR pairing to the newer format (
https://wa.me/settings/linked_devices#...with companion platform ID) for improved pairing reliability, matching upstream Baileys. - Fixed
companion_platform_idsent during pairing-code login — it was using the wrong enum (DeviceProps.PlatformTypeinstead ofCompanionWebClientType), which mismatched the platform ID sent to WhatsApp's servers for any browser other than Chrome and could cause pairing to fail or behave inconsistently.
v1.0.4
- Fixed pairing code login failing with "Couldn't link device — An error occurred. Try again." The bundled default WhatsApp Web version number (used when you don't pass
versionexplicitly) had gone stale, which WhatsApp now rejects during device linking. Bumped the fallback version inDefaultsandUtils/generics. - Reminder: WhatsApp rotates this build number often. For the most reliable pairing/QR login, call
fetchLatestWaWebVersion()(exported by the package) before connecting and pass its result asversioninmakeWASocket(), instead of relying on the bundled default. - Updated dependencies to their latest compatible versions:
@hapi/boom^10.0.1,pino^10.3.1,ws^8.21.3,lru-cache^11.2.6,p-queue^9.3.3,whatsapp-rust-bridge^0.5.5. - Fixed "Bad MAC" / session errors getting stuck in a permanent decryption-failure loop. Previously, a desynced or corrupted 1:1 session was detected (logged) but never actually cleared, so every retry kept failing the same way until the auth folder was deleted manually. Now, on a
Bad MAC,Invalid MAC, or missing-session error, the corrupted session is automatically deleted so the next incoming message can re-establish a clean session from a fresh prekey message. - Fixed a crash on every media upload (image/video/document/audio/sticker send):
Utils/messages-media.jsdynamically importedaxiosto upload files, butaxioswas never declared as a dependency, sogetWAUploadToServer()would throwCannot find module 'axios'on any environment that didn't happen to have it installed transitively. Replaced with the nativefetch()already used elsewhere in the same file — no new dependency needed. - Declared
long(used directly bySocket/messages-recv.js) as an explicit dependency instead of relying on it being pulled in transitively throughprotobufjs.
v1.0.1
- Minor fixes and cleanup.
v1.0.0
- Initial release of
cloud-baileys, a rebranded and maintained build based on a modded Baileys v7 core. - Built-in support for interactive messages, album messages, unified rich responses, newsletter helpers, and status mentions.
- Built-in VoIP (Voice Call) engine — full integration of WebRTC and WASM to enable native WhatsApp voice calling, no separate package needed.
- Robust handling for View Once messages (
viewOnceMessageV3&ptvMessage) to avoid socket crashes when media content isn't available. - Decryption retry handling in
messages-recv.jsfor "Bad MAC" errors, combined with a propergetMessagehook for seamless retries. - Browser parameter spoofing set to MacOS to help avoid Error 405 (Method Not Allowed) during pairing.
AI Rich Implementation (ORich)
Added the
ORichclass (an extension ofAIRichfrommessage_builder.js) to generate stunning AI response layouts easily.Example Usage:
import { ORich } from 'cloud-baileys'; const cloud = new ORich(sock) .addText('Hello from ORich AI!') .addSuggest(['Tell me more', 'Next']); await cloud.send(jid);
Table of Contents
- cloud-baileys
- Modded Baileys v7 — Interactive Messages, AI Rich Responses, Albums & More
- Table of Contents
- ✨ Features
- ✅ Requirements
- 🗂️ What’s Inside This Repo
- 📦 Installation
- 🛠️ Quick Start
- 🏗️ Architecture
- 📡 Socket API Reference
- 📡 Event Reference
- 🔧 Utility Exports
- 🏗️ Building This Package
- 🔀 Differences from Official Baileys
- 🤝 Contributing
- 📄 License
✨ Features
| Feature | Description | Status |
| --------------------------- | -------------------------------------------------------------------------------------- | ------ |
| VoIP Voice Calls | Native VoIP engine (WASM/WebRTC) via VoipClient, single shared socket | ✅ |
| Interactive Messages | Native flow buttons, list/select menus, button wrappers, carousel support via Dugong | ✅ |
| Album Messages | Multi-image/video album relay with count metadata and grouped delivery | ✅ |
| Rich Response Helpers | sendTable, sendList, sendCodeBlock, sendRichMessage, sendUnifiedResponse | ✅ |
| Unified Response V2 | sendTableV2, sendCodeBlockV2, sendLinkV2 with Meta-AI-style unified sections | ✅ |
| Link Messages | Rich inline links with citations, proofs, and forwarded bot context | ✅ |
| Latex Rendering Hooks | sendLatex, sendLatexImage, sendLatexInlineImage helper APIs | ✅ |
| Payment Messages | Request payment messages with note/sticker support | ✅ |
| Product / Catalog | Business product messages, catalog fetch/create/update/delete, cover photo helpers | ✅ |
| Event / Poll Result | Event message builders and poll result snapshots | ✅ |
| Newsletter Extras | URL resolve, metadata fetch, create/update, bulk follow, admin utilities, live updates | ✅ |
| Communities & Groups | Community CRUD, linked groups, invite workflows, join approval, labels | ✅ |
| Status Mention | sendStatusMention() helper to mention users/groups in status flows | ✅ |
| LID & Session Handling | LID↔PN mapping, session migration, retry/session recreation helpers | ✅ |
| Build Output Ready | Published runtime in lib/ and protobuf artifacts in WAProto/ | ✅ |
| TypeScript Declarations | Included .d.ts files for exported APIs and socket methods | ✅ |
✅ Requirements
- Node.js
>= 20.0.0 - ESM project (
"type": "module"in yourpackage.json) - A persistent auth store implementation for production use
- Optional helpers depending on your use case:
pinofor loggingqrcode-terminalif you want to render QR codes in the terminal yourselfsharp,jimp,audio-decode,link-preview-jsfor optional media/rich utilities
[!IMPORTANT]
cloud-baileysis ESM-only. CommonJS projects will need migration or dynamic import wrappers.
📁 What’s Inside This Repo
This package is not the TypeScript source workspace. It contains the compiled distributable files you actually publish/use.
| Path | Purpose |
| --------------------- | ------------------------------------------------------ |
| lib/ | Main compiled runtime, types, socket layers, utilities |
| WAProto/ | Generated protobuf runtime and typings |
| package.json | Published package metadata, dependencies, build script |
| tsconfig.json | TypeScript config used for authoring/build pipeline |
| tsconfig.build.json | Build-specific TS emit config targeting lib/ |
| proto-extract/ | Protobuf-related extraction/build assets |
If you are documenting or integrating this project, treat lib/index.js and lib/index.d.ts as the primary public surface.
📦 Installation
From NPM
npm install cloud-baileysRecommended companion packages for examples in this README:
npm install pino qrcode-terminalUsing Alias (Recommended for Cloud-MD Bots)
Add to package.json:
{
"dependencies": {
"cloud": "npm:cloud-baileys@latest"
}
}Then run:
npm install[!TIP] Using the alias
cloudallows you toimport cloud from 'cloud'without changing existing code.
[!NOTE] Peer dependencies such as
sharp,jimp,audio-decode, andlink-preview-jsare optional. Install only what your bot features need.
🛠️ Quick Start
1. Project Setup
mkdir my-bot && cd my-bot
npm init -yEnsure package.json has "type": "module":
{
"name": "my-bot",
"type": "module",
"dependencies": {
"cloud": "npm:cloud-baileys@latest"
}
}[!IMPORTANT] Required:
"type": "module"— cloud-baileys is ESM-only. Without this, imports will fail.
2. Install Dependencies
npm install cloud-baileys pino qrcode-terminal3. Create index.js
import makeWASocket, {
useMultiFileAuthState,
DisconnectReason,
Browsers,
} from "cloud-baileys";
import pino from "pino";
import qrcode from "qrcode-terminal";
const logger = pino({ level: "silent" });
async function startBot() {
const { state, saveCreds } = await useMultiFileAuthState("./session");
const sock = makeWASocket({
auth: state,
logger,
browser: Browsers.ubuntu("Chrome"),
syncFullHistory: false,
});
sock.ev.on("creds.update", saveCreds);
sock.ev.on("connection.update", ({ connection, lastDisconnect, qr }) => {
if (qr) {
qrcode.generate(qr, { small: true });
}
if (connection === "close") {
const shouldReconnect =
lastDisconnect?.error?.output?.statusCode !==
DisconnectReason.loggedOut;
if (shouldReconnect) startBot();
}
if (connection === "open") console.log("Connected!");
});
sock.ev.on("messages.upsert", async ({ messages }) => {
const msg = messages[0];
if (!msg?.message || msg.key.fromMe) return;
const text =
msg.message.conversation || msg.message.extendedTextMessage?.text || "";
if (text === ".ping") {
await sock.sendMessage(msg.key.remoteJid, { text: "Pong!" });
}
});
}
startBot();4. Run
node index.jsScan the QR code, wait until the socket reaches connection: "open", then send .ping to test.
5. Pairing Code Example
If you prefer pairing code over QR:
import { fetchLatestWaWebVersion } from "cloud-baileys";
// WhatsApp rotates its web build number frequently. Fetching it live avoids
// "Couldn't link device — An error occurred" caused by a stale bundled default.
const { version } = await fetchLatestWaWebVersion({});
const sock = makeWASocket({
auth: state,
logger,
version,
browser: Browsers.windows("Chrome"),
});
sock.ev.on("connection.update", async ({ connection }) => {
if (connection === "connecting") {
const code = await sock.requestPairingCode("6281234567890");
console.log("Pairing code:", code);
}
});You can also provide your own custom pairing code:
const code = await sock.requestPairingCode("6281234567890", "A1B2C3D4");
console.log("Custom pairing code:", code);Custom pairing codes must be exactly 8 characters.
[!WARNING]
printQRInTerminalstill exists in the type surface for compatibility, but it is deprecated in the current build. Prefer handling theqrvalue fromconnection.updateyourself.
6. Sending a Targeted ("Whisper") Group Message
New in v1.1.34: send a group message that's only encrypted/delivered to a subset of members, instead of the whole group.
await sock.sendMessage(groupJid, { text: "Hey, just you two" }, {
specificRecipient: ["[email protected]", "[email protected]"],
});- Has no effect on 1:1 chats — the destination jid is already the sole recipient.
- If the target is
status@broadcast, it's treated as an extra viewer list and the stanza gets anaudience: "only"attribute.
🏗️ Architecture
Socket Layer Chain
Each socket layer extends the previous via composition, adding functionality from bottom to top:
makeSocket → WebSocket + Noise protocol + pre-key management
makeChatsSocket → App state sync + chat modifications + profile
makeGroupsSocket → Group CRUD + participant management
makeMessagesSendSocket → Message sending + rich messages + relay
makeMessagesRecvSocket → Message receiving + decryption + notifications
makeBusinessSocket → Product catalog + business profile
makeCommunitiesSocket → Community CRUD + sub-groups
makeNewsletterSocket → Newsletter follow/unfollow/metadata
makeWASocket ← TOP LEVEL EXPORTKey Modules
| Module | Path | Description |
| ------------ | --------------- | ---------------------------------------------------------------- |
| Socket | lib/Socket/ | Connection, messaging, groups, newsletter, business, communities |
| Signal | lib/Signal/ | Signal protocol: 1:1 encryption, group SenderKey, LID mapping |
| WABinary | lib/WABinary/ | Binary node encoding/decoding, JID utilities |
| Utils | lib/Utils/ | Crypto, auth state, noise handler, rich messages, media |
| WAProto | WAProto/ | Compiled protobuf encode/decode |
| WAUSync | lib/WAUSync/ | User sync protocol (contact, device, LID) |
| WAM | lib/WAM/ | WhatsApp analytics binary encoding |
| Types | lib/Types/ | Full TypeScript type definitions |
Build Repo Layout
This repository does not currently expose a src/ directory in the checked-in package tree.
That means:
- Documentation should reference
lib/as the public implementation - API discovery is best done through:
lib/index.jslib/index.d.tslib/Socket/*.d.tslib/Utils/*.d.ts
- Consumers should treat this repo as a ready-to-install runtime artifact, not the authoring source tree
Connection Flow
- WebSocket connect → Noise XX handshake (Curve25519 + AES-256-GCM)
- QR code or Pairing Code authentication
CB:success→ upload pre-keys → send passive IQ → emitconnection: 'open'- Store own LID↔PN mapping, migrate own session
- Buffer events → process offline notifications → flush →
receivedPendingNotifications: true
📡 Socket API Reference
Connection & Authentication
const sock = makeWASocket({
auth: state, // AuthenticationState from useMultiFileAuthState
logger, // pino logger instance
browser: Browsers.ubuntu("Chrome"), // Browser identity
version: [2, 3000, 1035194821], // WA version
connectTimeoutMs: 20_000, // Connection timeout
defaultQueryTimeoutMs: 60_000, // Query timeout
retryRequestDelayMs: 250, // Retry delay
maxMsgRetryCount: 5, // Max message retry count
enableRecentMessageCache: true, // Enable message retry manager
enableAutoSessionRecreation: true,
syncFullHistory: false, // Sync full chat history
shouldIgnoreJid: (jid) => false, // Filter specific JIDs
qrTimeout: 60_000,
generateHighQualityLinkPreview: false,
});Pairing Code Authentication:
const sock = makeWASocket({
auth: state,
logger,
browser: Browsers.windows("Chrome"),
});
sock.ev.on("connection.update", async ({ connection, qr, isNewLogin }) => {
if (qr) {
// QR code available (fallback)
}
});
// Request pairing code
const code = await sock.requestPairingCode("6281234567890");
console.log("Pairing code:", code); // e.g. "A1B2-C3D4"Authentication State:
import { useMultiFileAuthState } from "cloud-baileys";
const { state, saveCreds } = await useMultiFileAuthState("./session");
// state.creds → credentials (me, platform, noise keys, etc.)
// state.keys → SignalKeyStore (pre-keys, sessions, identity keys, etc.)
// saveCreds() → persist credentials to diskCustom Data Store / Memory Store Pattern:
import {
BufferJSON,
initAuthCreds,
makeCacheableSignalKeyStore,
} from "cloud-baileys";
const credsStore = new Map();
const keyStoreData = new Map();
const creds = credsStore.get("creds") || initAuthCreds();
const keys = makeCacheableSignalKeyStore({
get: async (type, ids) => {
const data = {};
for (const id of ids) {
data[id] = keyStoreData.get(`${type}:${id}`);
}
return data;
},
set: async (data) => {
for (const category in data) {
for (const id in data[category]) {
const value = data[category][id];
const key = `${category}:${id}`;
if (value == null) keyStoreData.delete(key);
else keyStoreData.set(key, value);
}
}
},
});
const state = { creds, keys };
const saveCreds = async () => {
credsStore.set(
"creds",
JSON.parse(
JSON.stringify(state.creds, BufferJSON.replacer),
BufferJSON.reviver,
),
);
};This package does not currently ship a built-in makeInMemoryStore() helper.
Use these patterns instead:
useMultiFileAuthState()for bot/local usageinitAuthCreds()+ customSignalKeyStorefor DB/Redis/in-memory persistencemakeCacheableSignalKeyStore()when you want faster repeated key access with caching
[!WARNING]
useMultiFileAuthState()is convenient for bots and local testing, but the package itself warns against using it as your long-term production persistence layer. For production, write your own SQL/NoSQL-backed auth store.
Useful companion helpers:
import {
Browsers,
DisconnectReason,
fetchLatestBaileysVersion,
makeCacheableSignalKeyStore,
} from "cloud-baileys";
const { version, isLatest } = await fetchLatestBaileysVersion();
console.log(version, isLatest);VoIP (Voice Calls)
Modul VoIP kini terintegrasi langsung di cloud-baileys menggunakan VoipClient dan memanfaatkan shared socket (tanpa double pairing). Aset WebAssembly sudah built-in.
Inisiasi VoIP Client:
import { VoipClient, CallState } from "cloud-baileys";
// Lakukan ini SETELAH connection === "open"
if (!global.voipClient) {
global.voipClient = new VoipClient();
await global.voipClient.connectWithSocket(sock);
console.log("VoIP engine aktif!");
}Melakukan Panggilan:
try {
// Panggil nomor target (PN) - harus terhubung
const call = await global.voipClient.call("6281234567890", {
durationMs: 60000, // Timeout dalam ms
audioSource: "silence", // Atau "mic" / "file" (butuh audio-feeder & ffmpeg)
});
call.on("ringing", () => console.log("Berdering..."));
call.on("connected", () => console.log("Terhubung!"));
call.on("ended", (reason) => console.log("Panggilan berakhir:", reason));
// Menunggu hingga panggilan selesai
await call.waitForEnd();
} catch (e) {
console.error("Gagal menelpon:", e);
}Message Sending
// Text
await sock.sendMessage(jid, { text: "Hello!" });
// Text with mention
await sock.sendMessage(jid, {
text: "Hello @628xxx!",
mentions: ["[email protected]"],
});
// Image
await sock.sendMessage(jid, {
image: { url: "./photo.jpg" },
caption: "A photo",
});
// Video
await sock.sendMessage(jid, {
video: { url: "./video.mp4" },
caption: "A video",
gifPlayback: false,
});
// Audio
await sock.sendMessage(jid, {
audio: { url: "./audio.ogg" },
mimetype: "audio/ogg; codecs=opus",
ptt: true, // voice note
});
// Sticker
await sock.sendMessage(jid, {
sticker: { url: "./sticker.webp" },
});
// Sticker pack
await sock.sendMessage(
jid,
makeStickerPack({
name: "Cloud Starter Pack",
publisher: "Cloud",
description: "Starter sticker pack",
stickers: [
{ url: "./stickers/1.webp", emojis: ["🔥"] },
{ url: "./stickers/2.webp", emojis: ["😎"] },
],
cover: { url: "./stickers/cover.webp" },
}),
);
// Document
await sock.sendMessage(jid, {
document: { url: "./file.pdf" },
fileName: "document.pdf",
mimetype: "application/pdf",
});
// Reaction
await sock.sendMessage(jid, {
react: { key: msg.key, text: "👍" },
});
// Location
await sock.sendMessage(jid, {
location: {
degreesLatitude: -6.2,
degreesLongitude: 106.8,
name: "Jakarta",
},
});
// Contact
await sock.sendMessage(jid, {
contacts: {
displayName: "Contacts",
contacts: [
{ vcard: "BEGIN:VCARD\nVERSION:3.0\nFN:John\nTEL:+628xxx\nEND:VCARD" },
],
},
});
// Poll
await sock.sendMessage(jid, {
poll: {
name: "Vote!",
values: ["Option A", "Option B", "Option C"],
selectableCount: 1,
},
});
// Forward message
await sock.sendMessage(jid, {
forward: msg,
forwardingScore: 1,
isForwarded: true,
});
// Delete message
await sock.sendMessage(jid, { delete: msg.key });
// Edit message
await sock.sendMessage(jid, {
text: "Edited text",
edit: msg.key,
});Interactive Messages
Native Flow Buttons:
await sock.sendMessage(jid, {
interactiveMessage: {
title: "Welcome!",
footer: "Powered by Cloud",
buttons: [
{
name: "quick_reply",
buttonParamsJson: JSON.stringify({
display_text: "Menu",
id: "menu",
}),
},
{
name: "cta_url",
buttonParamsJson: JSON.stringify({
display_text: "Website",
url: "https://example.com",
}),
},
{
name: "cta_copy",
buttonParamsJson: JSON.stringify({
display_text: "Copy Code",
copy_code: "CLOUD2024",
}),
},
],
header: "Choose an option",
image: { url: "https://example.com/banner.jpg" },
},
});List Menu (single_select):
await sock.sendMessage(jid, {
interactiveMessage: {
title: "Select Category",
footer: "Powered by Cloud",
buttons: [
{
name: "single_select",
buttonParamsJson: JSON.stringify({
title: "Menu",
sections: [
{
title: "Games",
rows: [
{ title: "Quiz", id: ".quiz" },
{ title: "Tebak Gambar", id: ".tebakgambar" },
],
},
{
title: "Tools",
rows: [
{ title: "Sticker", id: ".sticker" },
{ title: "TTS", id: ".tts" },
],
},
],
}),
},
],
header: "Bot Menu",
},
});Album Messages
await sock.sendMessage(jid, {
albumMessage: [
{ image: { url: "./photo1.jpg" }, caption: "First" },
{ image: { url: "./photo2.jpg" }, caption: "Second" },
{ video: { url: "./clip.mp4" }, caption: "Video" },
],
});[!NOTE] Albums automatically set
expectedImageCountandexpectedVideoCountbased on array content.
AI Rich Response Messages
Send messages styled like Meta AI — tables, code blocks, and rich text. All rendered via botForwardedMessage > richResponseMessage.
Table (with heading):
await sock.sendTable(
jid,
"Java vs JavaScript",
["Feature", "Java", "JavaScript"],
[
["Type", "Compiled", "Interpreted"],
["Typing", "Static", "Dynamic"],
["Main Use", "Enterprise", "Web, Full-stack"],
],
quoted,
{
headerText: "Comparison:",
footer: "Hope this helps!",
},
);List (without heading):
await sock.sendList(
jid,
"Bot Info",
[
["Name", "Cloud AI"],
["Version", "2.4.0"],
["Developer", "Kaze"],
],
quoted,
{ footer: "© Cloud AI" },
);Code Block V1 (basic syntax highlighting):
await sock.sendCodeBlock(
jid,
`const greeting = "Hello World"
function sayHello(name) {
return greeting + " " + name
}
sayHello("Cloud")`,
quoted,
{
language: "javascript",
title: "Example Code",
footer: "Powered by Cloud",
},
);Supported V1 languages: javascript, typescript, python
Table V2 (Unified Response):
The V2 table uses the unified response format with GenATableUXPrimitive typename and base64-encoded data, matching the Meta AI rich response protocol.
Features over V1:
- String-based table input with flexible delimiters (
|or,for columns,;;for rows) - Unified response sections with
GenATableUXPrimitive/GenAIMarkdownTextUXPrimitivetypenames - Dual output:
rows(for submessages) +unified_rows(for sections) - Enhanced
contextInfowithbotMessageSharingInfo
await sock.sendTableV2(
jid,
[
"Java vs JavaScript", // title
"Feature | Java | JavaScript", // header (pipe-delimited)
"Type | Compiled | Interpreted;;Typing | Static | Dynamic;;Main Use | Enterprise | Web, Full-stack", // rows (;; separated, | or , delimited)
],
quoted,
{
headerText: "Comparison:",
text: "Here is a comparison table:",
footer: "Hope this helps!",
},
);Input format:
table[0]— title stringtable[1]— header row (columns separated by|or,)table[2+]— data rows (rows separated by;;, columns by|or,)
V2 Options:
| Option | Type | Default | Description |
| ------------ | -------- | ------- | ---------------------------------------------------- |
| title | string | — | Title (used if headerText not set) |
| headerText | string | — | Text shown before the table |
| text | string | — | Markdown text section (GenAIMarkdownTextUXPrimitive) |
| footer | string | — | Text shown after the table |
Code Block V2 (Unified Response)
The V2 code block uses the unified response format with sections/view_model/primitive structure and base64-encoded data, matching the Meta AI rich response protocol exactly.
Features over V1:
- 6 language families with keyword detection
/* */block comment support#comment support for python/bash/lua- Hex/binary/octal number literals
- Dual token output: numeric
codeBlock+ string-typedunified_codeBlock - Unified response sections with
GenAICodeUXPrimitive/GenAIMarkdownTextUXPrimitivetypenames - Enhanced
contextInfowithbotMessageSharingInfo
await sock.sendCodeBlockV2(
jid,
`package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}`,
quoted,
{
language: "go",
title: "Go Example",
text: "Here is a Go code snippet:",
footer: "Powered by Cloud",
},
);Supported V2 languages:
| Language Key | Aliases |
| ------------ | ------------------------ |
| javascript | js, typescript, ts |
| python | py |
| go | golang |
| lua | — |
| bash | sh, shell |
V2 Options:
| Option | Type | Default | Description |
| ---------- | -------- | -------------- | ---------------------------------------------------- |
| language | string | 'javascript' | Programming language for syntax highlighting |
| title | string | — | Title text shown before the code block |
| text | string | — | Markdown text section (GenAIMarkdownTextUXPrimitive) |
| footer | string | — | Footer text shown after the code block |
V2 Token Types:
| Code | V1 Name | V2 Name | Description |
| ---- | --------- | --------- | -------------------------------------------------- |
| 0 | DEFAULT | DEFAULT | Normal text, whitespace, operators |
| 1 | KEYWORD | KEYWORD | Language keywords (const, func, if, etc.) |
| 2 | METHOD | METHOD | Function/method calls (identifier followed by () |
| 3 | STRING | STR | String literals ("...", '...', `...`) |
| 4 | NUMBER | NUMBER | Numeric values (int, float, hex, binary, octal) |
| 5 | COMMENT | COMMENT | Comments (//, /* */, #) |
Link Message (Inline Embeds)
Send rich text with inline clickable links using {{IE_N}}display_text{{/IE_N}} placeholders, with optional citation metadata and verification proofs.
await sock.sendLink(
jid,
"Upload results:\n✅ Freeimage\n🔗 Klik: {{IE_0}}link disini{{/IE_0}}\n✅ Yardsansh\n🔗 Klik: {{IE_1}}link disini{{/IE_1}}",
["https://example.com/upload1", "https://example.com/upload2"],
quoted,
{
headerText: "📁 Media Uploader V3",
footer: "✨ Selesai!",
botJid: "867051314767696@bot",
forwardingScore: 3,
citations: [
{
sourceTitle: "Freeimage",
citationNumber: 1,
faviconCdnUrl: "https://cdn.example.com/favicon.ico",
},
{ sourceTitle: "Yardsansh", citationNumber: 2 },
],
proofs: [
{
version: 1,
useCase: 1,
signature: "base64signature==",
certificateChain: ["base64cert1", "base64cert2"],
},
],
},
);Link Options:
| Option | Type | Default | Description |
| ----------------- | ------------ | ----------------------- | ------------------------------------- |
| headerText | string | — | Text shown before the link content |
| footer | string | — | Text shown after the link content |
| botJid | string | '867051314767696@bot' | Bot JID for forwardedAiBotMessageInfo |
| forwardingScore | number | 3 | Forward score for context info |
| citations | Citation[] | [] | Citation metadata entries |
| proofs | Proof[] | [] | Verification proof entries |
Citation object:
| Field | Type | Description |
| ---------------- | -------- | -------------------------------------------- |
| sourceQuery | string | Source query text |
| faviconCdnUrl | string | CDN URL for favicon |
| citationNumber | number | Citation index (auto-incremented if omitted) |
| sourceTitle | string | Title of the source |
Proof object:
| Field | Type | Description |
| ------------------ | ---------- | ------------------------ |
| version | number | Proof version |
| useCase | number | Use case identifier |
| signature | string | Base64 signature |
| certificateChain | string[] | Base64 certificate chain |
Link V2 (search-result style):
await sock.sendLinkV2(
jid,
"Search results:\n- {{IE_0}}Official docs{{/IE_0}}\n- {{IE_1}}GitHub repo{{/IE_1}}",
[
{
url: "https://www.npmjs.com/package/cloud-baileys",
displayName: "Official docs",
sourceDisplayName: "npm",
sourceSubtitle: "package registry",
},
{
url: "https://github.com/FathulGans/cloud-baileys",
displayName: "GitHub repo",
sourceDisplayName: "github",
sourceSubtitle: "source hosting",
},
],
quoted,
{
headerText: "cloud-baileys",
footer: "Reference links",
searchEngine: "MAME",
},
);Other Message Types
Payment Request:
await sock.sendMessage(jid, {
requestPaymentMessage: {
amount: 50000,
currency: "IDR",
note: "Payment for order #123",
from: "[email protected]",
},
});Event:
await sock.sendMessage(jid, {
eventMessage: {
name: "Community Meetup",
description: "Join us for the monthly meetup!",
startTime: Date.now() + 86400000,
endTime: Date.now() + 90000000,
location: {
name: "Jakarta",
degreesLatitude: -6.2,
degreesLongitude: 106.8,
},
},
});Poll Result:
await sock.sendMessage(jid, {
pollResultMessage: {
name: "Favorite Color?",
pollVotes: [
{ optionName: "Red", optionVoteCount: 42 },
{ optionName: "Blue", optionVoteCount: 38 },
{ optionName: "Green", optionVoteCount: 25 },
],
},
});Status with Mentions:
await sock.sendStatusMention({ text: "Big update coming!" }, [
"[email protected]",
"[email protected]",
]);Product Message:
await sock.sendMessage(jid, {
productMessage: {
title: "Wireless Headphones",
description: "High quality bluetooth headphones",
productId: "WH-001",
retailerId: "cloud-shop",
url: "https://example.com/product",
priceAmount1000: 299000,
currencyCode: "IDR",
thumbnail: { url: "https://example.com/product.jpg" },
body: "Check out this product!",
footer: "Cloud Shop",
buttons: [
{
name: "quick_reply",
buttonParamsJson: JSON.stringify({
display_text: "Buy Now",
id: "buy_wh001",
}),
},
],
},
});Mixed Rich Message (custom submessages):
await sock.sendRichMessage(
jid,
[
{ messageType: 2, messageText: "Here is some info:" },
{
messageType: 4,
tableMetadata: {
title: "Stats",
rows: [
{ items: ["Metric", "Value"], isHeading: true },
{ items: ["Users", "1000"] },
{ items: ["Uptime", "99.9%"] },
],
},
},
{ messageType: 2, messageText: "And some code:" },
{
messageType: 5,
codeMetadata: {
codeLanguage: "javascript",
codeBlocks: [{ highlightType: 0, codeContent: 'console.log("OK")' }],
},
},
],
quoted,
);SubMessage Types:
| messageType | Name | Payload Field |
| ----------- | ------------- | ---------------------- |
| 0 | UNKNOWN | — |
| 1 | GRID_IMAGE | gridImageMetadata |
| 2 | TEXT | messageText |
| 3 | INLINE_IMAGE | imageMetadata |
| 4 | TABLE | tableMetadata |
| 5 | CODE | codeMetadata |
| 6 | DYNAMIC | dynamicMetadata |
| 7 | MAP | mapMetadata |
| 8 | LATEX | latexMetadata |
| 9 | CONTENT_ITEMS | contentItemsMetadata |
Newsletter Methods
// Resolve channel URL to metadata
const info = await sock.cekIDSaluran("https://whatsapp.com/channel/xxxxx");
console.log(info.name, info.subscribers);
// Bulk follow multiple channels
await sock.newsletterMultipleFollow("id1@newsletter id2@newsletter");
// Fetch all subscribed channels
const channels = await sock.newsletterFetchAllSubscribe();
// Generic action (follow/unfollow/mute/unmute)
await sock.newsletterAction("id@newsletter", "follow");
// Create newsletter
const nl = await sock.newsletterCreate("My Channel", "Description");
// Update newsletter
await sock.newsletterUpdate("id@newsletter", { name: "New Name" });
// Get subscriber count
const { subscribers } = await sock.newsletterSubscribers("id@newsletter");
// Get metadata
const meta = await sock.newsletterMetadata("jid", "id@newsletter");
// Follow / Unfollow
await sock.newsletterFollow("id@newsletter");
await sock.newsletterUnfollow("id@newsletter");
// Mute / Unmute
await sock.newsletterMute("id@newsletter");
await sock.newsletterUnmute("id@newsletter");
// Update name / description / picture
await sock.newsletterUpdateName("id@newsletter", "New Name");
await sock.newsletterUpdateDescription("id@newsletter", "New Desc");
await sock.newsletterUpdatePicture("id@newsletter", mediaUpload);
await sock.newsletterRemovePicture("id@newsletter");
// React to message
await sock.newsletterReactMessage("id@newsletter", serverId, "👍");
// Fetch messages
const msgs = await sock.newsletterFetchMessages("id@newsletter", 50, 0, 0);
// Admin operations
const count = await sock.newsletterAdminCount("id@newsletter");
await sock.newsletterChangeOwner("id@newsletter", newOwnerJid);
await sock.newsletterDemote("id@newsletter", userJid);
await sock.newsletterDelete("id@newsletter");Group Methods
// Fetch group metadata
const meta = await sock.groupMetadata("[email protected]");
// Create group
const group = await sock.groupCreate("My Group", ["[email protected]"]);
// Leave group
await sock.groupLeave("[email protected]");
// Update subject / description
await sock.groupUpdateSubject("[email protected]", "New Subject");
await sock.groupUpdateDescription("[email protected]", "New Description");
// Participant actions: add, remove, promote, demote
const result = await sock.groupParticipantsUpdate(
"[email protected]",
["[email protected]"],
"add", // 'remove' | 'promote' | 'demote'
);
// Handle join requests
const requests = await sock.groupRequestParticipantsList("[email protected]");
await sock.groupRequestParticipantsUpdate(
"[email protected]",
["[email protected]"],
"approve",
);
// Invite code
const code = await sock.groupInviteCode("[email protected]");
await sock.groupRevokeInvite("[email protected]");
await sock.groupAcceptInvite("ABCDE12345");
const info = await sock.groupGetInviteInfo("ABCDE12345");
// Settings: announcement, not_announcement, locked, unlocked
await sock.groupSettingUpdate("[email protected]", "announcement");
await sock.groupSettingUpdate("[email protected]", "locked");
// Member add mode / Join approval
await sock.groupMemberAddMode("[email protected]", "admin_add");
await sock.groupJoinApprovalMode("[email protected]", "on");
// Toggle disappearing messages
await sock.groupToggleEphemeral("[email protected]", 86400); // 24h
// Fetch all participating groups
const groups = await sock.groupFetchAllParticipating();
// Update member label
await sock.updateMemberLabel("[email protected]", "VIP");Community Methods
// Fetch community metadata
const meta = await sock.communityMetadata("[email protected]");
// Create community
const community = await sock.communityCreate(
"Our Community",
"Community description",
);
// Create a subgroup under a community
const subgroup = await sock.communityCreateGroup(
"Announcements",
["[email protected]"],
"[email protected]",
);
// Link / unlink an existing group
await sock.communityLinkGroup("[email protected]", "[email protected]");
await sock.communityUnlinkGroup("[email protected]", "[email protected]");
// Fetch linked groups
const linked = await sock.communityFetchLinkedGroups("[email protected]");
// Invite handling
const code = await sock.communityInviteCode("[email protected]");
await sock.communityRevokeInvite("[email protected]");
await sock.communityAcceptInvite(code);
const inviteInfo = await sock.communityGetInviteInfo(code);
// Requests / participants
const requests =
await sock.communityRequestParticipantsList("[email protected]");
await sock.communityRequestParticipantsUpdate(
"[email protected]",
["[email protected]"],
"approve",
);
await sock.communityParticipantsUpdate(
"[email protected]",
["[email protected]"],
"add",
);
// Settings
await sock.communityUpdateSubject("[email protected]", "New Subject");
await sock.communityUpdateDescription("[email protected]", "New Description");
await sock.communityToggleEphemeral("[email protected]", 86400);
await sock.communitySettingUpdate("[email protected]", "announcement");
await sock.communityMemberAddMode("[email protected]", "admin_add");
await sock.communityJoinApprovalMode("[email protected]", "on");
// Leave / list all
await sock.communityLeave("[email protected]");
const communities = await sock.communityFetchAllParticipating();Business Methods
// Catalog
const { products, nextPageCursor } = await sock.getCatalog({
jid: "[email protected]",
limit: 10,
});
const { collections } = await sock.getCollections("[email protected]", 10);
// Orders
const order = await sock.getOrderDetails(orderId, tokenBase64);
// Product CRUD
const product = await sock.productCreate({
name: "Premium Package",
description: "Official premium plan",
price: 150000,
currency: "IDR",
originCountryCode: "ID",
images: [mediaUpload],
});
await sock.productUpdate(product.id, {
name: "Premium Package Plus",
description: "Official premium plan plus",
price: 175000,
currency: "IDR",
images: [mediaUpload],
});
await sock.productDelete([product.id]);
// Business profile
await sock.updateBusinessProfile({
address: "Jakarta, Indonesia",
description: "Official store",
websites: ["https://example.com"],
email: "[email protected]",
hours: {
timezone: "Asia/Jakarta",
days: [{ day: "mon", mode: "open_24h" }],
},
});
// Legacy alias is still available for backward compatibility
await sock.updateBussinesProfile({
description: "Legacy alias still works",
});
await sock.updateCoverPhoto(mediaUpload);
await sock.removeCoverPhoto(coverId);
// Quick replies
await sock.addOrEditQuickReply({
shortcut: "hello",
message: "Hello from business account",
});
await sock.removeQuickReply(timestamp);Chat & Profile Methods
// Profile picture
const url = await sock.profilePictureUrl(jid, "image");
await sock.updateProfilePicture(jid, mediaUpload);
await sock.removeProfilePicture(jid);
// Profile name / status
await sock.updateProfileName("My Name");
await sock.updateProfileStatus("Available");
// Presence
await sock.sendPresenceUpdate("available", jid);
await sock.presenceSubscribe(jid);
// Read receipts
await sock.readMessages([msg.key]);
await sock.sendReceipt(jid, participant, [msgId], "read");
// Block / Unblock
await sock.updateBlockStatus(jid, "block");
await sock.updateBlockStatus(jid, "unblock");
// Fetch blocklist
const list = await sock.fetchBlocklist();
// Chat modifications
await sock.chatModify(
{
archive: true,
lastMessageOrig: msg,
lastMessage: msg,
},
jid,
);
// Star messages
await sock.star(jid, [{ id: msgId, fromMe: true }], true);
// Contact management
await sock.addOrEditContact(jid, { displayName: "Name" });
await sock.removeContact(jid);
// Labels
await sock.addChatLabel(jid, labelId);
await sock.removeChatLabel(jid, labelId);
await sock.addMessageLabel(jid, messageId, labelId);
// App state sync
await sock.resyncAppState(["regular", "critical_block"], true);
// Business profile
const biz = await sock.getBusinessProfile(jid);Privacy Settings
await sock.updateLastSeenPrivacy("all"); // 'all' | 'contacts' | 'contact_blacklist' | 'nobody'
await sock.updateOnlinePrivacy("all"); // 'all' | 'match_last_seen'
await sock.updateProfilePicturePrivacy("contacts");
await sock.updateStatusPrivacy("contacts");
await sock.updateReadReceiptsPrivacy("all"); // 'all' | 'none'
await sock.updateGroupsAddPrivacy("all"); // 'all' | 'contacts'
await sock.updateMessagesPrivacy("all"); // 'all' | 'contacts' | 'nobody'
await sock.updateCallPrivacy("everyone");
await sock.updateDefaultDisappearingMode(86400);
await sock.updateDisableLinkPreviewsPrivacy(true);📡 Event Reference
sock.ev.on('connection.update', ({ connection, lastDisconnect, qr, isNewLogin, receivedPendingNotifications, isOnline }) => {})
sock.ev.on('creds.update', (update) => {})
sock.ev.on('messaging-history.set', ({ chats, contacts, messages, isLatest }) => {})
sock.ev.on('chats.upsert', (chats) => {})
sock.ev.on('chats.update', (updates) => {})
sock.ev.on('chats.delete', (jids) => {})
sock.ev.on('contacts.upsert', (contacts) => {})
sock.ev.on('contacts.update', (updates) => {})
sock.ev.on('messages.upsert', ({ messages, type }) => {})
sock.ev.on('messages.update', (updates) => {})
sock.ev.on('messages.delete', (keys) => {})
sock.ev.on('messages.reaction', (reactions) => {})
sock.ev.on('message-receipt.update', (updates) => {})
sock.ev.on('groups.update', (updates) => {})
sock.ev.on('group-participants.update', (update) => {})
sock.ev.on('group.join-request', (update) => {})
sock.ev.on('call', (calls) => {})
sock.ev.on('labels.edit', (label) => {})
sock.ev.on('labels.associations', ({ associated, label, type }) => {})
sock.ev.on('newsletter.update', (updates) => {})
sock.ev.on('newsletter.follow', (jid) => {})
sock.ev.on('newsletter.unfollow', (jid) => {})
sock.ev.on('settings.update', ({ isAutoEmojiEnabled, isReadReceiptsEnabled, ... }) => {})🔧 Utility Exports
import {
// Auth
useMultiFileAuthState,
makeCacheableSignalKeyStore,
initAuthCreds,
BufferJSON,
fetchLatestBaileysVersion,
// Code tokenization
tokenizeCode,
tokenizeCodeV2,
CodeHighlightType,
RichSubMessageType,
// Rich message generators
generateTableContent,
generateTableContentV2,
toTableMetadataV2,
generateListContent,
generateCodeBlockContent,
generateCodeBlockContentV2,
generateLinkContent,
generateLinkContentV2,
generateRichMessageContent,
generateLatexContent,
generateLatexImageContent,
generateLatexInlineImageContent,
generateUnifiedResponseContent,
captureUnifiedResponse,
// Rich message builders
buildRichContextInfo,
buildBotForwardedMessage,
// Sticker pack helper
makeStickerPack,
// Media processing helpers
transcodeAudioToOggOpus,
compressImageIfNeeded,
compressVideoIfNeeded,
// Language keyword sets
JS_KEYWORDS,
PYTHON_KEYWORDS,
GO_KEYWORDS,
LUA_KEYWORDS,
BASH_KEYWORDS,
LANGUAGE_KEYWORDS,
// Crypto
Curve,
signedKeyPair,
aesEncryptGCM,
aesDecryptGCM,
// JID utilities
jidEncode,
jidDecode,
jidNormalizedUser,
areJidsSameUser,
isJidGroup,
isJidNewsletter,
isLidUser,
isPnUser,
isJidBot,
isJidMetaAI,
isJidBroadcast,
isJidStatusBroadcast,
// Connection
DisconnectReason,
Browsers,
// Dugong (advanced message types)
Dugong,
// Types
WASocket,
} from "cloud-baileys";[!NOTE] In this build, some advanced helper typings may appear first in
lib/Socket/messages-send.d.tsbefore they are reflected everywhere else in aggregated socket declarations. If your editor autocomplete lags behind runtime behavior, inspectlib/Socket/messages-send.jsandlib/Utils/rich-messages.d.tsfor the most complete helper surface.
🏗️ Building This Package
This repository ships compiled files, but it still includes the build script used to emit/update lib/.
npm install
npm run buildWhat the build does:
- runs TypeScript with
tsconfig.build.json - emits JavaScript and declaration files into
lib/ - runs
tsc-esm-fixso generated ESM imports resolve cleanly
Important build notes:
tsconfig.jsonis authoring-oriented and usesnoEmit: truetsconfig.build.jsonflips emit back on and excludes test files- published package files are limited to
lib/**/*andWAProto/**/*
Running Tests
npm install
npm testThis runs the smoke tests in test/ using Node's built-in test runner (node --test) — no extra test framework dependency required. Currently covers the interactive message builders (Button, ButtonV2, Carousel); the Carousel test stubs the media-upload path so it runs without sharp, ffmpeg, or network access.
🔀 Differences from Official Baileys
| Area | Official Baileys v7 | cloud-baileys |
| -------------------- | ------------------- | ---------------------------------------- |
| Interactive messages | No native support | Full support via Dugong |
| Album messages | Not supported | Multi-media albums |
| AI Rich Response | Not available | Table, code block, rich text |
| Table V1 | Not available | Basic table with headers |
| Table V2 | Not available | Unified response + GenATableUXPrimitive |
| Code Block V1 | Not available | Syntax highlighting (JS/TS/Python) |
| Code Block V2 | Not available | Unified response + 6 languages |
| Link Message | Not available | Inline embeds + citations + verification |
| Business nodes | Manual injection | Auto-inject on relay |
| Newsletter extras | Basic only | Auto-follow, bulk follow, URL resolve |
| Button detection | Not available | getButtonType() auto-detect |
| Payment messages | Not supported | Full support |
| Event messages | Basic | Enhanced all fields |
| Status mentions | Not available | sendStatusMention() |
| Product messages | Not supported | Catalog + buttons |
| LID support | Basic | Full LID↔PN mapping + session migration |
| Identity changes | No handling | Debounced session refresh |
| Message retry | Basic | MessageRetryManager with cache |
🤝 Contributing
- Fork this repo
- Create a branch (
git checkout -b feature/name) - Commit changes (
git commit -m 'feat: add feature') - Run
npm testand make sure it passes (see Running Tests) - Push to branch (
git push origin feature/name) - Open a Pull Request
🙏 Credits
cloud-baileys is built on top of WhiskeySockets/Baileys, the open-source WhatsApp Web API library. This package is a modded/rebranded distribution with additional features (interactive messages, VoIP, AI Rich responses, and more) layered on top of that core.
📄 License
MIT © Kaze
[!CAUTION] This library is for educational purposes. Ensure compliance with WhatsApp Terms of Service.
Made by Kaze
