ourin-baileys
v0.7.14
Published
Modded Baileys v7 with interactive message, album, and newsletter support
Maintainers
Readme
ourin-baileys
Modded Baileys v7 — 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 ourin-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 Ourin-MD ecosystem.
Table of Contents
- ourin-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 |
| --------------------------- | -------------------------------------------------------------------------------------- | ------ |
| 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]
ourin-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 ourin-baileysRecommended companion packages for examples in this README:
npm install pino qrcode-terminalUsing Alias (Recommended for Ourin-MD Bots)
Add to package.json:
{
"dependencies": {
"ourin": "npm:ourin-baileys@latest"
}
}Then run:
npm install[!TIP] Using the alias
ourinallows you toimport ourin from 'ourin'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": {
"ourin": "npm:ourin-baileys@latest"
}
}[!IMPORTANT] Required:
"type": "module"— ourin-baileys is ESM-only. Without this, imports will fail.
2. Install Dependencies
npm install ourin-baileys pino qrcode-terminal3. Create index.js
import makeWASocket, {
useMultiFileAuthState,
DisconnectReason,
Browsers,
} from "ourin-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:
const sock = makeWASocket({
auth: state,
logger,
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.
🏗️ 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 "ourin-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 "ourin-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 "ourin-baileys";
const { version, isLatest } = await fetchLatestBaileysVersion();
console.log(version, isLatest);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: "Ourin Starter Pack",
publisher: "Ourin",
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 Ourin",
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: "OURIN2024",
}),
},
],
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 Ourin",
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", "Ourin AI"],
["Version", "2.4.0"],
["Developer", "Zann"],
],
quoted,
{ footer: "© Ourin AI" },
);Code Block V1 (basic syntax highlighting):
await sock.sendCodeBlock(
jid,
`const greeting = "Hello World"
function sayHello(name) {
return greeting + " " + name
}
sayHello("Ourin")`,
quoted,
{
language: "javascript",
title: "Example Code",
footer: "Powered by Ourin",
},
);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 Ourin",
},
);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/ourin-baileys",
displayName: "Official docs",
sourceDisplayName: "npm",
sourceSubtitle: "package registry",
},
{
url: "https://github.com/LuckyArch/ourin-baileys",
displayName: "GitHub repo",
sourceDisplayName: "github",
sourceSubtitle: "source hosting",
},
],
quoted,
{
headerText: "ourin-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: "ourin-shop",
url: "https://example.com/product",
priceAmount1000: 299000,
currencyCode: "IDR",
thumbnail: { url: "https://example.com/product.jpg" },
body: "Check out this product!",
footer: "Ourin 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,
// 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 "ourin-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/**/*
🔀 Differences from Official Baileys
| Area | Official Baileys v7 | ourin-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') - Push to branch (
git push origin feature/name) - Open a Pull Request
📄 License
MIT © LuckyArch
[!CAUTION] This library is for educational purposes. Ensure compliance with WhatsApp Terms of Service.
Made with 💚 by Zann
