kezabaileys
v4.0.0
Published
A WebSockets
Readme
kezbail
Catatan Penting
Ini README sementara. Panduan lengkap akan dirilis ketika siap.
Disclaimer
Proyek ini tidak berafiliasi, diasosiasikan, disahkan, didukung, atau terhubung secara resmi dengan WhatsApp maupun anak perusahaannya.
"WhatsApp" serta nama, merek, dan logo terkait adalah merek dagang milik pemiliknya masing‑masing.
Pengelola kezbail tidak menganjurkan penggunaan yang melanggar Ketentuan Layanan WhatsApp. Gunakan secara bertanggung jawab.
Segala bentuk spam, stalkerware, atau pengiriman pesan massal/otomatis tidak disarankan.
Gunakan atas risiko Anda sendiri.
Ringkasan
- Terhubung langsung ke WhatsApp Web menggunakan WebSocket (tanpa Selenium/Chromium).
- Mendukung multi-device & Web.
- Hemat RAM karena tidak memerlukan browser headless.
- Dapat digunakan untuk membuat bot, integrasi internal, atau tooling otomasi.
Peringatan Perubahan internal WhatsApp dapat menyebabkan API tidak stabil sewaktu‑waktu. Lakukan monitoring & update rutin.
Instalasi
Gunakan versi stabil (contoh via yarn):
yarn add kezbail
# atau
npm i kezbailImpor pada kode Anda:
import makeWASocket from 'kezbail'Catatan
Jika Anda mengembangkan dari source lokal, sesuaikan langkah instalasi sesuai workflow Anda (monorepo, pnpm workspaces, dll.).
Indeks
- Menghubungkan Akun
- Catatan Penting tentang Konfigurasi Socket
- Menyimpan & Memulihkan Sesi
- Menangani Event
- Membuat Data Store
- Format WhatsApp ID
- Fungsi Utilitas
- Mengirim Pesan
- Modifikasi Pesan
- Manipulasi Media
- Menolak Panggilan
- Status Chat (Read/Preset)
- Modifikasi Chat
- Query Pengguna
- Ubah Profil
- Grup
- Privasi
- Broadcast & Stories
- Menulis Fungsionalitas Kustom
- Lisensi
Menghubungkan Akun
WhatsApp multi-device memungkinkan kezbail diautentikasi sebagai klien kedua dengan memindai QR Code atau menggunakan Pairing Code dari ponsel Anda.
Tip
Lihat Intellisense/TypeScript types untuk semua opsi konfigurasi socket yang didukung.
QR Code
import makeWASocket, { Browsers } from 'kezbail'
const sock = makeWASocket({
browser: Browsers.ubuntu('My App'),
printQRInTerminal: true
})Setelah terhubung, QR akan tercetak di terminal. Pindai dengan WhatsApp di ponsel Anda.
Pairing Code
Info
Pairing Code adalah cara login WhatsApp Web tanpa memindai QR. Hanya untuk satu perangkat pada satu waktu.
Nomor telepon harus hanya digit (tanpa+,(), atau-) dan sertakan kode negara.
import makeWASocket from 'kezbail'
const sock = makeWASocket({ printQRInTerminal: false })
if (!sock.authState.creds.registered) {
const number = '6281234567890'
const code = await sock.requestPairingCode(number)
console.log(code)
}Menerima Riwayat Penuh
import makeWASocket, { Browsers } from 'kezbail'
const sock = makeWASocket({
browser: Browsers.macOS('Desktop'),
syncFullHistory: true
})Catatan Penting tentang Konfigurasi Socket
Cache Metadata Grup (Disarankan)
import NodeCache from 'node-cache'
import makeWASocket from 'kezbail'
const groupCache = new NodeCache({ stdTTL: 5 * 60, useClones: false })
const sock = makeWASocket({
cachedGroupMetadata: async (jid) => groupCache.get(jid)
})
sock.ev.on('groups.update', async ([ev]) => {
const meta = await sock.groupMetadata(ev.id)
groupCache.set(ev.id, meta)
})
sock.ev.on('group-participants.update', async (ev) => {
const meta = await sock.groupMetadata(ev.id)
groupCache.set(ev.id, meta)
})Perbaiki Retry & Dekripsi Poll
const sock = makeWASocket({
getMessage: async (key) => await getMessageFromStore(key)
})Notifikasi di Aplikasi WhatsApp
const sock = makeWASocket({
markOnlineOnConnect: false
})Menyimpan & Memulihkan Sesi
import makeWASocket, { useMultiFileAuthState } from 'kezbail'
const { state, saveCreds } = await useMultiFileAuthState('auth_info_kezbail')
const sock = makeWASocket({ auth: state })
sock.ev.on('creds.update', saveCreds)Penting
Simpan perubahanauthState.keyssetiap ada pembaruan agar pengiriman pesan tetap berjalan.
Menangani Event
const sock = makeWASocket()
sock.ev.on('messages.upsert', ({ messages }) => {
console.log('got messages', messages)
})Contoh Awal
import makeWASocket, { DisconnectReason, useMultiFileAuthState } from 'kezbail'
import { Boom } from '@hapi/boom'
async function connect () {
const { state, saveCreds } = await useMultiFileAuthState('auth_info_kezbail')
const sock = makeWASocket({ auth: state, printQRInTerminal: true })
sock.ev.on('connection.update', (update) => {
const { connection, lastDisconnect } = update
if (connection === 'close') {
const shouldReconnect = (lastDisconnect.error as Boom)?.output?.statusCode !== DisconnectReason.loggedOut
if (shouldReconnect) connect()
} else if (connection === 'open') {
console.log('opened connection')
}
})
sock.ev.on('messages.upsert', async (event) => {
for (const m of event.messages) {
await sock.sendMessage(m.key.remoteJid!, { text: 'Hello World' })
}
})
sock.ev.on('creds.update', saveCreds)
}
connect()Dekripsi Poll
sock.ev.on('messages.update', async (event) => {
for (const { key, update } of event) {
if (update.pollUpdates) {
const pollCreation = await getMessage(key)
if (pollCreation) {
console.log('poll aggregation:', getAggregateVotesInPollMessage({
message: pollCreation,
pollUpdates: update.pollUpdates
}))
}
}
}
})Ringkasan Event Saat Pertama Connect
connection.updatememinta restart socket di awal.- Riwayat akan masuk melalui event
messaging.history-set.
Membuat Data Store
Contoh in-memory store sederhana:
import makeWASocket, { makeInMemoryStore } from 'kezbail'
const store = makeInMemoryStore({})
store.readFromFile('./kezbail_store.json')
setInterval(() => store.writeToFile('./kezbail_store.json'), 10_000)
const sock = makeWASocket({})
store.bind(sock.ev)
sock.ev.on('chats.upsert', () => {
console.log('chats', store.chats.all())
})
sock.ev.on('contacts.upsert', () => {
console.log('contacts', Object.values(store.contacts))
})Format WhatsApp ID
- Pribadi:
[email protected] - Grup:
[email protected] - Broadcast:
[timestamp]@broadcast - Status/Stories:
status@broadcast
Fungsi Utilitas
Beberapa utilitas umum:
getContentType(message)getDevice(message)makeCacheableSignalKeyStore(store)downloadContentFromMessage(message, type)
Mengirim Pesan
API dasar:
const jid: string
const content: AnyMessageContent
const options: MiscMessageGenerationOptions
await sock.sendMessage(jid, content, options)Non-Media
// teks
await sock.sendMessage(jid, { text: 'hello world' })
// quote
await sock.sendMessage(jid, { text: 'reply' }, { quoted: message })
// mention
await sock.sendMessage(jid, {
text: '@6281234567890',
mentions: ['[email protected]']
})
// forward
const msg = getMessageFromStore()
await sock.sendMessage(jid, { forward: msg })
// lokasi
await sock.sendMessage(jid, { location: { degreesLatitude: -6.2, degreesLongitude: 106.8 } })
// kontak
const vcard = `BEGIN:VCARD
VERSION:3.0
FN:John Doe
ORG:My Org
TEL;type=CELL;type=VOICE;waid=6281234567890:+62 812-3456-7890
END:VCARD`
await sock.sendMessage(jid, { contacts: { displayName: 'John', contacts: [{ vcard }] } })
// reaksi
await sock.sendMessage(jid, { react: { text: '💖', key: message.key } })
// pin message
await sock.sendMessage(jid, { pin: { type: 1, time: 86400, key: message.key } })
// poll
await sock.sendMessage(jid, { poll: { name: 'Pilih satu', values: ['A', 'B'], selectableCount: 1 } })Preview Tautan
await sock.sendMessage(jid, {
text: 'Cek ini: https://example.com/article'
})Media (GIF/Video/Audio/Gambar/ViewOnce)
// gif (mp4 + gifPlayback)
await sock.sendMessage(jid, {
video: fs.readFileSync('Media/gif.mp4'),
caption: 'hai',
gifPlayback: true
})
// video
await sock.sendMessage(jid, {
video: { url: './Media/video.mp4' },
caption: 'hai',
ptv: false
})
// audio
await sock.sendMessage(jid, {
audio: { url: './Media/voice.ogg' },
mimetype: 'audio/ogg; codecs=opus'
})
// gambar
await sock.sendMessage(jid, {
image: { url: './Media/photo.png' },
caption: 'hai'
})
// view once
await sock.sendMessage(jid, {
image: { url: './Media/photo.png' },
viewOnce: true,
caption: 'sekali lihat'
})Modifikasi Pesan
// hapus untuk semua
const sent = await sock.sendMessage(jid, { text: 'hapus aku' })
await sock.sendMessage(jid, { delete: sent.key })
// edit
await sock.sendMessage(jid, { text: 'teks baru', edit: sent.key })Manipulasi Media
- Thumbnail untuk gambar/stiker dapat dibuat otomatis jika Anda menambahkan dependensi
sharpataujimp. - Thumbnail video memerlukan
ffmpegterpasang. - Re-upload media lama:
await sock.updateMediaMessage(msg)Menolak Panggilan
await sock.rejectCall(callId, callFrom)Status Chat (Read/Preset)
Membaca Pesan
const key: WAMessageKey
await sock.readMessages([key])Update Presence
await sock.sendPresenceUpdate('available', jid)
// atau offline untuk menerima push notifikasi
await sock.sendPresenceUpdate('unavailable')Modifikasi Chat
- Arsipkan
const last = await getLastMessageInChat(jid)
await sock.chatModify({ archive: true, lastMessages: [last] }, jid)- Mute/Unmute
await sock.chatModify({ mute: 8 * 60 * 60 * 1000 }, jid)
await sock.chatModify({ mute: null }, jid)- Tandai baca/tidak dibaca
const last = await getLastMessageInChat(jid)
await sock.chatModify({ markRead: false, lastMessages: [last] }, jid)- Hapus untuk diri sendiri
await sock.chatModify({
clear: { messages: [{ id: 'ID', fromMe: true, timestamp: '1654823909' }] }
}, jid)- Hapus chat
const last = await getLastMessageInChat(jid)
await sock.chatModify({ delete: true, lastMessages: [{ key: last.key, messageTimestamp: last.messageTimestamp }] }, jid)- Pin/Unpin chat
await sock.chatModify({ pin: true }, jid)- Bintang pesan
await sock.chatModify({
star: { messages: [{ id: 'messageID', fromMe: true }], star: true }
}, jid)- Disappearing messages (detik): 0, 86400 (24h), 604800 (7d), 7776000 (90d)
await sock.sendMessage(jid, { disappearingMessagesInChat: 604800 })
await sock.sendMessage(jid, { text: 'hello' }, { ephemeralExpiration: 604800 })
await sock.sendMessage(jid, { disappearingMessagesInChat: false })Query Pengguna
// cek nomor
const [res] = await sock.onWhatsApp(jid)
if (res?.exists) console.log(`${jid} terdaftar sebagai ${res.jid}`)
// histori chat (perlu pesan tertua)
const oldest = await getOldestMessageInChat(jid)
await sock.fetchMessageHistory(50, oldest.key, oldest.messageTimestamp)
// status
const status = await sock.fetchStatus(jid)
console.log('status:', status)
// foto profil (low/high-res)
const pp = await sock.profilePictureUrl(jid) // low
const ppHigh = await sock.profilePictureUrl(jid, 'image') // highUbah Profil
await sock.updateProfileStatus('Hello World!')
await sock.updateProfileName('Nama Saya')
await sock.updateProfilePicture(jid, { url: './new-pp.jpeg' })
await sock.removeProfilePicture(jid)Grup
Untuk memodifikasi properti grup Anda harus menjadi admin.
// buat grup
const group = await sock.groupCreate('Grup Keren', ['[email protected]'])
await sock.sendMessage(group.id, { text: 'halo semua' })
// tambah/hapus/promote/demote
await sock.groupParticipantsUpdate(jid, ['[email protected]'], 'add')
// ganti subjek & deskripsi
await sock.groupUpdateSubject(jid, 'Subjek Baru')
await sock.groupUpdateDescription(jid, 'Deskripsi Baru')
// pengaturan
await sock.groupSettingUpdate(jid, 'announcement') // hanya admin yang boleh kirim
await sock.groupSettingUpdate(jid, 'not_announcement') // semua boleh kirim
await sock.groupSettingUpdate(jid, 'locked') // hanya admin boleh ubah info
await sock.groupSettingUpdate(jid, 'unlocked') // semua boleh ubah info
// keluar
await sock.groupLeave(jid)
// undangan
const code = await sock.groupInviteCode(jid)
const info = await sock.groupGetInviteInfo(code)
const joined = await sock.groupAcceptInvite(code)
await sock.groupRevokeInvite(jid)
// metadata & tools lain
const meta = await sock.groupMetadata(jid)
const all = await sock.groupFetchAllParticipating()
await sock.groupToggleEphemeral(jid, 86400)
await sock.groupMemberAddMode(jid, 'all_member_add') // atau 'admin_add'
// permintaan join
const reqs = await sock.groupRequestParticipantsList(jid)
await sock.groupRequestParticipantsUpdate(jid, ['[email protected]'], 'approve')Privasi
await sock.updateBlockStatus(jid, 'block')
await sock.updateBlockStatus(jid, 'unblock')
const privacy = await sock.fetchPrivacySettings(true)
const blocked = await sock.fetchBlocklist()
await sock.updateLastSeenPrivacy('all') // 'contacts' | 'contact_blacklist' | 'none'
await sock.updateOnlinePrivacy('match_last_seen')
await sock.updateProfilePicturePrivacy('contacts')
await sock.updateStatusPrivacy('all')
await sock.updateReadReceiptsPrivacy('all') // 'none'
await sock.updateGroupsAddPrivacy('contacts')
await sock.updateDefaultDisappearingMode(86400)Broadcast & Stories
await sock.sendMessage(
jid,
{ image: { url: './Media/photo.png' }, caption: 'status baru' },
{ backgroundColor: '#000000', font: 0, statusJidList: [], broadcast: true }
)ID broadcast berbentuk
12345678@broadcast.
Menulis Fungsionalitas Kustom
Debug Log
const sock = makeWASocket({
logger: P({ level: 'debug' })
})Callback untuk WebSocket Event
// untuk node tertentu
sock.ws.on('CB:edge_routing', (node: BinaryNode) => {})
sock.ws.on('CB:edge_routing,id:abcd', (node: BinaryNode) => {})
sock.ws.on('CB:edge_routing,id:abcd,routing_info', (node: BinaryNode) => {})Tip: Pelajari libsignal & noise protocol untuk memahami cara kerja protokol.
Lisensi
Copyright (c) 2025 kezbail contributors
Dilisensikan di bawah MIT License:
Izin diberikan secara gratis kepada siapa pun untuk mendapatkan salinan perangkat lunak ini dan dokumentasinya (“Perangkat Lunak”), untuk memperlakukan Perangkat Lunak tanpa batas, termasuk tanpa batasan hak untuk menggunakan, menyalin, memodifikasi, menggabungkan, memublikasikan, mendistribusikan, mensublisensikan, dan/atau menjual salinan Perangkat Lunak, dan mengizinkan orang yang diberikan Perangkat Lunak melakukannya, dengan ketentuan berikut:
Pernyataan hak cipta di atas dan pernyataan izin ini harus disertakan dalam semua salinan atau bagian substansial dari Perangkat Lunak.
PERANGKAT LUNAK INI DIBERIKAN “SEBAGAIMANA ADANYA”, TANPA JAMINAN APA PUN, TERSURAT MAUPUN TERSIRAT, TERMASUK NAMUN TIDAK TERBATAS PADA JAMINAN KELAYAKAN DIPERDAGANGKAN, KECOCOKAN UNTUK TUJUAN TERTENTU, DAN BEBAS PELANGGARAN. DALAM KEADAAN APA PUN, PENULIS ATAU PEMEGANG HAK CIPTA TIDAK BERTANGGUNG JAWAB ATAS KLAIM, KERUSAKAN, ATAU KEWAJIBAN LAIN, BAIK DALAM KONTRAK, PERBUATAN MELAWAN HUKUM, ATAU LAINNYA, YANG TIMBUL DARI, DARI, ATAU SEHUBUNGAN DENGAN PERANGKAT LUNAK ATAU PENGGUNAAN ATAU TRANSAKSI LAIN DALAM PERANGKAT LUNAK.
