Events & Chat Management

Semua event yang bisa kamu dengerin, plus fungsi chat, grup, newsletter, dan profile.

Event System

Semua event dipancarin lewat sock.ev (EventEmitter). Cara pasang listener:

sock.ev.on('nama.event', async (data) => {
  // handle event
})

Untuk nge-remove listener:

sock.ev.off('nama.event', handler)

connection.update

Event paling penting. Dipanggil setiap ada perubahan status koneksi.

Data yang Diterima

PropertyTipeKapan Muncul
connection'open' | 'connecting' | 'close'Setiap perubahan status
lastDisconnect.errorBoom | ErrorPas close. Cek .output.statusCode
lastDisconnect.dateDateWaktu disconnect
qrstring | undefinedQR code (Base64) pas pairing QR
isNewLoginbooleanPas pairing berhasil
receivedPendingNotificationsbooleanPas semua notif offline terkirim
isOnlinebooleanStatus online/offline
reachoutTimeLockReachoutTimelockStateInfo pembatasan akun (kalo kena restrict)

Error Codes & Reconnect Logic

lastDisconnect.error.output.statusCode (kalo pake Boom):

CodeKonstantaArtiHarus Reconnect?
401DisconnectReason.loggedOutSession expired / logoutTidak. Harus pairing ulang
403DisconnectReason.forbiddenAkun diblokir / dibatasiTidak
408DisconnectReason.timedOut / connectionLostTimeout / koneksi putusYa
428DisconnectReason.connectionClosedKoneksi ditutup serverYa
440DisconnectReason.connectionReplacedDevice lain konekYa (kalo mau)
500DisconnectReason.badSessionSession corruptTidak. Hapus auth & pairing ulang
503DisconnectReason.unavailableServiceServer WA sibukYa (delay lebih lama)
515DisconnectReason.restartRequiredServer minta restart (normal pas pairing)Ya
sock.ev.on('connection.update', async ({ connection, lastDisconnect, qr, isNewLogin }) => {
  if (qr) console.log('Scan QR:', qr)
  if (isNewLogin) console.log('Login baru!')
  if (connection === 'open') console.log('Siap!')
  if (connection === 'close') {
    const code = lastDisconnect?.error?.output?.statusCode
    const shouldReconnect = ![401, 403, 500].includes(code)
    if (shouldReconnect) setTimeout(reconnect, 3000)
  }
})

messages.upsert

Event utama buat nerima & baca pesan. Dipanggil tiap kali ada pesan baru — baik dari orang lain maupun dari kita sendiri (kalo emitOwnEvents: true).

Data

PropertyTipeKeterangan
messagesWAMessage[]Array pesan (biasanya 1, bisa lebih)
type'notify' | 'append'notify = pesan real-time. append = dari history sync
requestIdstring | undefinedAda kalo pesan dari phone karena server ga punya

Cara Baca Pesan

sock.ev.on('messages.upsert', async ({ messages, type }) => {
  if (type !== 'notify') return  // skip history sync

  for (const msg of messages) {
    if (msg.key.fromMe) continue  // skip pesan sendiri

    const jid = msg.key.remoteJid
    const sender = msg.key.participant || jid
    const text = msg.message?.conversation
      || msg.message?.extendedTextMessage?.text
      || msg.message?.imageMessage?.caption
      || msg.message?.videoMessage?.caption
      || ''

    console.log('Pesan dari:', sender, 'Text:', text)
  }
})

Filter Pesan Diri Sendiri

// Lewati kalo dariMe
if (msg.key.fromMe) return

// Atau cuma proses dariMe
if (!msg.key.fromMe) return

messages.update

Event ini dipanggil saat ada perubahan pada pesan yang udah ada: status baca, edit, reaksi poll, dll.

Data

PropertyTipeKeterangan
keyWAMessageKeyKey pesan yang diupdate
updatePartial<WAMessage>Field yang berubah

Poll Updates

Waktu seseorang vote di poll, kita dapet messages.update dengan update.message.pollUpdateMessage. Property-nya:

sock.ev.on('messages.update', ({ key, update }) => {
  // Poll vote update
  const pollUpdate = update.message?.pollUpdateMessage
  if (pollUpdate) {
    console.log('Vote di poll', key.id, pollUpdate.vote?.selectedOptions)
  }

  // Pesan diedit
  if (update.message?.extendedTextMessage) {
    console.log('Pesan diedit:', key.id)
  }
})

messages.reaction

Dipanggil waktu seseorang kasih atau hapus reaksi.

Data

