npm.io
1.0.6 • Published 5d ago

elynn-baileys

Licence
MIT
Version
1.0.6
Deps
27
Size
13.4 MB
Vulns
0
Weekly
808

elynn-baileys




elynn-baileys



✦  ECMASCRIPT MODULES  ·  NODE.JS 20+  ·  MIT LICENSE  ·  MAINTAINED BY ELYNN  ✦



npm version npm downloads node version license module type platforms


Elynn Baileys adalah library WhatsApp Web API yang kuat, stabil, dan ditingkatkan jauh dari basis aslinya — kini menyatu dengan engine Telegram Bot (ElynnTelegraf) dan Discord Client (ElynnDiscord) dalam satu package. Mendukung penuh protokol WhatsApp 2026 — View-Once Text, View-Once Voice Note, Community Events, Group Message History, Channel Polling, dan lainnya — dilengkapi plugin Brat/Bratvid bawaan serta fungsi eksklusif testMessage untuk menguji seluruh jenis pesan dalam satu panggilan. Dibangun khusus untuk Node.js dengan format ECMAScript Modules (ESM).


◈  PETA NAVIGASI  ◈

⟡ WhatsApp

Engine inti, enhanced dari Baileys dengan dukungan protokol 2026 penuh — pesan interaktif, media, event komunitas, hingga sistem keamanan session.

makeWASocket · useMultiFileAuthState · makeInMemoryStore

⟡ Telegram

ElynnTelegraf — engine bot Telegram lengkap dari long-polling dasar hingga Bot API 10.1: managed bots, guest mode, rich messages.

ElynnTelegraf · Scenes & Wizard · Inline Keyboard

⟡ Discord

ElynnDiscord — client Discord dari nol, mendukung slash command, sharding, modals UI 2026, dan per-guild bot profile.

ElynnDiscord · Slash Commands · ShardManager


Satu dependency untuk tiga platform messaging sekaligus — tidak perlu lagi merangkai tiga library berbeda dengan API yang tidak konsisten
Dukungan penuh protokol WhatsApp 2026 — fitur-fitur terbaru yang belum tersedia di kebanyakan fork Baileys lain
testMessage bawaan — uji 16 jenis pesan dalam satu panggilan fungsi, tanpa setup tambahan
sessionGuard — kunci session ke IP server pertama, proteksi nyata dari pencurian session
Plugin Brat/Bratvid bawaan, tidak perlu API key eksternal tambahan
Tiga jenis Auth State (multiFile, singleFile, sqlite) — fleksibel untuk semua skala deployment

01  Installation

02  Quick Start

03  Auth State
    ◦ 3.1 · Multi File Auth State
    ◦ 3.2 · Single File Auth State
    ◦ 3.3 · SQLite Auth State

04  makeInMemoryStore

05  Sending Messages  (38 topik)

    ◦ 5.1 · Text Biasa
    ◦ 5.2 · Text dengan Mention User
    ◦ 5.3 · Mention All
    ◦ 5.4 · Reply / Quote Message
    ◦ 5.5 · Reaction
    ◦ 5.6 · Image
    ◦ 5.7 · Video
    ◦ 5.8 · Audio
    ◦ 5.9 · Document
    ◦ 5.10 · Sticker
    ◦ 5.11 · Sticker Pack
    ◦ 5.12 · Contact / vCard
    ◦ 5.13 · Location
    ◦ 5.14 · Live Location
    ◦ 5.15 · Poll
    ◦ 5.16 · Album
    ◦ 5.17 · Interactive — Buttons (Native Flow)
    ◦ 5.18 · Interactive — List
    ◦ 5.19 · Interactive — Image Header
    ◦ 5.20 · Interactive sebagai Template
    ◦ 5.21 · Hydrated Template Button
    ◦ 5.22 · View Once
    ◦ 5.23 · Ephemeral
    ◦ 5.24 · Spoiler
    ◦ 5.25 · Group Status
    ◦ 5.26 · External Ad Reply
    ◦ 5.27 · Forward Pesan
    ◦ 5.28 · Pin Pesan
    ◦ 5.29 · Raw Message
    ◦ 5.30 · Group Invite Link
    ◦ 5.31 · Event dengan Reminder (fitur WA Januari 2026)
    ◦ 5.32 · Text Sticker (fitur WA Januari 2026)
    ◦ 5.33 · View-Once Text — Teks Sekali Lihat (WA 2026)
    ◦ 5.34 · View-Once Voice Note — Audio Sekali Dengar (WA 2026)
    ◦ 5.35 · Community Event — RSVP & Virtual Meeting Call (WA 2026)
    ◦ 5.36 · Group Message History Share (WA 2026)
    ◦ 5.37 · Channel Poll — Polling di Saluran/Channel (WA 2026)
    ◦ 5.38 · Channel Voice Note (WA 2026)


06  Rich Response Messages
    ◦ 6.1 · Text Rich
    ◦ 6.2 · Code Block
    ◦ 6.3 · Table
    ◦ 6.4 · Inline Image
    ◦ 6.5 · Inline Link / Citation
    ◦ 6.6 · Rich Response Kombinasi

07  Group Management

08  Newsletter / Channel

09  Privacy & Profile

10  Handling Events

11  Elynn Plugins : Brat & Bratvid

12  Read Messages & Presence

13  Delete / Edit Pesan

14  Message Options Tambahan

15  Browser Fingerprint (Kiwi, UC Browser, dll)

16  Telegram Bot (ElynnTelegraf)  (17 topik)

    ◦ 16.1 · Setup Dasar & Long Polling
    ◦ 16.2 · Setup via Webhook
    ◦ 16.3 · Inline Keyboard & Reply Keyboard
    ◦ 16.4 · Session, Scenes & Wizard
    ◦ 16.5 · Memanggil Elynn Plugins (Brat/Bratvid) dari Bot Telegram
    ◦ 16.6 · Cek Koneksi Bot dengan connectTelegram
    ◦ 16.7 · Bot API 9.3–9.4 – sendMessageDraft, Profile Photo Bot, Button Style & Icon
    ◦ 16.8 · Bot API 9.5 – Member Tags, Date-Time Entity
    ◦ 16.9 · Bot API 9.6 – Managed Bots
    ◦ 16.10 · Bot API 10.0 – Guest Mode
    ◦ 16.11 · Bot API 10.0 – Bot-to-Bot Communication
    ◦ 16.12 · Bot API 10.0 – Delete Reactions
    ◦ 16.13 · Bot API 10.0 – Live Photo
    ◦ 16.14 · Bot API 10.0 – Managed Bot Access Settings
    ◦ 16.15 · Bot API 10.0 – Get User Personal Chat Messages
    ◦ 16.16 · Bot API 10.1 – Join Request Queries
    ◦ 16.17 · Bot API 10.1 – Rich Messages


17  Discord Bot (ElynnDiscord)
    ◦ 17.1 · Setup Dasar & Login Bot
    ◦ 17.2 · Menangani Event & Pesan
    ◦ 17.3 · Slash Commands (Application Commands)
    ◦ 17.4 · Embed & File Upload
    ◦ 17.5 · Sharding dengan ShardManager
    ◦ 17.6 · Cek Koneksi Bot dengan connectDiscord

18  testMessage : Tes Semua Jenis Pesan
    ◦ Cara import & penggunaan
    ◦ Signature lengkap
    ◦ Yang diuji (16 jenis pesan)

19  sessionGuard : Proteksi Session dari Pencurian  (7 topik)

    ◦ Cara Import
    ◦ Penggunaan Dasar
    ◦ Opsi Lengkap
    ◦ Cara Kerja
    ◦ Cek Status Guard
    ◦ Reset Guard (Pindah Server)
    ◦ Contoh Output Log




§ SECTION 01

01 — Installation


