Semua event yang bisa kamu dengerin, plus fungsi chat, grup, newsletter, dan profile.
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)
Event paling penting. Dipanggil setiap ada perubahan status koneksi.
| Property | Tipe | Kapan Muncul |
|---|---|---|
connection | 'open' | 'connecting' | 'close' | Setiap perubahan status |
lastDisconnect.error | Boom | Error | Pas close. Cek .output.statusCode |
lastDisconnect.date | Date | Waktu disconnect |
qr | string | undefined | QR code (Base64) pas pairing QR |
isNewLogin | boolean | Pas pairing berhasil |
receivedPendingNotifications | boolean | Pas semua notif offline terkirim |
isOnline | boolean | Status online/offline |
reachoutTimeLock | ReachoutTimelockState | Info pembatasan akun (kalo kena restrict) |
lastDisconnect.error.output.statusCode (kalo pake Boom):
| Code | Konstanta | Arti | Harus Reconnect? |
|---|---|---|---|
| 401 | DisconnectReason.loggedOut | Session expired / logout | Tidak. Harus pairing ulang |
| 403 | DisconnectReason.forbidden | Akun diblokir / dibatasi | Tidak |
| 408 | DisconnectReason.timedOut / connectionLost | Timeout / koneksi putus | Ya |
| 428 | DisconnectReason.connectionClosed | Koneksi ditutup server | Ya |
| 440 | DisconnectReason.connectionReplaced | Device lain konek | Ya (kalo mau) |
| 500 | DisconnectReason.badSession | Session corrupt | Tidak. Hapus auth & pairing ulang |
| 503 | DisconnectReason.unavailableService | Server WA sibuk | Ya (delay lebih lama) |
| 515 | DisconnectReason.restartRequired | Server 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) } })
Event utama buat nerima & baca pesan. Dipanggil tiap kali ada pesan baru — baik dari orang lain maupun dari kita sendiri (kalo emitOwnEvents: true).
| Property | Tipe | Keterangan |
|---|---|---|
messages | WAMessage[] | Array pesan (biasanya 1, bisa lebih) |
type | 'notify' | 'append' | notify = pesan real-time. append = dari history sync |
requestId | string | undefined | Ada kalo pesan dari phone karena server ga punya |
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) } })
// Lewati kalo dariMe if (msg.key.fromMe) return // Atau cuma proses dariMe if (!msg.key.fromMe) return
Event ini dipanggil saat ada perubahan pada pesan yang udah ada: status baca, edit, reaksi poll, dll.
| Property | Tipe | Keterangan |
|---|---|---|
key | WAMessageKey | Key pesan yang diupdate |
update | Partial<WAMessage> | Field yang berubah |
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) } })
Dipanggil waktu seseorang kasih atau hapus reaksi.
| Property | Tipe | Keterangan |
|---|---|---|
key | WAMessageKey | Key pesan yang kena reaksi |
reaction.text | string | null | Emoji reaksi. null = reaksi dihapus |
reaction.key | WAMessageKey | Key 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}`) } })
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) } })
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}`) } })
Event kalo ada perubahan anggota grup: ada yang masuk, dikeluarin, di-promote, di-demote.
| Property | Tipe | Keterangan |
|---|---|---|
id | string | JID grup |
author | string | Yang melakukan aksi |
participants | string[] | 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) } })
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}`) })
Update status online/typing/recording dari user lain.
| Property | Tipe | Keterangan |
|---|---|---|
id | string | JID chat |
presences | { [participant]: PresenceData } | Map participant ke presence mereka |
| Field | Tipe | Keterangan |
|---|---|---|
lastKnownPresence | 'available' | 'unavailable' | 'composing' | 'recording' | 'paused' | Status presence |
lastSeen | number | undefined | Timestamp terakhir online |
groupOnlineCount | number | undefined | Jumlah 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}`) } })
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) } })
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) })
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) } })
Update credential — key Signal, pairing, sync state. WAJIB di-save.
sock.ev.on('creds.update', saveCreds)
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) })
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`) })
Status progres history sync.
sock.ev.on('messaging-history.status', ({ syncType, status, explicit }) => { console.log(`Sync ${syncType}: ${status} (explicit: ${explicit})`) })
Mapping LID ke PN diperbarui.
Update media — dipake internal buat updateMediaMessage.
Event buat perubahan label.
Perubahan setting: unarchiveChats, locale, disableLinkPreviews, dll.
Chat di-lock / unlock.
Info batas pengiriman pesan (kalo kena spam limit).
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.
Kirim status presence (online, typing, recording).
| Type | Keterangan |
|---|---|
'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
Fungsi umum buat modifikasi chat: archive, mute, pin, delete, star, mark unread, dll.
// 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)
// 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 })
await sock.removeProfilePicture(jid)
await sock.updateProfileStatus('Hidup itu indah')
await sock.updateProfileName('Nama Baru')
const url = await sock.profilePictureUrl('628xxx@s.whatsapp.net', 'image') // HQ const preview = await sock.profilePictureUrl('628xxx@s.whatsapp.net', 'preview') // LQ
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)
const group = await sock.groupCreate('Nama Grup', [ '628xxx@s.whatsapp.net', '628yyy@s.whatsapp.net', ]) console.log('Grup ID:', group.id)
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)
// 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')
// 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
// 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')
// 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')
// 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')
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) })