PropertyTipeKeterangan
keyWAMessageKeyKey pesan yang kena reaksi
reaction.textstring | nullEmoji reaksi. null = reaksi dihapus
reaction.keyWAMessageKeyKey pesan reaksi itu sendiri
sock.ev.on('messages.reaction', ({ key, reaction }) => {
  if (reaction.text) {
    console.log(`Dapat reaksi ${reaction.text} di pesan ${key.id}`)
  } else {
    console.log(`Reaksi dihapus dari pesan ${key.id}`)
  }
})

messages.delete

Dipanggil kalo ada pesan yang dihapus.

sock.ev.on('messages.delete', (data) => {
  if ('keys' in data) {
    console.log('Pesan dihapus:', data.keys.length)
  } else {
    console.log('Semua pesan dihapus di chat', data.jid)
  }
})

message-receipt.update

Notifikasi centang (delivery / read receipt).

sock.ev.on('message-receipt.update', (updates) => {
  for (const { key, receipt } of updates) {
    console.log(`Pesan ${key.id} udah dibaca ${receipt.readTimestamp}`)
  }
})

group-participants.update

Event kalo ada perubahan anggota grup: ada yang masuk, dikeluarin, di-promote, di-demote.

Data

PropertyTipeKeterangan
idstringJID grup
authorstringYang melakukan aksi
participantsstring[]Yang kena aksi
action'add' | 'remove' | 'promote' | 'demote'Aksi yang dilakukan
sock.ev.on('group-participants.update', ({ id, author, participants, action }) => {
  console.log(`[${action}] ${participants.join(', ')} oleh ${author} di ${id}`)

  if (action === 'add') {
    console.log('Anggota baru:', participants)
  }
  if (action === 'remove') {
    console.log('Anggota keluar:', participants)
  }
  if (action === 'promote') {
    console.log('Jadi admin:', participants)
  }
})

group.join-request

Kalo grup pake joinApprovalMode, event ini muncul pas ada yang minta gabung.

sock.ev.on('group.join-request', ({ id, author, participant, action, method }) => {
  console.log(`${participant} minta gabung ke ${id}`)
})

presence.update

Update status online/typing/recording dari user lain.

Data

PropertyTipeKeterangan
idstringJID chat
presences{ [participant]: PresenceData }Map participant ke presence mereka

PresenceData

FieldTipeKeterangan
lastKnownPresence'available' | 'unavailable' | 'composing' | 'recording' | 'paused'Status presence
lastSeennumber | undefinedTimestamp terakhir online
groupOnlineCountnumber | undefinedJumlah online di grup (kalo available)
sock.ev.on('presence.update', ({ id, presences }) => {
  for (const [participant, presence] of Object.entries(presences)) {
    console.log(`${participant}: ${presence.lastKnownPresence}`)
  }
})

call

Event pas ada panggilan masuk. Bisa ditolak pake sock.rejectCall.

sock.ev.on('call', async (calls) => {
  for (const call of calls) {
    console.log('Panggilan dari:', call.from, 'tipe:', call.isVideo ? 'video' : 'audio')

    // Tolak otomatis
    await sock.rejectCall(call.id, call.from)
  }
})

chats.upsert / chats.update / chats.delete

Event buat perubahan di daftar chat.

sock.ev.on('chats.upsert', (chats) => {
  console.log('Chat baru:', chats.length)
})

sock.ev.on('chats.update', (updates) => {
  for (const update of updates) {
    console.log('Chat diupdate:', update.id, update.unreadCount)
  }
})

sock.ev.on('chats.delete', (ids) => {
  console.log('Chat dihapus:', ids)
})

contacts.upsert / contacts.update

Update kontak — nama, photo, dll.

sock.ev.on('contacts.upsert', (contacts) => {
  for (const contact of contacts) {
    console.log('Kontak baru:', contact.id, contact.name)
  }
})

sock.ev.on('contacts.update', (updates) => {
  for (const update of updates) {
    console.log('Kontak update:', update.id, update.notify)
  }
})

creds.update

Update credential — key Signal, pairing, sync state. WAJIB di-save.

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

blocklist.set / blocklist.update

Event daftar blokir.

sock.ev.on('blocklist.set', ({ blocklist }) => {
  console.log('Blocklist:', blocklist)
})

sock.ev.on('blocklist.update', ({ blocklist, type }) => {
  console.log(`${type === 'add' ? 'Ditambah' : 'Dihapus'} dari blocklist:`, blocklist)
})

Event Lainnya

messaging-history.set

Data history sync — chats, contacts, messages dari server.

sock.ev.on('messaging-history.set', ({ chats, contacts, messages, isLatest }) => {
  console.log(`History: ${chats.length} chats, ${contacts.length} kontak, ${messages.length} pesan`)
})

messaging-history.status

Status progres history sync.

sock.ev.on('messaging-history.status', ({ syncType, status, explicit }) => {
  console.log(`Sync ${syncType}: ${status} (explicit: ${explicit})`)
})

lid-mapping.update

Mapping LID ke PN diperbarui.