Anda dapat menginstal package ini menggunakan manajer paket Node.js favorit Anda. Package ini membutuhkan Node.js versi 20 ke atas.

npm install elynn-baileys
yarn add elynn-baileys
pnpm add elynn-baileys

Untuk memaksimalkan semua fitur yang ada, terutama fitur manipulasi media, integrasi database, dan sistem preview, Anda disarankan untuk menginstal peer dependencies opsional berikut ini secara bersamaan.

npm install sharp jimp @napi-rs/image audio-decode better-sqlite3 link-preview-js

§ SECTION 02

02 — Quick Start


Berikut adalah contoh lengkap cara melakukan inisialisasi koneksi ke WhatsApp. Kode ini menangani pembuatan socket, integrasi kredensial login, dan logika rekoneksi otomatis. Terdapat dua metode login: menggunakan Pairing Code atau QR Code.

import pino from 'pino'
import { makeWASocket, useMultiFileAuthState, DisconnectReason, fetchLatestBaileysVersion, Browsers } from 'elynn-baileys'

async function connectToWhatsApp() {
  const logger = pino({ level: 'silent' })
  
  const { state, saveCreds } = await useMultiFileAuthState('./session-auth')
  const { version, isLatest } = await fetchLatestBaileysVersion()
  
  const usePairingCode = true
  const phoneNumber = '6281234567890'

  const sock = makeWASocket({
    version: version,
    logger: logger,
    printQRInTerminal: !usePairingCode,
    auth: state,
    browser: Browsers.ubuntu('Chrome'), // bisa juga Browsers.kiwi(), Browsers.ucBrowser(), dll — lihat Bab 15
    markOnlineOnConnect: true,
    generateHighQualityLinkPreview: true,
    syncFullHistory: false
  })

  if (usePairingCode && !sock.authState.creds.registered) {
    const code = await sock.requestPairingCode(phoneNumber)
    console.log(`Pairing Code Anda: ${code}`)
  }

  sock.ev.on('creds.update', saveCreds)

  sock.ev.on('connection.update', (update) => {
    const { connection, lastDisconnect } = update
    
    if (connection === 'close') {
      const shouldReconnect = lastDisconnect.error?.output?.statusCode !== DisconnectReason.loggedOut
      
      if (shouldReconnect) {
        connectToWhatsApp()
      } else {
        console.log('Koneksi terputus dan sesi telah dihapus.')
      }
    } else if (connection === 'open') {
      console.log('Koneksi berhasil dibuka dan WhatsApp siap digunakan.')
    }
  })

  return sock
}

connectToWhatsApp()

§ SECTION 03

03 — Auth State


elynn-baileys menyediakan tiga jenis mekanisme penyimpanan status autentikasi yang dapat Anda pilih sesuai dengan infrastruktur aplikasi Anda.

◈ 3.1 · Multi File Auth State

Menyimpan data kredensial dan keys dalam sebuah direktori yang berisi banyak file JSON. Sangat stabil dan direkomendasikan untuk penggunaan standar.

import { useMultiFileAuthState } from 'elynn-baileys'

async function setupAuth() {
  const { state, saveCreds } = await useMultiFileAuthState('./auth_info_baileys')
  return { state, saveCreds }
}
◈ 3.2 · Single File Auth State

Menyimpan seluruh data kredensial ke dalam satu file JSON tunggal. Mudah dipindahkan namun bisa menjadi sangat besar seiring waktu.

import { useSingleFileAuthState } from 'elynn-baileys'

async function setupAuth() {
  const { state, saveCreds } = await useSingleFileAuthState('./creds.json')
  return { state, saveCreds }
}
◈ 3.3 · SQLite Auth State

Menyimpan data autentikasi ke dalam database SQLite. Sangat cepat, hemat memori, dan sangat disarankan untuk produksi berskala besar.

import { useSqliteAuthState } from 'elynn-baileys'

async function setupAuth() {
  // Membutuhkan peer dependency: npm install better-sqlite3
  const { state, saveCreds } = await useSqliteAuthState({ dbPath: './auth_database.db' })
  return { state, saveCreds }
}

§ SECTION 04

04 — makeInMemoryStore


makeInMemoryStore adalah sistem penyimpanan data sesi dalam memori yang ditingkatkan. Menyediakan caching cerdas untuk pesan, kontak, dan metadata grup. Konfigurasi dan implementasi lengkap:

import { makeInMemoryStore } from 'elynn-baileys'
import pino from 'pino'

const logger = pino({ level: 'silent' })

const store = makeInMemoryStore({
  logger: logger,
  maxMessages: Infinity,
  presenceTTL: 300000
})

function setupStore(sock) {
  store.bind(sock.ev)

  store.on('onMessage', (message) => {
    console.log(message)
  })

  store.on('onPresence', (presence) => {
    console.log(presence)
  })

  store.on('onChat', (chat) => {
    console.log(chat)
  })

  setInterval(() => {
    store.writeToFile('./store_backup.json')
  }, 10000)
}

async function useStoreFeatures(sock, jid, messageId) {
  const stats = store.getStats()
  
  const searchResults = await store.searchMessages('halo dunia', jid)
  
  const allMessages = await store.loadAllMessages(jid)
  
  const lastMessages = await store.loadLastMessages(jid, 20)
  
  const allGroupMetadata = await store.fetchAllGroupMetadata(sock)
  
  const isRead = store.isMessageRead(jid, messageId)
  
  store.readFromFile('./store_backup.json')
  
  store.clear()
}

§ SECTION 05

05 — Sending Messages


Seksi ini memuat seluruh metode dan struktur pengiriman pesan menggunakan library ini.

◈ 5.1 · Text Biasa
async function sendText(sock, jid) {
  await sock.sendMessage(jid, { 
    text: 'Halo, ini adalah pesan teks biasa.' 
  })
}
◈ 5.2 · Text dengan Mention User
async function sendMention(sock, jid) {
  await sock.sendMessage(jid, {
    text: 'Halo @6281234567890, selamat datang di grup!',
    mentions: ['6281234567890@s.whatsapp.net']
  })
}
◈ 5.3 · Mention All
async function sendMentionAll(sock, jid) {
  const meta = await sock.groupMetadata(jid)
  await sock.sendMessage(jid, {
    text: 'Pengumuman untuk seluruh anggota grup!',
    mentionAll: true,
    groupMetadata: meta
  })
}
◈ 5.4 · Reply / Quote Message
async function sendReply(sock, jid, quotedMessage) {
  await sock.sendMessage(jid, {
    text: 'Ini adalah balasan dari pesan sebelumnya.',
    quote: quotedMessage
  })
}
◈ 5.5 · Reaction
async function sendReaction(sock, jid, messageKey) {
  await sock.sendMessage(jid, {
    react: { 
      text: '🔥', 
      key: messageKey 
    }
  })
}
◈ 5.6 · Image
import fs from 'fs'

async function sendImages(sock, jid) {
  await sock.sendMessage(jid, {
    image: { url: 'https://domain.com/gambar-bagus.jpg' },
    caption: 'Ini adalah gambar yang dikirim dari URL'
  })

  const bufferImage = fs.readFileSync('./lokal_foto.jpg')
  await sock.sendMessage(jid, {
    image: bufferImage,
    caption: 'Ini adalah gambar yang dikirim dari buffer lokal'
  })
}
◈ 5.7 · Video
async function sendVideo(sock, jid) {
  await sock.sendMessage(jid, {
    video: { url: 'https://domain.com/video-keren.mp4' },
    caption: 'Deskripsi untuk video ini',
    gifPlayback: false
  })
}
◈ 5.8 · Audio
async function sendAudio(sock, jid) {
  await sock.sendMessage(jid, {
    audio: { url: 'https://domain.com/voice-note.ogg' },
    mimetype: 'audio/ogg; codecs=opus',
    ptt: true
  })

  await sock.sendMessage(jid, {
    audio: { url: 'https://domain.com/musik.mp3' },
    mimetype: 'audio/mp4'
  })
}
◈ 5.9 · Document
async function sendDocument(sock, jid) {
  await sock.sendMessage(jid, {
    document: { url: 'https://domain.com/laporan-tahunan.pdf' },
    mimetype: 'application/pdf',
    fileName: 'laporan-tahunan-2026.pdf',
    caption: 'Berikut adalah file dokumen yang diminta'
  })
}
◈ 5.10 · Sticker
import fs from 'fs'

