npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ourin-baileys

v0.7.14

Published

Modded Baileys v7 with interactive message, album, and newsletter support

Readme

ourin-baileys

Modded Baileys v7 — Interactive Messages, AI Rich Responses, Albums & More

npm version npm downloads GitHub License Node ESM


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


✨ 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 your package.json)
  • A persistent auth store implementation for production use
  • Optional helpers depending on your use case:
    • pino for logging
    • qrcode-terminal if you want to render QR codes in the terminal yourself
    • sharp, jimp, audio-decode, link-preview-js for optional media/rich utilities

[!IMPORTANT] ourin-baileys is 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-baileys

Recommended companion packages for examples in this README:

npm install pino qrcode-terminal

Using Alias (Recommended for Ourin-MD Bots)

Add to package.json:

{
  "dependencies": {
    "ourin": "npm:ourin-baileys@latest"
  }
}

Then run:

npm install

[!TIP] Using the alias ourin allows you to import ourin from 'ourin' without changing existing code.

[!NOTE] Peer dependencies such as sharp, jimp, audio-decode, and link-preview-js are optional. Install only what your bot features need.


🛠️ Quick Start

1. Project Setup

mkdir my-bot && cd my-bot
npm init -y

Ensure 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-terminal

3. 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.js

Scan 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] printQRInTerminal still exists in the type surface for compatibility, but it is deprecated in the current build. Prefer handling the qr value from connection.update yourself.


🏗️ 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 EXPORT

Key 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.js
    • lib/index.d.ts
    • lib/Socket/*.d.ts
    • lib/Utils/*.d.ts
  • Consumers should treat this repo as a ready-to-install runtime artifact, not the authoring source tree

Connection Flow

  1. WebSocket connect → Noise XX handshake (Curve25519 + AES-256-GCM)
  2. QR code or Pairing Code authentication
  3. CB:success → upload pre-keys → send passive IQ → emit connection: 'open'
  4. Store own LID↔PN mapping, migrate own session
  5. 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 disk

Custom 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 usage
  • initAuthCreds() + custom SignalKeyStore for DB/Redis/in-memory persistence
  • makeCacheableSignalKeyStore() 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 expectedImageCount and expectedVideoCount based 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 / GenAIMarkdownTextUXPrimitive typenames
  • Dual output: rows (for submessages) + unified_rows (for sections)
  • Enhanced contextInfo with botMessageSharingInfo
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 string
  • table[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-typed unified_codeBlock
  • Unified response sections with GenAICodeUXPrimitive / GenAIMarkdownTextUXPrimitive typenames
  • Enhanced contextInfo with botMessageSharingInfo
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.ts before they are reflected everywhere else in aggregated socket declarations. If your editor autocomplete lags behind runtime behavior, inspect lib/Socket/messages-send.js and lib/Utils/rich-messages.d.ts for 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 build

What the build does:

  • runs TypeScript with tsconfig.build.json
  • emits JavaScript and declaration files into lib/
  • runs tsc-esm-fix so generated ESM imports resolve cleanly

Important build notes:

  • tsconfig.json is authoring-oriented and uses noEmit: true
  • tsconfig.build.json flips emit back on and excludes test files
  • published package files are limited to lib/**/* and WAProto/**/*

🔀 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

  1. Fork this repo
  2. Create a branch (git checkout -b feature/name)
  3. Commit changes (git commit -m 'feat: add feature')
  4. Push to branch (git push origin feature/name)
  5. 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

⭐ Star this repo · 🐛 Report Bug · 💡 Request Feature