# Baileys — Comprehensive Reference

> **Source:** https://baileys.wiki  
> **Package:** `@whiskeysockets/baileys`  
> **Language:** TypeScript (Node 17+, ESM only since v6.8.0)

---

## Table of Contents

1. [Overview](#1-overview)
2. [Installation](#2-installation)
3. [WhatsApp ID Formats](#3-whatsapp-id-formats)
4. [Authentication & Session Persistence](#4-authentication--session-persistence)
5. [Socket Configuration](#5-socket-configuration)
6. [Connecting to WhatsApp](#6-connecting-to-whatsapp)
7. [History Sync](#7-history-sync)
8. [Receiving Updates & Events](#8-receiving-updates--events)
9. [Handling Messages](#9-handling-messages)
10. [Sending Messages](#10-sending-messages)
11. [Group Management](#11-group-management)
12. [Privacy Settings](#12-privacy-settings)
13. [App State Updates](#13-app-state-updates)
14. [Business Features](#14-business-features)
15. [Broadcast Lists & Status](#15-broadcast-lists--status)
16. [Migration to v7.x.x](#16-migration-to-v7xx)
17. [FAQ & Common Pitfalls](#17-faq--common-pitfalls)
18. [Disclaimer](#18-disclaimer)

---

## 1. Overview

Baileys is a **WhatsApp Web API automation library** for TypeScript/Node that communicates directly over WhatsApp's WebSocket protocol. It requires **no browser, no Selenium, no Chromium** — saving ~500 MB of RAM compared to browser-based approaches.

| Feature | Detail |
|---|---|
| Protocol | WhatsApp Web WebSocket |
| Auth method | Personal or Business account via Linked Devices |
| **NOT** | WhatsApp Business API (WABA / Cloud API) |
| Node requirement | v17+ |
| Module system | ESM only (since v6.8.0) |
| Primary export | `makeWASocket` |

### What it can do

- Send/receive text, media, contacts, locations, polls, reactions
- Edit and delete messages
- Manage disappearing messages
- Group creation, member management, settings
- Privacy and blocklist control
- Chat state management (read, mute, archive, pin)
- Download media content
- Query presence and status
- Update profile information
- Broadcast lists and Stories/Status updates
- Pairing code & QR code authentication

---

## 2. Installation

```bash
# npm
npm install @whiskeysockets/baileys

# Yarn
yarn add @whiskeysockets/baileys

# pnpm
pnpm add @whiskeysockets/baileys

# Bun
bun add @whiskeysockets/baileys

# Edge / latest unreleased fixes
yarn add github:WhiskeySockets/Baileys
```

> Baileys v6.8.0+ is **ESM-only**. Your project must use `"type": "module"` in `package.json` or use dynamic `await import()` from CommonJS.

---

## 3. WhatsApp ID Formats

Baileys uses JID (Jabber ID) strings to address every entity:

| Entity | Format | Example |
|---|---|---|
| Individual user | `[countryCode][phone]@s.whatsapp.net` | `254712345678@s.whatsapp.net` |
| Group | `[timestamp]-[random]@g.us` | `123456789-123345@g.us` |
| Broadcast list | `[timestamp]@broadcast` | `1234567890@broadcast` |
| WhatsApp Status | `status@broadcast` | `status@broadcast` |
| LID (v7+) | `[lid]@lid` | (opaque identifier) |

> **v7 note:** WhatsApp introduced LIDs (Local Identifiers) to anonymise users in large groups. Phone numbers are becoming less reliable as primary identifiers; new Signal sessions default to LID format.

---

## 4. Authentication & Session Persistence

### Auth State

The `auth` object passed to `makeWASocket` must conform to the `AuthenticationState` type. Baileys ships `useMultiFileAuthState` as a reference implementation.

```typescript
import { makeWASocket, useMultiFileAuthState } from '@whiskeysockets/baileys'

const { state, saveCreds } = await useMultiFileAuthState('./auth_info')

const sock = makeWASocket({ auth: state })

// Persist credentials whenever they change
sock.ev.on('creds.update', saveCreds)
```

> **WARNING:** `useMultiFileAuthState` is **I/O-intensive** and unsuitable for production. Use it as a reference only. Implement your own auth state backed by SQL, NoSQL, or Redis.

### Production Auth State Requirements

Your custom auth state must support these key namespaces (see `SignalDataTypeMap`):

| Key namespace | Purpose |
|---|---|
| `session` | Signal encryption sessions |
| `pre-key` | Pre-keys for E2E |
| `sender-key` | Group encryption |
| `app-state-sync-key` | App state decryption |
| `app-state-sync-version` | Versioning |
| `sender-key-memory` | Session memory |
| `lid-mapping` *(v7+)* | Phone ↔ LID mapping |
| `device-list` *(v7+)* | Multi-device list |
| `tctoken` *(v7+)* | Token for LID system |

### Reconnecting Without Re-scanning

Because credentials are persisted, pass `state` on every new socket creation. WhatsApp will reconnect without a new QR.

```typescript
async function connect() {
  const { state, saveCreds } = await useMultiFileAuthState('./auth')
  const sock = makeWASocket({ auth: state })
  sock.ev.on('creds.update', saveCreds)
  return sock
}
```

---

## 5. Socket Configuration

`makeWASocket(config: UserFacingSocketConfig)` — all options:

### Required

| Option | Type | Description |
|---|---|---|
| `auth` | `AuthenticationState` | Your auth state implementation |

### Commonly Used

| Option | Type | Default | Description |
|---|---|---|---|
| `logger` | `Logger` (pino) | pino instance | Log sink — stream to file or consume as stream |
| `getMessage` | `async (key) => proto.IMessage` | — | **Required** for message retry and poll vote decryption. Query your DB by message key. |
| `browser` | `WABrowserDescription` | — | Browser fingerprint. **Critical for pairing code** — must be a valid config, e.g. `Browsers.macOS('Google Chrome')` |
| `version` | `[number, number, number]` | Latest from WA servers | WhatsApp Web version. Use default unless you need a specific version (keep slightly behind latest). |
| `printQRInTerminal` | `boolean` | `false` | Print QR to stdout (useful during dev) |
| `markOnlineOnConnect` | `boolean` | `true` | Set `false` to stop suppressing phone notifications |
| `syncFullHistory` | `boolean` | `false` | Set `true` to emulate desktop and receive full chat history; pair with `Browsers.macOS('Desktop')` |
| `shouldSyncHistoryMessage` | `() => boolean` | `() => true` | Return `false` to disable history sync entirely |
| `cachedGroupMetadata` | `async (jid) => GroupMetadata` | — | Cache group participant lists to avoid rate-limiting on group sends |

### Example

```typescript
import makeWASocket, {
  useMultiFileAuthState,
  Browsers,
  fetchLatestBaileysVersion,
  makeCacheableSignalKeyStore,
} from '@whiskeysockets/baileys'
import NodeCache from 'node-cache'

const groupCache = new NodeCache({ stdTTL: 300 })

async function startSocket() {
  const { state, saveCreds } = await useMultiFileAuthState('./auth')
  const { version } = await fetchLatestBaileysVersion()

  const sock = makeWASocket({
    version,
    auth: {
      creds: state.creds,
      keys: makeCacheableSignalKeyStore(state.keys, console),
    },
    browser: Browsers.macOS('Chrome'),
    printQRInTerminal: true,
    markOnlineOnConnect: false,
    syncFullHistory: true,
    cachedGroupMetadata: async (jid) => groupCache.get(jid),
    getMessage: async (key) => {
      // return message from your DB or undefined
      return undefined
    },
  })

  sock.ev.on('creds.update', saveCreds)
  return sock
}
```

---

## 6. Connecting to WhatsApp

### Method 1 — QR Code

The socket automatically connects on creation and emits `connection.update` with QR data.

```typescript
import makeWASocket, { DisconnectReason } from '@whiskeysockets/baileys'
import { Boom } from '@hapi/boom'

const sock = makeWASocket({ printQRInTerminal: true, auth: state })

sock.ev.on('connection.update', ({ connection, lastDisconnect, qr }) => {
  if (qr) {
    // qr is a string — render it as a QR image for the user
    console.log('QR received:', qr)
  }

  if (connection === 'open') {
    console.log('Connected to WhatsApp')
  }

  if (connection === 'close') {
    const reason = new Boom(lastDisconnect?.error)?.output?.statusCode

    if (reason === DisconnectReason.loggedOut) {
      console.log('Logged out — delete auth and re-scan')
    } else if (reason === DisconnectReason.restartRequired) {
      console.log('Restart required — creating new socket')
      startSocket() // reconnect
    } else {
      console.log('Disconnected:', reason)
    }
  }
})
```

> After scanning the QR, WhatsApp deliberately disconnects to finalise authentication. This is **expected** — handle it by reconnecting.

### Method 2 — Pairing Code (Phone Number)

```typescript
const sock = makeWASocket({
  auth: state,
  browser: Browsers.macOS('Google Chrome'), // required for pairing code
  printQRInTerminal: false,
})

if (!sock.authState.creds.registered) {
  // Phone in E.164 format WITHOUT the leading +
  const code = await sock.requestPairingCode('254712345678')
  console.log('Pairing code:', code) // e.g. ABCD-EFGH
}
```

### Connection States

| `connection` value | Meaning |
|---|---|
| `'connecting'` | Establishing WebSocket |
| `'open'` | Authenticated and ready |
| `'close'` | Disconnected |

### Disconnect Reasons

| `DisconnectReason` | Value | Action |
|---|---|---|
| `loggedOut` | 401 | Delete auth state, re-scan QR |
| `restartRequired` | 515 | Create new socket (old one is dead) |
| `connectionClosed` | 428 | Reconnect |
| `connectionLost` | 408 | Reconnect |
| `connectionReplaced` | 440 | Another client connected |
| `timedOut` | 408 | Reconnect |
| `badSession` | 500 | Delete auth, re-scan |

---

## 7. History Sync

After connecting, Baileys automatically downloads past chats, contacts, and messages via the `messaging-history.set` event.

```typescript
sock.ev.on('messaging-history.set', ({ chats, contacts, messages, syncType }) => {
  console.log(`Sync type: ${syncType}`)
  console.log(`Chats: ${chats.length}, Contacts: ${contacts.length}, Messages: ${messages.length}`)

  // Persist to your database
  for (const msg of messages) {
    db.saveMessage(msg)
  }
})
```

### Disabling History Sync

```typescript
const sock = makeWASocket({
  auth: state,
  shouldSyncHistoryMessage: () => false,
})
```

### On-Demand History Fetch

Request older messages from the primary device beyond the initial sync window:

```typescript
await sock.fetchMessageHistory(/* count */, /* cursor */)
```

---

## 8. Receiving Updates & Events

All events are emitted via `sock.ev.on(eventName, handler)`.

### Message Events

| Event | Payload | Description |
|---|---|---|
| `messages.upsert` | `{ messages, type }` | New or sync'd messages. `type: 'notify'` = new; `type: 'append'` = historical |
| `messages.update` | `MessageUpdate[]` | Status changes, edits, deletions, acks |
| `messages.delete` | key info | Message removed |
| `messages.reaction` | reaction data | Reaction added or removed |
| `message-receipt.update` | receipt data | Delivery / read / played in groups |

```typescript
sock.ev.on('messages.upsert', ({ messages, type }) => {
  if (type !== 'notify') return

  for (const msg of messages) {
    if (msg.key.fromMe) continue

    const jid = msg.key.remoteJid
    const text =
      msg.message?.conversation ??
      msg.message?.extendedTextMessage?.text ??
      null

    console.log(`[${jid}] ${text}`)
  }
})
```

> Always iterate the full `messages` array — never assume a single message.

### Chat Events

| Event | Description |
|---|---|
| `chats.upsert` | New chat started |
| `chats.update` | Chat metadata changed (unread count, last message) |
| `chats.delete` | Chat removed |
| `blocklist.set` | Full blocklist received |
| `blocklist.update` | Incremental blocklist change |
| `call` | Incoming call (offer, accept, decline, timeout) |

### Contact Events

| Event | Description |
|---|---|
| `contacts.upsert` | New contacts added |
| `contacts.update` | Existing contact updated |

### Group Events

| Event | Description |
|---|---|
| `groups.upsert` | Joined a new group |
| `groups.update` | Group metadata changed |
| `group-participants.update` | Members added/removed/promoted/demoted |

### v7 Events

| Event | Description |
|---|---|
| `lid-mapping.update` | Phone ↔ LID mapping updated |

---

## 9. Handling Messages

Messages arrive as `proto.IWebMessageInfo` objects. The actual content lives inside `msg.message` as `proto.IMessage`.

### Message Content Types

| Content field | Type | Use case |
|---|---|---|
| `message.conversation` | `string` | Plain text |
| `message.extendedTextMessage` | object | Text with reply quote, link preview, group invite |
| `message.imageMessage` | object | Image |
| `message.videoMessage` | object | Video |
| `message.audioMessage` | object | Audio / voice note |
| `message.documentMessage` | object | File / document |
| `message.stickerMessage` | object | Sticker |
| `message.contactMessage` | object | Contact card |
| `message.locationMessage` | object | Location pin |
| `message.pollCreationMessage` | object | Poll |
| `message.reactionMessage` | object | Reaction |

### Extracting Text

```typescript
function getTextContent(msg: proto.IWebMessageInfo): string | null {
  return (
    msg.message?.conversation ??
    msg.message?.extendedTextMessage?.text ??
    null
  )
}
```

### Downloading Media

```typescript
import { downloadMediaMessage } from '@whiskeysockets/baileys'

const buffer = await downloadMediaMessage(
  msg,
  'buffer', // 'buffer' | 'stream'
  {},
  {
    logger,
    reuploadRequest: sock.updateMediaMessage,
  }
)
```

> If media download fails (expired URL), call `sock.updateMediaMessage(msg)` to refresh the URL, then retry.

### Relaying Messages (Raw Send)

You can send a raw `proto.IMessage` using `sock.relayMessage`:

```typescript
await sock.relayMessage(jid, proto.Message, { messageId: '...' })
```

---

## 10. Sending Messages

All sending goes through `sock.sendMessage(jid, content, options?)`.

### Text

```typescript
await sock.sendMessage('254712345678@s.whatsapp.net', { text: 'Hello!' })
```

### Text with Mentions

```typescript
await sock.sendMessage(jid, {
  text: 'Hey @254712345678!',
  mentions: ['254712345678@s.whatsapp.net'],
})
```

### Reply / Quote

```typescript
await sock.sendMessage(jid, { text: 'Replying!' }, { quoted: originalMsg })
```

### Image

```typescript
import fs from 'fs'

await sock.sendMessage(jid, {
  image: fs.readFileSync('./photo.jpg'),
  caption: 'Check this out',
})

// From URL
await sock.sendMessage(jid, {
  image: { url: 'https://example.com/image.jpg' },
  caption: 'From URL',
})
```

### Video

```typescript
await sock.sendMessage(jid, {
  video: fs.readFileSync('./video.mp4'),
  caption: 'Watch this',
  gifPlayback: false, // set true to send as GIF
})
```

### Audio / Voice Note

```typescript
await sock.sendMessage(jid, {
  audio: fs.readFileSync('./audio.mp3'),
  mimetype: 'audio/mp4',
  ptt: true, // true = voice note, false = audio file
})
```

### Document / File

```typescript
await sock.sendMessage(jid, {
  document: fs.readFileSync('./report.pdf'),
  mimetype: 'application/pdf',
  fileName: 'report.pdf',
})
```

### Sticker

```typescript
await sock.sendMessage(jid, {
  sticker: fs.readFileSync('./sticker.webp'),
})
```

### Contact Card

```typescript
await sock.sendMessage(jid, {
  contacts: {
    displayName: 'John Doe',
    contacts: [{ vcard: 'BEGIN:VCARD\nVERSION:3.0\nFN:John Doe\nTEL:+254712345678\nEND:VCARD' }],
  },
})
```

### Location

```typescript
await sock.sendMessage(jid, {
  location: { degreesLatitude: -1.286389, degreesLongitude: 36.817223 },
})
```

### Link Preview

```typescript
await sock.sendMessage(jid, {
  text: 'Check out https://example.com',
  linkPreview: {
    url: 'https://example.com',
    title: 'Example Domain',
    description: 'An example site',
  },
})
```

### Reaction

```typescript
await sock.sendMessage(jid, {
  react: {
    text: '👍',          // empty string '' to remove reaction
    key: targetMsg.key,
  },
})
```

### Poll

```typescript
await sock.sendMessage(jid, {
  poll: {
    name: 'Favourite colour?',
    values: ['Red', 'Green', 'Blue'],
    selectableCount: 1, // max choices user can select
  },
})
```

### Edit a Message

```typescript
await sock.sendMessage(jid, {
  edit: originalMsg.key,
  text: 'Updated text',
})
```

### Delete a Message

```typescript
// Delete for everyone
await sock.sendMessage(jid, { delete: targetMsg.key })
```

### Disappearing Messages

```typescript
// Enable disappearing messages in a chat (604800 = 7 days)
await sock.sendMessage(jid, { disappearingMessagesInChat: 604800 })

// Send a single ephemeral message
await sock.sendMessage(
  jid,
  { text: 'This will disappear' },
  { ephemeralExpiration: 604800 }
)
```

### Forward a Message

```typescript
await sock.sendMessage(jid, { forward: msgToForward })
```

### Button / Interactive Messages

> Interactive message support varies by WhatsApp version. Use with caution.

```typescript
await sock.sendMessage(jid, {
  buttons: [
    { buttonId: 'id1', buttonText: { displayText: 'Option 1' }, type: 1 },
    { buttonId: 'id2', buttonText: { displayText: 'Option 2' }, type: 1 },
  ],
  text: 'Pick one:',
  footer: 'footer text',
  headerType: 1,
})
```

### sendMessage Return Value

`sendMessage` returns the sent `proto.IWebMessageInfo` object, which you should store to enable reply/quote, edit, or delete later.

---

## 11. Group Management

### Create a Group

```typescript
const result = await sock.groupCreate('My Group', [
  '254712345678@s.whatsapp.net',
  '254700000000@s.whatsapp.net',
])
console.log(result.gid) // the new group JID
```

### Fetch Group Metadata

```typescript
const meta = await sock.groupMetadata('123456789-123345@g.us')
console.log(meta.subject)       // group name
console.log(meta.participants)  // array of { id, admin }
```

### Manage Participants

```typescript
// Add members
await sock.groupParticipantsUpdate(groupJid, ['jid1', 'jid2'], 'add')

// Remove members
await sock.groupParticipantsUpdate(groupJid, ['jid1'], 'remove')

// Promote to admin
await sock.groupParticipantsUpdate(groupJid, ['jid1'], 'promote')

// Demote from admin
await sock.groupParticipantsUpdate(groupJid, ['jid1'], 'demote')
```

### Update Group Settings

```typescript
// Change group subject (name)
await sock.groupUpdateSubject(groupJid, 'New Group Name')

// Change description
await sock.groupUpdateDescription(groupJid, 'New description')

// Restrict messages to admins only
await sock.groupSettingUpdate(groupJid, 'announcement')

// Allow all members to send messages
await sock.groupSettingUpdate(groupJid, 'not_announcement')

// Restrict editing group info to admins
await sock.groupSettingUpdate(groupJid, 'locked')
```

### Invite Links

```typescript
// Get invite link
const link = await sock.groupInviteCode(groupJid)
console.log(`https://chat.whatsapp.com/${link}`)

// Revoke invite link
await sock.groupRevokeInvite(groupJid)

// Get group info from invite code
const info = await sock.groupGetInviteInfo(code)

// Accept invite
await sock.groupAcceptInvite(code)
```

### Join Requests (Community feature)

```typescript
// Approve join request
await sock.groupRequestParticipantsUpdate(groupJid, ['jid1'], 'approve')

// Reject join request
await sock.groupRequestParticipantsUpdate(groupJid, ['jid1'], 'reject')
```

### Leave a Group

```typescript
await sock.groupLeave(groupJid)
```

### Performance Tip — Cache Group Metadata

Every `sendMessage` to a group fetches participant lists to build encryption keys. Cache this to avoid rate-limiting:

```typescript
import NodeCache from 'node-cache'
const groupCache = new NodeCache({ stdTTL: 300 })

sock.ev.on('groups.update', ([event]) => {
  groupCache.del(event.id) // invalidate on change
})

const sock = makeWASocket({
  cachedGroupMetadata: async (jid) => groupCache.get(jid),
})
```

---

## 12. Privacy Settings

### Blocklist

```typescript
// Get blocklist
const blocked = await sock.fetchBlocklist()

// Block a user
await sock.updateBlockStatus('jid@s.whatsapp.net', 'block')

// Unblock a user
await sock.updateBlockStatus('jid@s.whatsapp.net', 'unblock')
```

### Privacy Settings

```typescript
// Fetch all settings (pass true to bypass cache)
const settings = await sock.fetchPrivacySettings(true)

// Last seen visibility
await sock.updateLastSeenPrivacy('all' | 'contacts' | 'contacts_blacklist' | 'none')

// Profile picture
await sock.updateProfilePicturePrivacy('all' | 'contacts' | 'contacts_blacklist' | 'none')

// Status/About
await sock.updateStatusPrivacy('all' | 'contacts' | 'contacts_blacklist' | 'none')

// Who can add you to groups
await sock.updateGroupsAddPrivacy('all' | 'contacts' | 'contacts_blacklist' | 'none')

// Online presence
await sock.updateOnlinePrivacy('all' | 'match_last_seen')

// Read receipts (blue ticks)
await sock.updateReadReceiptsPrivacy('all' | 'none')
```

---

## 13. App State Updates

Baileys syncs chat state (archive, mute, pin, read) via an encrypted App State system that mirrors the WhatsApp multi-device protocol. The `appStateSyncKeyId` and related keys in your auth state drive this.

Changes are delivered through standard chat/contact events (`chats.update`, `contacts.update`) after Baileys decrypts the sync patch.

### Mark Chat as Read

```typescript
await sock.readMessages([{ remoteJid: jid, id: lastMsgId, fromMe: false }])
```

### Archive a Chat

```typescript
await sock.chatModify({ archive: true, lastMessages: [lastMsg] }, jid)
```

### Mute a Chat

```typescript
// mute for 8 hours (ms)
await sock.chatModify({ mute: 8 * 60 * 60 * 1000 }, jid)

// unmute
await sock.chatModify({ mute: null }, jid)
```

### Pin a Chat

```typescript
await sock.chatModify({ pin: true }, jid)
```

### Delete a Chat

```typescript
await sock.chatModify(
  { delete: true, lastMessages: [{ key: lastMsg.key, messageTimestamp: lastMsg.messageTimestamp }] },
  jid
)
```

---

## 14. Business Features

Most WhatsApp Business features are implemented. The only gap is **modifying** business profile data.

### Fetch Business Profile

```typescript
const profile = await sock.getBusinessProfile(jid)
console.log(profile?.description)
console.log(profile?.category)
```

### Products and Orders

Product catalog and order management methods are available via the socket but not yet fully documented on the official wiki. Refer to the TypeScript types in the package (`sock.getOrderDetails`, `sock.getCatalog`, etc.).

---

## 15. Broadcast Lists & Status

### Send to Broadcast List

```typescript
await sock.sendMessage('listId@broadcast', { text: 'Hello everyone!' })
```

### Send a Status Update (Story)

```typescript
// Text status
await sock.sendMessage('status@broadcast', {
  text: 'My status update',
  backgroundColor: '#FF5733',
  font: 1,
})

// Image status
await sock.sendMessage('status@broadcast', {
  image: { url: './photo.jpg' },
  caption: 'Look at this!',
})
```

### Subscribe to Status Updates

```typescript
sock.ev.on('messages.upsert', ({ messages }) => {
  for (const msg of messages) {
    if (msg.key.remoteJid === 'status@broadcast') {
      console.log('Status from:', msg.key.participant)
    }
  }
})
```

---

## 16. Migration to v7.x.x

### 1. ESM Migration (v6.8.0+)

CommonJS `require()` no longer works. Two options:

**Option A — Convert project to ESM (recommended)**

```json
// package.json
{
  "type": "module"
}
```

```js
// Replace require() with import
import makeWASocket from '@whiskeysockets/baileys'
```

**Option B — Dynamic import from CJS**

```js
const { default: makeWASocket } = await import('@whiskeysockets/baileys')
```

### 2. LID System

WhatsApp now uses LIDs (Local Identifiers) to anonymise users in large groups.

**Auth state additions required:**

```typescript
// Your SignalDataTypeMap implementation must handle:
'lid-mapping'  // Phone ↔ LID map
'device-list'  // Multi-device list
'tctoken'      // Auth token
```

**API changes:**

| Old | New |
|---|---|
| `isJidUser(jid)` | `isPnUser(jid)` |
| `contact.id` (phone) | `contact.id`, `contact.phoneNumber`, `contact.lid` |
| `MessageKey` | Now includes `remoteJidAlt`, `participantAlt` |

**New enum:**

```typescript
WAMessageAddressingMode.PHONE_NUMBER // address by PN
WAMessageAddressingMode.LID          // address by LID
```

**New event:**

```typescript
sock.ev.on('lid-mapping.update', (mappings) => {
  // store mappings for LID ↔ phone resolution
})
```

### 3. Acknowledgements

Baileys **no longer sends delivery ACKs** — WhatsApp was banning accounts for it.

### 4. Protobufs

`proto-methods` bundle was removed. Only `.create()`, `.encode()`, `.decode()` remain.

```typescript
import { BufferJSON } from '@whiskeysockets/baileys'

// Encode
const json = JSON.stringify(data, BufferJSON.replacer)

// Decode
const obj = JSON.parse(json, BufferJSON.reviver)

// Decode + hydrate messages
import { decodeAndHydrate } from '@whiskeysockets/baileys'
const msg = decodeAndHydrate(buffer)
```

### 5. Meta Coexistence (Experimental)

Allows connecting a Business App and Meta API simultaneously on the same number. Mark as experimental — do not rely on in production.

---

## 17. FAQ & Common Pitfalls

### Do not use `useMultiFileAuthState` in production

It performs a file read/write on every message — at scale it will bottleneck your service. Use it as a template to write your own DB-backed auth state.

### `getMessage` is mandatory in practice

Without it, the retry system cannot resend missing messages and poll vote decryption will fail.

```typescript
const sock = makeWASocket({
  getMessage: async (key) => {
    const msg = await db.messages.findOne({ id: key.id })
    return msg?.message ?? undefined
  },
})
```

### Always reconnect on `restartRequired`

```typescript
if (reason === DisconnectReason.restartRequired) {
  startSocket() // create a new socket — the old one is dead
}
```

### QR disconnect after scan is normal

WhatsApp disconnects once to finalise the auth handshake. Reconnect using your persisted credentials and the status will go to `'open'`.

### Browser config matters for pairing code

If using pairing code, `browser` must be set to a real browser fingerprint:

```typescript
browser: Browsers.macOS('Google Chrome')
// or
browser: Browsers.ubuntu('Chrome')
```

### Rate limiting on group sends

If you send to many groups rapidly, Baileys fetches participant lists each time. Use `cachedGroupMetadata` to cache them.

### `@whiskeysockets/baileys` vs `baileys`

The active, maintained package is `@whiskeysockets/baileys`. The plain `baileys` package is outdated.

### Node version

Node 17+ is required. The plan is to remove the Node dependency in a future release for browser/extension environments.

---

## 18. Disclaimer

Baileys is **not affiliated with or endorsed by WhatsApp or Meta**.

- Using this library may violate [WhatsApp's Terms of Service](https://www.whatsapp.com/legal/terms-of-service).
- The maintainers **do not condone** spam, bulk messaging, stalkerware, or any automated abuse.
- You are solely responsible for how you use this library.
- Exercise discretion. Accounts can be banned for suspicious automation patterns.

---

*Documentation compiled from https://baileys.wiki and https://github.com/WhiskeySockets/Baileys — April 2026.*