messages.media-update

Update media — dipake internal buat updateMediaMessage.

labels.edit / labels.association

Event buat perubahan label.

settings.update

Perubahan setting: unarchiveChats, locale, disableLinkPreviews, dll.

chats.lock

Chat di-lock / unlock.

message-capping.update

Info batas pengiriman pesan (kalo kena spam limit).


Fungsi Chat Management

readMessages

Tandai pesan sebagai sudah dibaca (centang biru). Bisa bulk dari berbagai chat sekaligus.

// Baca 1 pesan
await sock.readMessages([messageKey])

// Baca banyak pesan dari berbagai chat
await sock.readMessages([key1, key2, key3])

Secara otomatis pake 'read' (centang biru) atau 'read-self' (centang doang) tergantung privacy settings user.

sendPresenceUpdate

Kirim status presence (online, typing, recording).

Parameter

TypeKeterangan
'available'Tandai online
'unavailable'Tandai offline
'composing'Status "typing..."
'recording'Status "recording..."
'paused'Berhenti typing
await sock.sendPresenceUpdate('available')          // Online
await sock.sendPresenceUpdate('composing', jid)     // Typing di chat tertentu
await sock.sendPresenceUpdate('recording', jid)    // Recording voice note
await sock.sendPresenceUpdate('paused', jid)       // Berhenti typing
await sock.sendPresenceUpdate('unavailable')       // Offline

chatModify

Fungsi umum buat modifikasi chat: archive, mute, pin, delete, star, mark unread, dll.

Cara Pake

// Archive chat
await sock.chatModify({ archive: true }, jid)

// Unarchive
await sock.chatModify({ archive: false }, jid)

// Pin chat (nomor urut pin)
await sock.chatModify({ pin: 1 }, jid)

// Unpin
await sock.chatModify({ pin: null }, jid)

// Mute chat untuk 8 jam (nilai dalam detik)
await sock.chatModify({ mute: 28800 }, jid)

// Mute forever
await sock.chatModify({ mute: -1 }, jid)

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

// Tandai belum dibaca
await sock.chatModify({ markRead: false }, jid)

// Tandai sudah dibaca
await sock.chatModify({ markRead: true }, jid)

// Hapus chat (clear messages)
await sock.chatModify({ clear: 'all' }, jid)

// Star pesan
await sock.star(jid, [{ id: msgKey.id, fromMe: msgKey.fromMe }], true)

// Unstar pesan
await sock.star(jid, [{ id: msgKey.id }], false)

// Delete chat
await sock.chatModify({ delete: true }, jid)

Profile Functions

updateProfilePicture

// Update foto profil sendiri
await sock.updateProfilePicture(sock.user?.id, fs.readFileSync('./foto.jpg'))

// Update foto grup (butuh admin)
await sock.updateProfilePicture('123456@g.us', { url: './grup.jpg' }, { width: 640, height: 640 })

removeProfilePicture

await sock.removeProfilePicture(jid)

updateProfileStatus

await sock.updateProfileStatus('Hidup itu indah')

updateProfileName

await sock.updateProfileName('Nama Baru')

profilePictureUrl

const url = await sock.profilePictureUrl('628xxx@s.whatsapp.net', 'image')  // HQ
const preview = await sock.profilePictureUrl('628xxx@s.whatsapp.net', 'preview')  // LQ

Privacy Settings

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

Fungsi Grup

groupCreate

const group = await sock.groupCreate('Nama Grup', [
  '628xxx@s.whatsapp.net',
  '628yyy@s.whatsapp.net',
])
console.log('Grup ID:', group.id)

groupMetadata

const meta = await sock.groupMetadata('123456@g.us')
console.log(meta.subject, meta.size, meta.owner, meta.desc)
console.log(meta.participants) // [{ id, admin, lid }]
console.log(meta.restrict, meta.announce, meta.ephemeralDuration)

groupParticipantsUpdate

// Tambah anggota
const result = await sock.groupParticipantsUpdate('123@g.us', ['628xxx@s.whatsapp.net'], 'add')

// Keluarkan
await sock.groupParticipantsUpdate('123@g.us', ['628xxx@s.whatsapp.net'], 'remove')

// Jadikan admin
await sock.groupParticipantsUpdate('123@g.us', ['628xxx@s.whatsapp.net'], 'promote')

// Hapus admin
await sock.groupParticipantsUpdate('123@g.us', ['628xxx@s.whatsapp.net'], 'demote')

Group Settings

// Ubah nama grup
await sock.groupUpdateSubject('123@g.us', 'Nama Baru')

// Ubah deskripsi
await sock.groupUpdateDescription('123@g.us', 'Deskripsi baru')

// Hapus deskripsi
await sock.groupUpdateDescription('123@g.us')