async function sendSticker(sock, jid) {
  const stickerBuffer = fs.readFileSync('./animasi_sticker.webp')
  await sock.sendMessage(jid, {
    sticker: stickerBuffer
  })
}
◈ 5.11 · Sticker Pack
import fs from 'fs'

async function sendStickerPack(sock, jid) {
  const localSticker = fs.readFileSync('./sticker_dua.webp')
  await sock.sendMessage(jid, {
    stickerPack: {
      name: 'Koleksi Sticker Eksklusif',
      publisher: 'Elynn',
      cover: { url: 'https://domain.com/cover-pack.png' },
      stickers: [
        { data: { url: 'https://domain.com/sticker_satu.webp' }, emojis: ['😂', '🤣'] },
        { data: localSticker, emojis: ['🔥', ''] }
      ]
    }
  })
}
◈ 5.12 · Contact / vCard
async function sendContact(sock, jid) {
  const vcardString = 'BEGIN:VCARD\nVERSION:3.0\nFN:Elynn\nTEL;type=CELL;waid=6281234567890:+62 812 3456 7890\nEND:VCARD'
  
  await sock.sendMessage(jid, {
    contacts: {
      displayName: 'Elynn Contact',
      contacts: [{
        vcard: vcardString
      }]
    }
  })
}
◈ 5.13 · Location
async function sendLocation(sock, jid) {
  await sock.sendMessage(jid, {
    location: {
      degreesLatitude: -6.2087634,
      degreesLongitude: 106.845599,
      name: 'Monumen Nasional',
      address: 'Gambir, Jakarta Pusat, DKI Jakarta, Indonesia'
    }
  })
}
◈ 5.14 · Live Location
import { generateWAMessageFromContent } from 'elynn-baileys'

async function sendLiveLocation(sock, jid) {
  const messageContent = {
    locationMessage: {
      degreesLatitude: -6.2087634,
      degreesLongitude: 106.845599,
      name: 'Lokasi Terkini',
      address: 'Berbagi Lokasi Langsung',
      liveLocation: {
        degreesLatitude: -6.2087634,
        degreesLongitude: 106.845599,
        accuracyInMeters: 10,
        speedInMps: 0,
        degreesClockwiseFromMagneticNorth: 0,
        caption: 'Saya sedang membagikan lokasi langsung',
        sequenceNumber: 1,
        timeOffset: 3600
      },
      contextInfo: {
        forwardingScore: 1,
        isForwarded: false
      }
    }
  }

  const generatedMessage = await generateWAMessageFromContent(
    jid,
    messageContent,
    { userJid: sock.user.id }
  )

  await sock.relayMessage(jid, generatedMessage.message, {
    messageId: generatedMessage.key.id
  })
}
◈ 5.15 · Poll
async function sendPoll(sock, jid) {
  await sock.sendMessage(jid, {
    poll: {
      name: 'Apa bahasa pemrograman favorit Anda untuk backend?',
      values: ['Node.js', 'Python', 'Go', 'Rust'],
      selectableCount: 1
    }
  })
}
◈ 5.16 · Album
import fs from 'fs'

async function sendAlbum(sock, jid) {
  const localImage = fs.readFileSync('./foto_galeri.jpg')
  
  await sock.sendMessage(jid, {
    album: [
      { image: { url: 'https://domain.com/foto_satu.jpg' }, caption: 'Dokumentasi Bagian 1' },
      { image: localImage, caption: 'Dokumentasi Bagian 2' },
      { video: { url: 'https://domain.com/video_dokumentasi.mp4' }, caption: 'Video Rekaman' }
    ]
  })
}
◈ 5.17 · Interactive — Buttons (Native Flow)
import { generateWAMessageFromContent } from 'elynn-baileys'

async function sendInteractiveButtons(sock, jid) {
  const messageContent = {
    viewOnceMessage: {
      message: {
        interactiveMessage: {
          header: {
            hasMediaAttachment: false
          },
          body: {
            text: 'Silakan pilih salah satu opsi di bawah ini untuk melanjutkan:'
          },
          footer: {
            text: 'elynn-baileys'
          },
          nativeFlowMessage: {
            buttons: [
              {
                name: 'quick_reply',
                buttonParamsJson: JSON.stringify({
                  display_text: '✅ Konfirmasi Pesanan',
                  id: 'btn_confirm_order'
                })
              },
              {
                name: 'cta_url',
                buttonParamsJson: JSON.stringify({
                  display_text: '🌐 Kunjungi Website Resmi',
                  url: 'https://example.com',
                  merchant_url: 'https://example.com'
                })
              },
              {
                name: 'cta_copy',
                buttonParamsJson: JSON.stringify({
                  display_text: '📋 Salin Kode Promo',
                  copy_code: 'ELYNN2026PROMO'
                })
              },
              {
                name: 'cta_call',
                buttonParamsJson: JSON.stringify({
                  display_text: '📞 Hubungi Customer Service',
                  phone_number: '+6281234567890'
                })
              }
            ],
            messageVersion: 1
          }
        }
      }
    }
  }

  const generatedMessage = await generateWAMessageFromContent(
    jid,
    messageContent,
    { userJid: sock.user.id }
  )

  await sock.relayMessage(jid, generatedMessage.message, {
    messageId: generatedMessage.key.id
  })
}
◈ 5.18 · Interactive — List
import { generateWAMessageFromContent } from 'elynn-baileys'

async function sendInteractiveList(sock, jid) {
  const messageContent = {
    viewOnceMessage: {
      message: {
        interactiveMessage: {
          body: {
            text: 'Berikut adalah katalog produk kami. Silakan pilih kategori yang Anda inginkan:'
          },
          footer: {
            text: 'elynn-baileys'
          },
          nativeFlowMessage: {
            buttons: [
              {
                name: 'single_select',
                buttonParamsJson: JSON.stringify({
                  title: '📋 Buka Katalog Menu',
                  sections: [
                    {
                      title: '🍔 Makanan Utama',
                      rows: [
                        {
                          id: 'menu_nasi_goreng',
                          title: 'Nasi Goreng Spesial',
                          description: 'Rp 25.000 - Ekstra Telur'
                        },
                        {
                          id: 'menu_mie_goreng',
                          title: 'Mie Goreng Seafood',
                          description: 'Rp 30.000 - Udang & Cumi'
                        }
                      ]
                    },
                    {
                      title: '🥤 Minuman Segar',
                      rows: [
                        {
                          id: 'menu_es_teh',
                          title: 'Es Teh Manis',
                          description: 'Rp 5.000 - Gula Asli'
                        },
                        {
                          id: 'menu_jus_jeruk',
                          title: 'Jus Jeruk Peras',
                          description: 'Rp 12.000 - Jeruk Murni'
                        }
                      ]
                    }
                  ]
                })
              }
            ],
            messageVersion: 1
          }
        }
      }
    }
  }

  const generatedMessage = await generateWAMessageFromContent(
    jid,
    messageContent,
    { userJid: sock.user.id }
  )

  await sock.relayMessage(jid, generatedMessage.message, {
    messageId: generatedMessage.key.id
  })
}
◈ 5.19 · Interactive — Image Header
async function sendInteractiveImageHeader(sock, jid) {
  const imagePreparation = await sock.prepareMessage(jid, {
    image: { url: 'https://domain.com/banner-promo.jpg' }
  })
  
  await sock.sendMessage(jid, {
    interactive: {
      type: 'native_flow',
      header: {
        hasMediaAttachment: true,
        imageMessage: imagePreparation.message.imageMessage
      },
      body: { text: 'Dapatkan diskon 50% untuk pembelian pertama Anda hari ini!' },
      footer: { text: 'elynn-baileys' },
      nativeFlowMessage: {
        buttons: [
          { 
            name: 'quick_reply', 
            buttonParamsJson: JSON.stringify({ 
              display_text: '🛒 Klaim Diskon & Beli Sekarang', 
              id: 'claim_discount_buy' 
            }) 
          }
        ]
      }
    }
  })
}
◈ 5.20 · Interactive sebagai Template