// Set grup hanya admin yang bisa kirim pesan (announcement)
await sock.groupSettingUpdate('123@g.us', 'announcement')

// Buka grup (semua bisa kirim)
await sock.groupSettingUpdate('123@g.us', 'not_announcement')

// Kunci grup (hanya admin bisa edit)
await sock.groupSettingUpdate('123@g.us', 'locked')

// Buka kunci
await sock.groupSettingUpdate('123@g.us', 'unlocked')

// Mode tambah anggota
await sock.groupMemberAddMode('123@g.us', 'admin_add')        // Hanya admin
await sock.groupMemberAddMode('123@g.us', 'all_member_add')   // Semua anggota

// Join approval mode (setuju-admin)
await sock.groupJoinApprovalMode('123@g.us', 'on')
await sock.groupJoinApprovalMode('123@g.us', 'off')

// Disappearing messages di grup
await sock.groupToggleEphemeral('123@g.us', 86400)   // 24 jam
await sock.groupToggleEphemeral('123@g.us', 0)       // matikan

Invite Grup

// Dapetin kode invite
const code = await sock.groupInviteCode('123@g.us')

// Revoke / buat ulang kode invite
const newCode = await sock.groupRevokeInvite('123@g.us')

// Terima invite pake kode
const groupJid = await sock.groupAcceptInvite('abc123')

// Info grup dari kode invite
const info = await sock.groupGetInviteInfo('abc123')

// Terima GroupInviteMessage (v4)
await sock.groupAcceptInviteV4(msg.key, msg.message.groupInviteMessage)

// Revoke invite untuk seseorang (v4)
await sock.groupRevokeInviteV4('123@g.us', '628xxx@s.whatsapp.net')

Lain-lain Grup

// Keluar grup
await sock.groupLeave('123@g.us')

// Fetch semua grup yang diikuti
const allGroups = await sock.groupFetchAllParticipating()
console.log(Object.keys(allGroups))

// Daftar minta gabung (join request)
const requests = await sock.groupRequestParticipantsList('123@g.us')

// Setujui / tolak minta gabung
await sock.groupRequestParticipantsUpdate('123@g.us', ['628xxx@s.whatsapp.net'], 'approve')

Fungsi Newsletter / Channel

Mengelola Newsletter

// Buat newsletter
const nl = await sock.newsletterCreate('Nama Channel', 'Deskripsi channel')

// Ambil metadata
const meta = await sock.newsletterMetadata('jid', '123@newsletter')
const metaByInvite = await sock.newsletterMetadata('invite', 'invitecode')

// Follow / unfollow
await sock.newsletterFollow('123@newsletter')
await sock.newsletterUnfollow('123@newsletter')

// Mute / unmute
await sock.newsletterMute('123@newsletter')
await sock.newsletterUnmute('123@newsletter')

// Update nama, deskripsi
await sock.newsletterUpdateName('123@newsletter', 'Nama Baru')
await sock.newsletterUpdateDescription('123@newsletter', 'Deskripsi baru')

// Update foto
await sock.newsletterUpdatePicture('123@newsletter', fs.readFileSync('./foto.jpg'))
await sock.newsletterRemovePicture('123@newsletter')

// Hapus newsletter
await sock.newsletterDelete('123@newsletter')

// Hitung subscriber
const { subscribers } = await sock.newsletterSubscribers('123@newsletter')

// Jumlah admin
const adminCount = await sock.newsletterAdminCount('123@newsletter')

// Kirim reaksi ke pesan newsletter
await sock.newsletterReactMessage('123@newsletter', 'server_id_pesan', '🔥')
await sock.newsletterReactMessage('123@newsletter', 'server_id_pesan')  // hapus reaksi

// Fetch pesan newsletter
const messages = await sock.newsletterFetchMessages('123@newsletter', 50, 0, 0)

// Subscribe live updates (dapet notif real-time)
const live = await sock.subscribeNewsletterUpdates('123@newsletter')

// Ganti owner / demote admin
await sock.newsletterChangeOwner('123@newsletter', '628xxx@s.whatsapp.net')
await sock.newsletterDemote('123@newsletter', '628xxx@s.whatsapp.net')

Event Newsletter

sock.ev.on('newsletter.reaction', ({ id, server_id, reaction }) => {
  console.log('Reaksi di newsletter:', id, reaction)
})

sock.ev.on('newsletter.view', ({ id, server_id, count }) => {
  console.log('Dilihat:', count, 'kali')
})

sock.ev.on('newsletter-participants.update', ({ id, author, user, new_role, action }) => {
  console.log(`${user} ${action} sebagai ${new_role}`)
})

sock.ev.on('newsletter-settings.update', ({ id, update }) => {
  console.log('Setting newsletter berubah', id)
})
← Kembali Lanjut: Lanjutan →