Opsi interactiveAsTemplate membungkus pesan jadi templateMessage, format legacy yang tidak tampil di akun WhatsApp personal (lihat catatan di 5.21). Hanya gunakan ini jika tujuan target adalah WhatsApp Business Cloud API resmi dengan template approved. Untuk bot/personal account biasa, kirim langsung tanpa flag interactiveAsTemplate (lihat 5.17).

async function sendInteractiveAsTemplate(sock, jid) {
  await sock.sendMessage(jid, {
    interactive: {
      type: 'native_flow',
      body: { text: 'Pesan interaktif ini dikirim menggunakan format bungkus template.' },
      footer: { text: 'elynn-baileys' },
      nativeFlowMessage: {
        buttons: [
          {
            name: 'quick_reply',
            buttonParamsJson: JSON.stringify({
              display_text: 'Tampilkan Detail',
              id: 'show_details'
            })
          }
        ]
      }
    },
    interactiveAsTemplate: true
  })
}
◈ 5.21 · Hydrated Template Button

PENTING — templateMessage/buttonsMessage (legacy) SUDAH TIDAK WORK di akun WhatsApp personal. Berdasarkan dokumentasi resmi WhatsApp (developers.facebook.com), button & template format lama ini hanya didukung lewat WhatsApp Business Cloud API dengan template yang sudah di-approve Meta — bukan lewat koneksi personal/MD seperti Baileys. Mengirim templateMessage mentah dari akun biasa akan terkirim tapi buttonnya tidak muncul / pesan tidak tampil di sisi penerima (silent fail). Gunakan 5.17 Native Flow sebagai gantinya — itu yang dipakai WA app resmi sekarang untuk personal account.

Helper templateButtons di bawah ini tetap disediakan untuk kompatibilitas kode lama, tapi secara internal otomatis di-convert memakai struktur yang sama dengan native flow agar tetap bisa tampil:

import { generateWAMessageFromContent, proto } from 'elynn-baileys'

// ✅ CARA YANG BENAR-BENAR WORK — pakai nativeFlow (lihat juga 5.17)
async function sendWorkingButtons(sock, jid) {
  await sock.sendMessage(jid, {
    text: 'Pilih salah satu opsi di bawah ini:',
    footer: 'elynn-baileys',
    nativeFlow: {
      buttons: [
        { url: 'https://example.com', text: '🌐 Buka Situs Web' },
        { call: '+6281234567890', text: '📞 Hubungi Kami' },
        { id: 'btn_agree_terms', text: '✅ Setuju' }
      ]
    }
  })
}

// ⚠️ Legacy hydratedTemplate — disediakan untuk backward-compat, TIDAK direkomendasikan untuk fitur baru
async function sendHydratedTemplate(sock, jid) {
  await sock.sendMessage(jid, {
    templateButtons: [
      { url: 'https://example.com', text: '🌐 Buka Situs Web' },
      { call: '+6281234567890', text: '📞 Hubungi Kami' },
      { id: 'btn_agree_terms', text: '✅ Setuju' }
    ],
    text: 'Ini adalah teks konten utama untuk pesan jenis hydrated template.',
    footer: 'Informasi Footer Tambahan'
  })
}
◈ 5.22 · View Once
async function sendViewOnce(sock, jid) {
  await sock.sendMessage(jid, {
    image: { url: 'https://domain.com/rahasia.jpg' },
    caption: 'Dokumen ini hanya dapat dilihat satu kali.',
    viewOnce: true
  })

  await sock.sendMessage(jid, {
    video: { url: 'https://domain.com/video-rahasia.mp4' },
    viewOnceV2: true
  })
}
◈ 5.23 · Ephemeral
async function sendEphemeral(sock, jid) {
  await sock.sendMessage(jid, {
    text: 'Pesan ini bersifat rahasia dan akan terhapus otomatis secara permanen dalam waktu 24 jam.',
    ephemeral: true
  }, { 
    ephemeralExpiration: 86400 
  })
}
◈ 5.24 · Spoiler
async function sendSpoiler(sock, jid) {
  await sock.sendMessage(jid, {
    image: { url: 'https://domain.com/kejutan.jpg' },
    caption: 'Ini adalah gambar kejutan yang disembunyikan di balik spoiler!',
    spoiler: true
  })
}
◈ 5.25 · Group Status
async function sendGroupStatus(sock, jid) {
  await sock.sendMessage(jid, {
    text: 'Pengumuman penting telah ditambahkan ke status grup.',
    groupStatus: true
  })
}
◈ 5.26 · External Ad Reply

Catatan penting: externalAdReply di shorthand sock.sendMessage() butuh field url (string, dipakai untuk mediaUrl/sourceUrl/thumbnailUrl sekaligus) dan thumbnail (Buffer JPEG, bukan thumbnailUrl string) — bukan thumbnailUrl/sourceUrl terpisah. Tanpa thumbnail (Buffer), preview card sering tidak muncul karena WA app butuh gambar sudah ter-embed, tidak bisa fetch dari URL eksternal saat render. Sertakan juga forwardingScore + isForwarded: true — pola ini paling konsisten membuat card-nya muncul.

[!WARNING] Limitasi yang tidak bisa diperbaiki dari sisi kode: externalAdReply murni metadata dekorasi di contextInfo, bukan tipe pesan sendiri — apakah card-nya dirender atau tidak itu keputusan WhatsApp app di sisi penerima, tergantung platform (Android/iOS) dan versi app. Ini dikonfirmasi sebagai known issue di banyak fork Baileys (lihat issue #51 dan #75 di repo WhiskeySockets/Baileys). Gejala umum: pengirim/linked-device sendiri melihat card lengkap (karena disinkron via WA Web/Desktop yang versinya lebih baru), tapi penerima dengan WA app versi/platform berbeda hanya melihat teks biasa tanpa card. Tidak ada konfigurasi proto yang menjamin tampil 100% di semua device — anggap fitur ini sebagai progressive enhancement, bukan sesuatu yang reliable untuk dipakai sebagai fitur utama bot.

import fs from 'fs'

async function sendExternalAdReply(sock, jid) {
  await sock.sendMessage(jid, {
    text: 'Silakan periksa tautan referensi berikut ini untuk informasi lebih lanjut!',
    contextInfo: {
      forwardingScore: 100,
      isForwarded: true
    },
    externalAdReply: {
      title: 'Artikel Referensi Lengkap',
      body: 'Membahas teknologi terbaru dan perkembangannya di masa depan',
      thumbnail: fs.readFileSync('./thumbnail-artikel.jpg'), // wajib Buffer, bukan URL
      url: 'https://example.com/artikel-lengkap', // dipakai untuk mediaUrl & sourceUrl
      mediaType: 1, // 1 = tanpa media spesifik, 2 = image, 3 = video
      renderLargerThumbnail: true,
      showAdAttribution: true // default sudah true di lib, eksplisit di sini untuk kejelasan
    }
  })
}

// Alternatif: raw style sesuai proto asli, kalau butuh kontrol penuh tanpa shorthand
async function sendExternalAdReplyRaw(sock, jid) {
  await sock.sendMessage(jid, {
    text: 'Versi raw, langsung isi contextInfo.externalAdReply.',
    contextInfo: {
      forwardingScore: 100,
      isForwarded: true,
      externalAdReply: {
        title: 'Artikel Referensi Lengkap',
        body: 'Membahas teknologi terbaru',
        thumbnail: fs.readFileSync('./thumbnail-artikel.jpg'),
        thumbnailUrl: 'https://example.com/thumbnail-artikel.jpg',
        sourceUrl: 'https://example.com/artikel-lengkap',
        mediaType: 1,
        showAdAttribution: true
      }
    }
  })
}
◈ 5.27 · Forward Pesan
async function sendForwardMessage(sock, jid, messageToForward) {
  await sock.sendMessage(jid, {
    forward: messageToForward
  })
}
◈ 5.28 · Pin Pesan
async function pinMessageInChat(sock, jid, messageKey) {
  await sock.sendMessage(jid, {
    pin: { 
      messageKey: messageKey, 
      type: 1 
    }
  })
}
◈ 5.29 · Raw Message
async function sendRawProtoMessage(sock, jid) {
  await sock.sendMessage(jid, {
    text: 'Pengujian pengiriman struktur raw protocol buffer langsung.',
    raw: true
  })
}
async function sendGroupInvite(sock, jid) {
  const currentTime = Math.round(new Date().getTime() / 1000)
  const expirationTime = currentTime + 86400

  await sock.sendMessage(jid, {
    groupInviteMessage: {
      inviteCode: 'AbCdEfGhIjKlMnOp',
      inviteExpiration: expirationTime,
      groupJid: '1234567890-0987654321@g.us',
      groupName: 'Komunitas Pengembang Nusantara',
      caption: 'Mari bergabung dengan grup diskusi kami untuk bertukar wawasan dan pengalaman!'
    }
  })
}
◈ 5.31 · Event dengan Reminder (fitur WA Januari 2026)

WhatsApp resmi menambahkan "Event Reminders" pada update grup chat 7 Januari 2026 — pembuat event kini bisa menyetel pengingat otomatis untuk semua undangan sebelum acara dimulai. Cukup tambahkan reminderOffsetSec (dalam detik) ke object event yang sudah ada di elynn-baileys.

async function sendEventWithReminder(sock, jid) {
  await sock.sendMessage(jid, {
    event: {
      name: 'Nonton Bareng Final Liga',
      description: 'Kumpul bareng nonton final di basecamp ya, jangan telat!',
      startDate: new Date('2026-08-01T20:00:00+07:00'),
      endDate: new Date('2026-08-01T23:00:00+07:00'),
      location: {
        degreesLatitude: -7.983908,
        degreesLongitude: 112.621391,
        name: 'Basecamp Komunitas, Jl. Mawar No. 5'
      },
      extraGuestsAllowed: true,
      reminderOffsetSec: 3600
    }
  })
}

Catatan: jika reminderOffsetSec diisi, elynn-baileys otomatis menyetel hasReminder: true pada eventMessage. Tanpa parameter ini, event tetap terkirim normal tanpa pengingat — perilaku ini sepenuhnya backward-compatible dengan kode event lama Anda.

◈ 5.32 · Text Sticker (fitur WA Januari 2026)

WhatsApp juga merilis "Text Stickers" pada update yang sama — mengubah kata apa pun menjadi stiker hanya dengan mengetik di Sticker Search. Karena fitur aslinya murni rendering sisi klien (tanpa endpoint protokol khusus), elynn-baileys menyediakan generator renderTextSticker() bawaan yang merender teks menjadi stiker WebP secara lokal (memakai canvas + sharp/@napi-rs/image, tanpa API pihak ketiga) lalu langsung bisa dikirim seperti stiker biasa.

import { renderTextSticker } from 'elynn-baileys'

async function sendTextSticker(sock, jid) {
  const stickerBuffer = await renderTextSticker('MANTAP', {
    backgroundColor: '#FFD60A',
    textColor: '#1A1A1A',
    fontWeight: 'bold'
  })

  await sock.sendMessage(jid, {
    sticker: stickerBuffer
  })
}

Beda dengan plugin attp/ttp (Bab 11) yang memanggil API eksternal untuk efek teks bergerak/glow, renderTextSticker murni lokal — tidak butuh koneksi internet maupun API key, cocok untuk stiker teks polos yang cepat dan privat.


◈ 5.33 · View-Once Text — Teks Sekali Lihat (WA 2026)

Pertengahan 2026, WhatsApp merilis kemampuan mengirim teks murni sebagai view-once: pesan hanya bisa dibaca satu kali, setelah itu otomatis dihapus. Penerima tidak bisa menyalin, meneruskan, atau merekam layarnya. Di Baileys, ini bekerja dengan membungkus extendedTextMessage ke dalam viewOnceMessageV2 via generateWAMessageFromContent.

import { generateWAMessageFromContent, proto } from 'elynn-baileys'

async function sendViewOnceText(sock, jid) {
  // Cara 1 — shorthand flag (dicoba dulu, support tergantung versi WA penerima)
  await sock.sendMessage(jid, {
    text: 'Pesan rahasia ini hanya bisa dibaca satu kali. 🔒',
    viewOnce: true,
  })

  // Cara 2 — raw proto wrap (lebih kompatibel dengan WA build terbaru)
  const innerMsg = generateWAMessageFromContent(jid, {
    extendedTextMessage: {
      text: 'Isi pesan rahasia yang hanya bisa dilihat sekali.',
    },
  }, {})

  const viewOnceMsg = generateWAMessageFromContent(jid, {
    viewOnceMessageV2: {
      message: innerMsg.message,
    },
  }, { userJid: sock.user.id })

  await sock.relayMessage(jid, viewOnceMsg.message, { messageId: viewOnceMsg.key.id })
}

Catatan: Pastikan WA penerima sudah versi yang mendukung view-once teks (2025.8+). Pada versi lebih lama pesan akan tampil sebagai teks biasa.


◈ 5.34 · View-Once Voice Note — Audio Sekali Dengar (WA 2026)

Voice note (PTT) kini resmi bisa dikirim sebagai view-once: audio hanya bisa diputar satu kali lalu hilang. Cocok untuk kirim kode OTP audio atau pesan suara rahasia.

async function sendViewOnceVoice(sock, jid) {
  // View-Once Voice Note (PTT sekali dengar)
  await sock.sendMessage(jid, {
    audio: { url: './voice-rahasia.ogg' },
    mimetype: 'audio/ogg; codecs=opus',
    ptt: true,          // wajib true agar muncul sebagai voice note
    viewOnce: true,     // sekali dengar, lalu terhapus otomatis
  })

  // Dengan waveform custom (opsional, memperindah tampilan)
  await sock.sendMessage(jid, {
    audio: { url: './voice-rahasia.ogg' },
    mimetype: 'audio/ogg; codecs=opus',
    ptt: true,
    viewOnce: true,
    waveform: [0, 15, 42, 80, 110, 95, 70, 50, 30, 10], // array amplitudo 0-100
  })
}

Catatan: ptt: true wajib ada — tanpa itu audio dikirim sebagai musik biasa dan flag viewOnce tidak akan aktif dengan benar.


◈ 5.35 · Community Event — RSVP & Virtual Meeting Call (WA 2026)

WhatsApp 2026 memperluas fitur event di Community dengan dukungan RSVP tracking dan link virtual meeting langsung di dalam pesan event. Berbeda dari 5.31 (event grup biasa dengan reminder), fitur ini spesifik untuk:

Kapabilitas Penjelasan
Virtual call Audio/video link tertanam langsung di pesan event
RSVP Bot mendeteksi siapa yang menerima/menolak via messages.upsert bertipe eventResponseMessage
extraGuestsAllowed Anggota grup bisa mengajak tamu di luar grup ke event
// Kirim event virtual meeting di community/grup
async function sendVirtualMeetingEvent(sock, groupJid) {
  await sock.sendMessage(groupJid, {
    event: {
      isCancelled:        false,
      name:               'Elynn Dev — Sprint Review Q4',
      description:        'Review sprint bulanan + demo fitur baru. Join via WA Call.',
      location: {
        // Untuk virtual meeting: isi name dengan link meeting, lat/long bisa 0
        degreesLatitude:  0,
        degreesLongitude: 0,
        name:             'Google Meet — meet.google.com/abc-defg-hij',
      },
      call:               'video',  // 'audio' = voice call, 'video' = video call -- butuh options.getCallLink saat dipanggil dari generateWAMessageFromContent agar joinLink terisi
      startDate:          new Date('2026-10-10T15:00:00+07:00'), // wajib objek Date, bukan unix timestamp
      endDate:            new Date('2026-10-10T16:30:00+07:00'),
      extraGuestsAllowed: false,    // false = hanya member grup yang bisa join
    },
  })
}

// Handle respons RSVP dari peserta
sock.ev.on('messages.upsert', ({ messages }) => {
  for (const msg of messages) {
    const rsvp = msg.message?.eventResponseMessage
    if (!rsvp) continue

    // rsvp.response: 1 = GOING, 2 = NOT GOING
    const status  = rsvp.response === 1 ? 'HADIR ✅' : 'TIDAK HADIR ❌'
    const eventId = rsvp.eventCreationMessageKey?.id
    const voter   = msg.key.participant || msg.key.remoteJid

    console.log(`RSVP dari ${voter}: ${status} (event ID: ${eventId})`)
  }
})

Perbedaan dari 5.31: Section 5.31 fokus pada event grup biasa dengan reminderOffsetSec (pengingat waktu). Section ini fokus pada virtual meeting + RSVP response handling — dua kemampuan berbeda yang hadir bersamaan di WA 2026.


◈ 5.36 · Group Message History Share (WA 2026)

WhatsApp merilis fitur ini Februari 2026: saat member baru ditambahkan, admin/member bisa membagikan 25–100 pesan terakhir ke member tersebut lewat prompt di UI client resmi. Fitur ini murni client-side (ditangani oleh aplikasi WA, bukan dikirim sebagai pesan protokol terpisah) dan field internalnya (GroupHistoryBundleInfo) ditandai deprecated di proto WA sendiri — sehingga belum ada endpoint resmi untuk men-trigger ini lewat Baileys/elynn-baileys.

Yang sudah bisa dilakukan lewat lib ini sekarang:

// Cek setting grup yang berkaitan (member add mode, announce, dst)
async function checkGroupSettings(sock, groupJid) {
  const meta = await sock.groupMetadata(groupJid)
  console.log('Group metadata:', {
    name:          meta.subject,
    memberAddMode: meta.memberAddMode, // 'all_member_add' | 'admin_add'
    announce:      meta.announce,      // true = hanya admin bisa kirim pesan
    participants:  meta.participants.length,
  })
  return meta
}

// Alternatif manual: forward N pesan terakhir ke member baru via DM/bot logic sendiri
async function shareRecentMessagesManually(sock, groupJid, newMemberJid, messages) {
  for (const msg of messages.slice(-25)) { // ambil 25 pesan terakhir
    await sock.relayMessage(newMemberJid, msg.message, { messageId: msg.key.id })
  }
}

Catatan: Belum ada method native (groupToggleMessageHistory dkk tidak exist) karena WA belum membuka protokol publik untuk fitur ini. Jangan gunakan nama method yang belum ada di lib — cek dulu dengan console.log(Object.keys(sock)) untuk daftar method yang benar-benar tersedia.


◈ 5.37 · Channel Poll — Polling di Saluran/Channel (WA 2026)

WhatsApp Channels kini mendukung pembuatan polling — fitur interaksi satu arah berskala besar langsung di saluran. Gunakan toAnnouncementGroup: true agar poll terkirim ke channel/saluran (newsletter JID).

async function sendChannelPoll(sock, channelJid) {
  // Kirim poll ke Channel / Saluran WhatsApp
  // channelJid format: 'xxxxxxxxxxxxxxxxxx@newsletter'
  await sock.sendMessage(channelJid, {
    poll: {
      name:              'Bahasa pemrograman favorit kamu?',
      values:            ['JavaScript', 'Python', 'Go', 'Rust', 'TypeScript'],
      selectableCount:   1,           // 1 = single choice, >1 = multi choice
      toAnnouncementGroup: true,      // WAJIB true untuk Channel/saluran
    },
  })
}

// Poll biasa di grup (bukan channel)
async function sendGroupPoll(sock, groupJid) {
  await sock.sendMessage(groupJid, {
    poll: {
      name:              'Kapan kita meet offline?',
      values:            ['Minggu ini', 'Minggu depan', 'Bulan depan', 'Belum bisa'],
      selectableCount:   1,
      toAnnouncementGroup: false,
    },
  })
}

// Handling respons poll di event handler
sock.ev.on('messages.upsert', ({ messages }) => {
  for (const msg of messages) {
    if (msg.message?.pollUpdateMessage) {
      const update = msg.message.pollUpdateMessage
      console.log('Vote masuk:', {
        voter:       msg.key.participant,
        pollMsgId:   update.pollCreationMessageKey?.id,
        selectedOpt: update.vote?.selectedOptions,
      })
    }
  }
})

◈ 5.38 · Channel Voice Note (WA 2026)

WhatsApp Channels kini mendukung pengiriman voice note — memungkinkan kreator saluran berinteraksi lebih personal dengan subscriber via audio langsung di channel.

async function sendChannelVoiceNote(sock, channelJid) {
  // channelJid format: 'xxxxxxxxxxxxxxxxxx@newsletter'
  await sock.sendMessage(channelJid, {
    audio: { url: './pengumuman.ogg' },
    mimetype: 'audio/ogg; codecs=opus',
    ptt: true,    // wajib true agar tampil sebagai voice note di channel
  })

  // Dengan caption/deskripsi (support tergantung WA build)
  await sock.sendMessage(channelJid, {
    audio: { url: './rekaman-siaran.mp3' },
    mimetype: 'audio/mp4',
    ptt: false,   // false = audio biasa (musik/rekaman), bukan PTT
    caption: 'Rekaman siaran terbaru — dengarkan sekarang! 🎙️',
  })
}

Catatan: Newsletter JID bisa didapat dari sock.newsletterSubscribers(channelJid), sock.newsletterFetchMessages(...), atau dari metadata channel yang sudah kamu follow saat event messaging-history.set.



§ SECTION 06

06 — Rich Response Messages


Fitur ini secara eksklusif memungkinkan Anda mengirim struktur data yang lebih kompleks menyerupai antarmuka dari bot AI resmi WhatsApp.

◈ 6.1 · Text Rich
import { prepareRichResponseMessage } from 'elynn-baileys'

async function sendRichText(sock, jid) {
  const messageData = prepareRichResponseMessage({
    contentText: 'Ini adalah paragraf teks biasa yang dirender dalam kontainer rich response yang memiliki margin dan padding khusus.'
  })
  
  await sock.sendMessage(jid, messageData)
}
◈ 6.2 · Code Block
import { prepareRichResponseMessage } from 'elynn-baileys'

async function sendRichCode(sock, jid) {
  const kodeProgram = 'const status = "success";\nconsole.log(`Operasi selesai dengan status: ${status}`);'
  
  const messageData = prepareRichResponseMessage({
    headerText: 'Berikut adalah implementasi kode dalam JavaScript:',
    code: kodeProgram,
    language: 'javascript'
  })
  
  await sock.sendMessage(jid, messageData)
}
◈ 6.3 · Table
import { prepareRichResponseMessage } from 'elynn-baileys'

async function sendRichTable(sock, jid) {
  const tabelData = [
    ['Nama Menu', 'Harga', 'Ketersediaan'],
    ['Nasi Goreng Spesial', 'Rp 25.000', '✅ Tersedia'],
    ['Mie Goreng Seafood', 'Rp 30.000', '✅ Tersedia'],
    ['Es Teh Manis', 'Rp 5.000', '✅ Tersedia'],
    ['Ayam Bakar Madu', 'Rp 35.000', '❌ Habis']
  ]

  const messageData = prepareRichResponseMessage({
    headerText: 'Daftar Harga Lengkap:',
    title: 'Katalog Menu Restoran',
    table: tabelData,
    noHeading: false
  })
  
  await sock.sendMessage(jid, messageData)
}
◈ 6.4 · Inline Image
import { prepareRichResponseMessage } from 'elynn-baileys'

async function sendRichInlineImage(sock, jid) {
  const messageData = prepareRichResponseMessage({
    contentText: 'Gambar di bawah ini disisipkan langsung di dalam kotak pesan:',
    inlineImage: 'https://domain.com/gambar-inline.jpg',
    imageText: 'Ilustrasi pemandangan alam',
    tapLinkUrl: 'https://example.com/galeri'
  })
  
  await sock.sendMessage(jid, messageData)
}
import { prepareRichResponseMessage } from 'elynn-baileys'

async function sendRichCitation(sock, jid) {
  const messageData = prepareRichResponseMessage({
    links: [{
      text: 'Silakan merujuk ke dokumentasi resmi untuk rincian lebih lanjut',
      title: 'Dokumentasi API',
      url: 'https://example.com/docs',
      displayName: 'Portal Edukasi',
      sources: [{ 
        displayName: 'Portal Edukasi', 
        subtitle: 'Situs Referensi', 
        url: 'https://example.com/docs' 
      }]
    }]
  })
  
  await sock.sendMessage(jid, messageData)
}
◈ 6.6 · Rich Response Kombinasi
import { prepareRichResponseMessage } from 'elynn-baileys'

async function sendComplexRichResponse(sock, jid) {
  const tabelKombinasi = [
    { isHeading: true, items: ['Kolom Identitas', 'Kolom Status'] },
    { isHeading: false, items: ['Server Utama', 'Online'] },
    { isHeading: false, items: ['Server Cadangan', 'Maintenance'] }
  ]

  const messageData = prepareRichResponseMessage({
    richResponse: [
      { text: 'Sistem telah menyelesaikan analisis keseluruhan. Berikut adalah laporan terperinci:' },
      { code: [{ codeContent: 'function checkStatus() { return true; }', highlightType: 0 }], language: 'javascript' },
      { text: 'Kode di atas memvalidasi integritas data. Status server saat ini adalah:' },
      { table: tabelKombinasi, title: 'Status Infrastruktur Jaringan' },
      { inlineImage: 'https://domain.com/grafik-server.png', imageText: 'Grafik Beban Server' }
    ]
  })
  
  await sock.sendMessage(jid, messageData)
}

§ SECTION 07

07 — Group Management


API yang ekstensif untuk memanipulasi dan mengelola data serta operasional grup secara menyeluruh.

async function manageGroup(sock, jid) {
  const daftarAnggotaAwal = ['6281234567890@s.whatsapp.net', '6289876543210@s.whatsapp.net']
  const grupBaru = await sock.groupCreate('Grup Diskusi Internal', daftarAnggotaAwal)
  const idGrup = grupBaru.id

  const metadataGrup = await sock.groupMetadata(idGrup)

  const targetUser = ['628111222333@s.whatsapp.net']
  await sock.groupParticipantsUpdate(idGrup, targetUser, 'add')
  await sock.groupParticipantsUpdate(idGrup, targetUser, 'promote')
  await sock.groupParticipantsUpdate(idGrup, targetUser, 'demote')
  await sock.groupParticipantsUpdate(idGrup, targetUser, 'remove')

  await sock.groupUpdateSubject(idGrup, 'Grup Diskusi Internal v2')
  await sock.groupUpdateDescription(idGrup, 'Ini adalah deskripsi grup yang baru saja diperbarui melalui sistem bot otomatis.')
  await sock.updateProfilePicture(idGrup, { url: 'https://domain.com/ikon-grup.png' })

  const kodeUndangan = await sock.groupInviteCode(idGrup)
  await sock.groupRevokeInvite(idGrup)
  const infoUndangan = await sock.groupGetInviteInfo(kodeUndangan)
  await sock.groupAcceptInvite(kodeUndangan)

  await sock.groupSettingUpdate(idGrup, 'announcement')
  await sock.groupSettingUpdate(idGrup, 'not_announcement')
  await sock.groupSettingUpdate(idGrup, 'locked')
  await sock.groupSettingUpdate(idGrup, 'unlocked')

  await sock.groupToggleEphemeral(idGrup, 86400)
  await sock.groupJoinApprovalMode(idGrup, 'on')
  await sock.groupMemberAddMode(idGrup, 'admin_add')

  await sock.groupLeave(idGrup)

  const daftarGrupAktif = await sock.groupFetchAllParticipating()
}

§ SECTION 08

08 — Newsletter / Channel


Fungsionalitas penuh untuk memoderasi saluran informasi siaran satu arah (Channel WhatsApp).

async function manageNewsletter(sock) {
  const metadataChannelBaru = await sock.newsletterCreate('Saluran Berita Utama', 'Pusat informasi dan pembaruan sistem secara langsung dan cepat.')
  const idChannel = metadataChannelBaru.id

  await sock.newsletterFollow(idChannel)
  await sock.newsletterUnfollow(idChannel)

  await sock.newsletterMute(idChannel)
  await sock.newsletterUnmute(idChannel)

  await sock.newsletterUpdateName(idChannel, 'Berita Utama Revisi')
  await sock.newsletterUpdateDescription(idChannel, 'Pembaruan deskripsi untuk memperjelas tujuan dari saluran komunikasi ini.')
  await sock.newsletterUpdatePicture(idChannel, { url: 'https://domain.com/logo-channel.jpg' })
  await sock.newsletterRemovePicture(idChannel)

  const kodeInviteChannel = 'KODE_INVITE_YANG_VALID'
  const detailMetadataChannel = await sock.newsletterMetadata('invite', kodeInviteChannel)

  const idPesanServer = '1234567890'
  await sock.newsletterReactMessage(idChannel, idPesanServer, '🔥')

  const daftarSaluranDiikuti = await sock.newsletterSubscribed()

  const batasPesan = 10
  const daftarPesanChannel = await sock.newsletterFetchMessages('invite', kodeInviteChannel, batasPesan, null, null)

  await sock.newsletterDelete(idChannel)
}

§ SECTION 09

09 — Privacy & Profile


Pengaturan terkait profil pribadi pengguna dan konfigurasi privasi keamanan akun.

async function updateProfileAndPrivacy(sock) {
  const targetJid = '6281234567890@s.whatsapp.net'

  await sock.updateProfileName('Elynn Bot System')
  await sock.updateProfileStatus('Sistem berjalan dengan optimal dan sedang memonitor antrean tugas.')
  await sock.updateProfilePicture(targetJid, { url: 'https://domain.com/foto-profil-baru.jpg' })
  await sock.removeProfilePicture(targetJid)

  const tautanFotoProfil = await sock.profilePictureUrl(targetJid, 'image')
  const informasiBio = await sock.fetchStatus(targetJid)

  await sock.updateLastSeenPrivacy('all')
  await sock.updateOnlinePrivacy('all')
  await sock.updateProfilePicturePrivacy('all')
  await sock.updateStatusPrivacy('all')
  await sock.updateReadReceiptsPrivacy('all')
  await sock.updateGroupsAddPrivacy('all')
  await sock.updateCallPrivacy('all')
  await sock.updateMessagesPrivacy('all')
  await sock.updateDefaultDisappearingMode(86400)

  await sock.updateBlockStatus(targetJid, 'block')
  await sock.updateBlockStatus(targetJid, 'unblock')
  const daftarBlokir = await sock.fetchBlocklist()

  const nomorTelepon = '6281234567890'
  const hasilPengecekanWA = await sock.onWhatsApp(nomorTelepon)

  await sock.sendPresenceUpdate('composing', targetJid)
  await sock.sendPresenceUpdate('recording', targetJid)
  await sock.sendPresenceUpdate('paused', targetJid)
  await sock.presenceSubscribe(targetJid)
}

§ SECTION 10

10 — Handling Events


Cara komprehensif untuk mendaftarkan pendengar acara ke seluruh aktivitas yang terjadi di jaringan.

function setupEventHandlers(sock, saveCreds) {
  sock.ev.on('connection.update', (updatePayload) => {
    const koneksi = updatePayload.connection
    const pemutusanTerakhir = updatePayload.lastDisconnect
    const kodeQr = updatePayload.qr
    const loginBaru = updatePayload.isNewLogin
  })

  sock.ev.on('messages.upsert', (dataUpsert) => {
    const daftarPesan = dataUpsert.messages
    const tipeData = dataUpsert.type

    for (const dataPesan of daftarPesan) {
      const pengirimJid = dataPesan.key.remoteJid
      const dikirimOlehSaya = dataPesan.key.fromMe
      const apakahGrup = pengirimJid.endsWith('@g.us')
      
      const teksPesan = dataPesan.message?.conversation
                     || dataPesan.message?.extendedTextMessage?.text
                     || dataPesan.message?.imageMessage?.caption
                     || ''
                     
      console.log({ pengirimJid, dikirimOlehSaya, apakahGrup, teksPesan })
    }
  })

  sock.ev.on('messages.update', (dataPembaruanPesan) => {
  })

  sock.ev.on('messages.reaction', (dataReaksi) => {
  })

  sock.ev.on('message-receipt.update', (dataTandaTerima) => {
  })

  sock.ev.on('presence.update', (dataKehadiran) => {
    const identitasUser = dataKehadiran.id
    const statusKehadiran = dataKehadiran.presences
  })

  sock.ev.on('chats.update', (dataPembaruanChat) => {
  })

  sock.ev.on('chats.upsert', (dataChatBaru) => {
  })

  sock.ev.on('chats.delete', (dataPenghapusanChat) => {
  })

  sock.ev.on('contacts.upsert', (dataKontakBaru) => {
  })

  sock.ev.on('contacts.update', (dataPembaruanKontak) => {
  })

  sock.ev.on('groups.update', (dataPembaruanGrup) => {
  })

  sock.ev.on('group-participants.update', (dataAksiPesertaGrup) => {
    const idGrup = dataAksiPesertaGrup.id
    const daftarPeserta = dataAksiPesertaGrup.participants
    const jenisTindakan = dataAksiPesertaGrup.action
  })

  sock.ev.on('call', (dataPanggilanMasuk) => {
    for (const panggilan of dataPanggilanMasuk) {
      const idPanggilan = panggilan.id
      const pemanggil = panggilan.from
      
      sock.rejectCall(idPanggilan, pemanggil)
    }
  })

  sock.ev.on('labels.edit', (dataLabelDiedit) => {
  })

  sock.ev.on('labels.association', (dataAsosiasiLabel) => {
    const tipeAsosiasi = dataAsosiasiLabel.type
    const detailAsosiasi = dataAsosiasiLabel.association
  })

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

§ SECTION 11

11 — Elynn Plugins : Brat & Bratvid


elynn-baileys menyertakan 30+ plugin bawaan siap pakai mencakup AI, berita, downloader, search, stalk, info, dan maker. Plugin dapat diimport langsung atau diakses via objek plugins. Output tiap plugin mengikuti format { ok, type, result } — langsung bisa dipakai di sendMessage.

Key Method Endpoint Output Parameter
brat GET /api/maker/brat Sticker · img text string
bratvid GET /api/maker/bratvid Sticker · vid text string
import { plugins, listPlugins } from 'elynn-baileys'

// Cek plugin yang tersedia
console.log(listPlugins()) // ['ai', 'deepseek', 'qwq', 'glm', 'gpt', 'gita', 'cnbc', 'cnn', ..., 'brat', 'bratvid'] (30+ plugins)

// Kirim Brat image sebagai stiker
async function kirimBrat(sock, jid) {
  const hasil = await plugins.brat({ text: 'gabut nih' })
  if (!hasil.ok) return console.error(hasil.message)

  // hasil.type === 'sticker' — kirim langsung sebagai stiker
  await sock.sendMessage(jid, {
    sticker: { url: hasil.result },
  })
}

// Kirim Bratvid (video) sebagai stiker animasi
async function kirimBratvid(sock, jid) {
  const hasil = await plugins.bratvid({ text: 'literally me every monday' })
  if (!hasil.ok) return console.error(hasil.message)

  await sock.sendMessage(jid, {
    sticker: { url: hasil.result },
    isAnimated: true, // opsional — indikator untuk stiker bergerak
  })
}

// Contoh di dalam handler pesan bot
sock.ev.on('messages.upsert', async ({ messages }) => {
  for (const msg of messages) {
    const text  = msg.message?.conversation || msg.message?.extendedTextMessage?.text || ''
    const jid   = msg.key.remoteJid
    const isBot = msg.key.fromMe

    if (isBot || !text) continue

    if (text.startsWith('.brat ')) {
      const input = text.slice(6).trim()
      const res   = await plugins.brat({ text: input })
      if (res.ok) {
        await sock.sendMessage(jid, { sticker: { url: res.result } }, { quoted: msg })
      }
    }

    if (text.startsWith('.bratvid ')) {
      const input = text.slice(9).trim()
      const res   = await plugins.bratvid({ text: input })
      if (res.ok) {
        await sock.sendMessage(jid, { sticker: { url: res.result } }, { quoted: msg })
      }
    }
  }
})

Plugin Brat & Bratvid selalu mengembalikan { ok: boolean, type: 'sticker', result: string } di mana result adalah URL gambar/video yang bisa langsung dipakai di sendMessage. Tidak ada API key tambahan yang diperlukan — sudah ter-bundle di dalam library.


§ SECTION 12

12 — Read Messages & Presence


Kendali mutlak atas indikator pesan dibaca dan pelaporan presensi sesi secara waktu nyata.

async function markMessagesAsRead(sock, kunciPesanTunggal, arrayKunciPesan) {
  await sock.readMessages([kunciPesanTunggal])
  
  const kunciPesanSatu = arrayKunciPesan[0]
  const kunciPesanDua = arrayKunciPesan[1]
  const kunciPesanTiga = arrayKunciPesan[2]
  
  await sock.readMessages([kunciPesanSatu, kunciPesanDua, kunciPesanTiga])
}

§ SECTION 13

13 — Delete / Edit Pesan


Mekanisme pasca-pengiriman yang memungkinkan Anda menarik kembali atau merevisi pesan yang telah telanjur terkirim ke server tujuan.

async function modifySentMessages(sock, jid, kunciPesanTerkirim) {
  await sock.sendMessage(jid, {
    delete: kunciPesanTerkirim
  })

  await sock.sendMessage(jid, {
    edit: kunciPesanTerkirim,
    text: 'Ini adalah teks yang telah direvisi dan menggantikan konten pesan sebelumnya yang salah.'
  })
}

§ SECTION 14

14 — Message Options Tambahan


Modifikasi perilaku tambahan untuk pesan agar sesuai dengan spesifikasi kasus penggunaan tingkat lanjut.

import { p

Keywords