levvleys
v2.1.0
Published
WhatsApp Web API Library
Maintainers
Readme
LevviCode
💝 Donasi
Dukung pengembangan proyek ini melalui:
- Saweria: https://saweria.co/levvicode
✨ Fitur Utama
- 🚀 Modern & Cepat – Dibangun dengan TypeScript dan teknologi terkini.
- 🔧 Perbaikan @lid & @jid – Mengatasi masalah ID lokal ke ID ponsel di grup WhatsApp.
- 📱 Dukungan Multi‑Device – Koneksi penuh ke WhatsApp Multi‑Device.
- 🔐 Enkripsi End‑to‑End – Semua pesan terenkripsi.
- 📨 Semua Jenis Pesan – Teks, media (gambar, video, audio), polling, stiker, lokasi, kontak, dan lainnya.
- 🧩 Ringan & Optimal – Performa stabil dengan dukungan streaming media.
- 📂 Manajemen Autentikasi – Simpan kredensial di file atau database.
⚠️ Peringatan
Proyek ini tidak berafiliasi, didukung, atau terhubung secara resmi dengan WhatsApp atau anak perusahaannya. Situs resmi WhatsApp: whatsapp.com.
Pengguna bertanggung jawab penuh atas penggunaan aplikasi ini. Hindari spam dan otomatisasi berlebihan yang melanggar Ketentuan Layanan WhatsApp.
📦 Instalasi
Versi Stabil (Direkomendasikan)
npm install levvleysVersi Terbaru (Edge)
npm install levvleys@latest
# atau dengan yarn
yarn add levvleys@latestCara Impor
// CommonJS
const { default: makeWASocket } = require("levvleys")
// ES6 Module
import makeWASocket from "levvleys"🚀 Mulai Cepat
Contoh Dasar (dengan QR Code)
const { default: makeWASocket, DisconnectReason, useMultiFileAuthState } = require('levvleys')
const { Boom } = require('@hapi/boom')
async function connectToWhatsApp() {
// Simpan kredensial di folder 'auth_info_levvleys'
const { state, saveCreds } = await useMultiFileAuthState('auth_info_levvleys')
const sock = makeWASocket({
auth: state,
printQRInTerminal: true,
browser: ['LevviCode', 'Desktop', '3.0']
})
// Event koneksi
sock.ev.on('connection.update', (update) => {
const { connection, lastDisconnect } = update
if (connection === 'close') {
const shouldReconnect = (lastDisconnect?.error as Boom)?.output?.statusCode !== DisconnectReason.loggedOut
console.log('Koneksi tertutup, reconnecting:', shouldReconnect)
if (shouldReconnect) connectToWhatsApp()
} else if (connection === 'open') {
console.log('✅ Berhasil terhubung ke WhatsApp!')
}
})
// Event pesan masuk
sock.ev.on('messages.upsert', async ({ messages }) => {
for (const m of messages) {
if (!m.message) continue
console.log('📱 Pesan baru:', JSON.stringify(m, undefined, 2))
// Balas otomatis
await sock.sendMessage(m.key.remoteJid!, {
text: 'Halo! Saya bot WhatsApp menggunakan levvleys 🤖'
})
}
})
// Simpan kredensial saat diperbarui
sock.ev.on('creds.update', saveCreds)
}
connectToWhatsApp()🔌 Koneksi Akun
WhatsApp menyediakan API multi‑device yang memungkinkan levvleys terautentikasi sebagai klien WhatsApp sekunder melalui QR code atau pairing code.
Hubungkan dengan QR Code
const { default: makeWASocket, Browsers } = require("levvleys")
const sock = makeWASocket({
browser: Browsers.ubuntu('My App'),
printQRInTerminal: true
})Setelah koneksi berhasil, QR code akan muncul di terminal. Pindai dengan WhatsApp di ponsel Anda untuk login.
Hubungkan dengan Pairing Code
Penting: Pairing code memungkinkan koneksi tanpa QR code. Nomor telepon harus tanpa +, (), atau -, dan sertakan kode negara.
const { default: makeWASocket } = require("levvleys")
const sock = makeWASocket({
printQRInTerminal: false
})
// Pairing normal
if (!sock.authState.creds.registered) {
const number = '6285134816783' // ganti dengan nomor Anda
const code = await sock.requestPairingCode(number)
console.log('🔑 Kode Pairing:', code)
}
// Pairing dengan kode kustom (8 karakter)
if (!sock.authState.creds.registered) {
const pair = "LEVVCODE"
const number = '6285134816783'
const code = await sock.requestPairingCode(number, pair)
console.log('🔑 Kode Pairing Kustom:', code)
}Terima Riwayat Lengkap
Untuk menerima riwayat pesan lengkap, setel syncFullHistory ke true.
const { default: makeWASocket, Browsers } = require("levvleys")
const sock = makeWASocket({
browser: Browsers.macOS('Desktop'),
syncFullHistory: true
})⚙️ Catatan Penting Konfigurasi Socket
Caching Metadata Grup (Direkomendasikan)
Untuk penggunaan grup, implementasikan caching metadata grup:
const { default: makeWASocket } = require("levvleys")
const NodeCache = require('node-cache')
const groupCache = new NodeCache({ stdTTL: 5 * 60, useClones: false })
const sock = makeWASocket({
cachedGroupMetadata: async (jid) => groupCache.get(jid)
})
sock.ev.on('groups.update', async ([event]) => {
const metadata = await sock.groupMetadata(event.id)
groupCache.set(event.id, metadata)
})
sock.ev.on('group-participants.update', async (event) => {
const metadata = await sock.groupMetadata(event.id)
groupCache.set(event.id, metadata)
})Perbaiki Sistem Retry & Dekripsi Vote Poll
Tingkatkan pengiriman pesan dan dekripsi vote poll dengan store:
const sock = makeWASocket({
getMessage: async (key) => await getMessageFromStore(key)
})Terima Notifikasi di Aplikasi WhatsApp
Nonaktifkan status online untuk menerima notifikasi:
const sock = makeWASocket({
markOnlineOnConnect: false
})💾 Simpan Info Auth
Hindari pemindaian QR code berulang dengan menyimpan kredensial:
const { default: makeWASocket, useMultiFileAuthState } = require("levvleys")
async function connect() {
const { state, saveCreds } = await useMultiFileAuthState('auth_info_levvleys')
const sock = makeWASocket({ auth: state })
sock.ev.on('creds.update', saveCreds)
}
connect()Penting: useMultiFileAuthState menyimpan status auth di folder. Untuk produksi, gunakan database SQL/No‑SQL dan kelola update kunci dengan hati‑hati.
🗄️ Implementasi Data Store
levvleys tidak menyertakan penyimpanan default untuk obrolan, kontak, atau pesan. Namun, implementasi in‑memory sederhana disediakan.
const { default: makeWASocket, makeInMemoryStore } = require("levvleys")
const store = makeInMemoryStore({ })
store.readFromFile('./levvleys_store.json')
setInterval(() => {
store.writeToFile('./levvleys_store.json')
}, 10_000)
const sock = makeWASocket({ })
store.bind(sock.ev)
sock.ev.on('chats.upsert', () => {
console.log('dapat obrolan', store.chats.all())
})
sock.ev.on('contacts.upsert', () => {
console.log('dapat kontak', Object.values(store.contacts))
})🆔 Penjelasan ID WhatsApp
id adalah ID WhatsApp, disebut juga jid, untuk orang atau grup tujuan pesan.
· Orang: [kode negara][nomor telepon]@s.whatsapp.net Contoh: [email protected] · Grup: [email protected] · Daftar siaran: [timestamp pembuatan]@broadcast · Cerita: status@broadcast
🔧 Fungsi Utilitas
· getContentType – Mengembalikan tipe konten pesan · getDevice – Mengembalikan perangkat dari pesan · makeCacheableSignalKeyStore – Mempercepat store auth · downloadContentFromMessage – Unduh konten dari pesan
📤 Kirim Pesan
Kirim semua jenis pesan dengan satu fungsi.
sock.sendMessage(jid, content, options)Pesan Non‑Media
Pesan Teks
await sock.sendMessage(jid, { text: 'halo dunia' })Pesan Kutipan (bekerja dengan semua tipe)
await sock.sendMessage(jid, { text: 'halo dunia' }, { quoted: message })Sebut Pengguna
await sock.sendMessage(
jid,
{
text: '@12345678901',
mentions: ['[email protected]']
}
)Teruskan Pesan
const msg = getMessageFromStore() // implementasikan sendiri
await sock.sendMessage(jid, { forward: msg })Pesan Lokasi
await sock.sendMessage(
jid,
{
location: {
degreesLatitude: 24.121231,
degreesLongitude: 55.1121221
}
}
)Pesan Kontak (vCard)
const vcard = 'BEGIN:VCARD\n'
+ 'VERSION:3.0\n'
+ 'FN:Jeff Singh\n'
+ 'ORG:Ashoka Uni;\n'
+ 'TEL;type=CELL;type=VOICE;waid=911234567890:+91 12345 67890\n'
+ 'END:VCARD'
await sock.sendMessage(
id,
{
contacts: {
displayName: 'Jeff',
contacts: [{ vcard }]
}
}
)Pesan Reaksi
await sock.sendMessage(
jid,
{
react: {
text: '💖', // kosongkan untuk hapus reaksi
key: message.key
}
}
)Pin Pesan
await sock.sendMessage(
jid,
{
pin: {
type: 1, // 0 untuk hapus
time: 86400, // 24 jam dalam detik
key: message.key
}
}
)Pesan Poll
await sock.sendMessage(
jid,
{
poll: {
name: 'Poll Saya',
values: ['Opsi 1', 'Opsi 2', 'Opsi 3'],
selectableCount: 1,
toAnnouncementGroup: false
}
}
)Kirim dengan Pratinjau Tautan
Instal link-preview-js:
npm install link-preview-jsawait sock.sendMessage(
jid,
{
text: 'Halo, ini dikirim menggunakan https://npmjs.com/levvleys'
}
)Pesan Media
Catatan: Di pesan media, bisa gunakan { stream: Stream }, { url: Url }, atau Buffer langsung.
Kirim Gambar
await sock.sendMessage(
id,
{
image: {
url: './Media/ma_img.png'
},
caption: 'halo dunia'
}
)Kirim Video
await sock.sendMessage(
id,
{
video: {
url: './Media/ma_video.mp4'
},
caption: 'halo dunia',
ptv: false // true untuk video note
}
)Kirim GIF
await sock.sendMessage(
jid,
{
video: fs.readFileSync('Media/ma_gif.mp4'),
caption: 'halo dunia',
gifPlayback: true
}
)Kirim Audio
await sock.sendMessage(
jid,
{
audio: {
url: './Media/audio.mp3'
},
mimetype: 'audio/mp4'
}
)View Once
await sock.sendMessage(
id,
{
image: {
url: './Media/ma_img.png'
},
viewOnce: true,
caption: 'halo dunia'
}
)✏️ Ubah Pesan
Hapus Pesan (untuk semua)
const msg = await sock.sendMessage(jid, { text: 'halo dunia' })
await sock.sendMessage(jid, { delete: msg.key })Edit Pesan
await sock.sendMessage(jid, {
text: 'teks terupdate di sini',
edit: response.key,
})🖼️ Manipulasi Pesan Media
Unduh Pesan Media
import { createWriteStream } from 'fs'
import { downloadMediaMessage, getContentType } from 'levvleys'
sock.ev.on('messages.upsert', async ({ messages: [m] }) => {
if (!m.message) return
const messageType = getContentType(m)
if (messageType === 'imageMessage') {
const stream = await downloadMediaMessage(
m,
'stream',
{ },
{
logger,
reuploadRequest: sock.updateMediaMessage
}
)
const writeStream = createWriteStream('./my-download.jpeg')
stream.pipe(writeStream)
}
})📞 Tolak Panggilan
await sock.rejectCall(callId, callFrom)💬 Status Kirim di Obrolan
Baca Pesan
await sock.readMessages([key]) // bisa multiple kunciUpdate Kehadiran
await sock.sendPresenceUpdate('available', jid)
await sock.sendPresenceUpdate('composing', jid)📁 Ubah Obrolan
Arsipkan Obrolan
const lastMsgInChat = await getLastMessageInChat(jid) // implementasikan sendiri
await sock.chatModify({ archive: true, lastMessages: [lastMsgInChat] }, jid)Bisukan/Buka Bisukan Obrolan
// Bisukan 8 jam
await sock.chatModify({ mute: 8 * 60 * 60 * 1000 }, jid)
// Buka bisukan
await sock.chatModify({ mute: null }, jid)Tandai Obrolan Dibaca/Tidak Dibaca
const lastMsgInChat = await getLastMessageInChat(jid)
await sock.chatModify({ markRead: false, lastMessages: [lastMsgInChat] }, jid)Hapus Pesan untuk Saya
await sock.chatModify(
{
clear: {
messages: [
{
id: 'ATWYHDNNWU81732J',
fromMe: true,
timestamp: '1654823909'
}
]
}
},
jid
)Hapus Obrolan
const lastMsgInChat = await getLastMessageInChat(jid)
await sock.chatModify({
delete: true,
lastMessages: [
{
key: lastMsgInChat.key,
messageTimestamp: lastMsgInChat.messageTimestamp
}
]
}, jid)Pin/Hapus Pin Obrolan
await sock.chatModify({ pin: true }, jid) // pin
await sock.chatModify({ pin: false }, jid) // hapus pinBintangi/Hapus Bintang Pesan
await sock.chatModify({
star: {
messages: [
{
id: 'messageID',
fromMe: true
}
],
star: true // atau false untuk hapus bintang
}
}, jid)Pesan Menghilang
// Nyalakan pesan menghilang (7 hari default)
await sock.sendMessage(
jid,
{ disappearingMessagesInChat: 604800 } // 7 hari dalam detik
)
// Kirim sebagai pesan menghilang
await sock.sendMessage(jid, { text: 'halo' }, { ephemeralExpiration: 604800 })
// Matikan
await sock.sendMessage(
jid,
{ disappearingMessagesInChat: false }
)👤 Query Pengguna
Periksa ID Ada di WhatsApp
const [result] = await sock.onWhatsApp(jid)
if (result.exists) console.log(`${jid} ada di WhatsApp, sebagai jid: ${result.jid}`)Query Riwayat Obrolan
const msg = await getOldestMessageInChat(jid) // implementasikan sendiri
await sock.fetchMessageHistory(
50, // jumlah (max: 50 per query)
msg.key,
msg.messageTimestamp
)Ambil Status
const status = await sock.fetchStatus(jid)
console.log('status: ' + status)Ambil Foto Profil (grup juga)
// resolusi rendah
const ppUrl = await sock.profilePictureUrl(jid)
console.log(ppUrl)
// resolusi tinggi
const ppUrlHigh = await sock.profilePictureUrl(jid, 'image')Ambil Profil Bisnis
const profile = await sock.getBusinessProfile(jid)
console.log('deskripsi: ' + profile.description + ', kategori: ' + profile.category)Ambil Kehadiran Seseorang
sock.ev.on('presence.update', console.log)
await sock.presenceSubscribe(jid) 🔄 Ubah Profil
Ubah Status Profil
await sock.updateProfileStatus('Halo Dunia!')Ubah Nama Profil
await sock.updateProfileName('Nama Saya')Ubah Foto Tampilan (grup juga)
await sock.updateProfilePicture(jid, { url: './new-profile-picture.jpeg' })Hapus Foto Tampilan (grup juga)
await sock.removeProfilePicture(jid)👥 Grup
Buat Grup
const group = await sock.groupCreate('Grup Saya', ['[email protected]', '[email protected]'])
console.log('grup dibuat dengan id: ' + group.gid)Tambah/Hapus atau Turunkan/Naikkan
await sock.groupParticipantsUpdate(
jid,
['[email protected]', '[email protected]'],
'add' // 'remove', 'demote', atau 'promote'
)Ubah Subjek (nama)
await sock.groupUpdateSubject(jid, 'Subjek Baru!')Ubah Deskripsi
await sock.groupUpdateDescription(jid, 'Deskripsi Baru!')Ubah Pengaturan
// Hanya admin kirim pesan
await sock.groupSettingUpdate(jid, 'announcement')
// Semua bisa kirim
await sock.groupSettingUpdate(jid, 'not_announcement')
// Semua bisa ubah pengaturan grup
await sock.groupSettingUpdate(jid, 'unlocked')
// Hanya admin ubah pengaturan
await sock.groupSettingUpdate(jid, 'locked')Keluar Grup
await sock.groupLeave(jid)Ambil Kode Undangan
const code = await sock.groupInviteCode(jid)
console.log('https://chat.whatsapp.com/' + code)Cabut Kode Undangan
const code = await sock.groupRevokeInvite(jid)
console.log('Kode grup baru: ' + code)Gabung Menggunakan Kode Undangan
const response = await sock.groupAcceptInvite(code)
console.log('bergabung ke: ' + response)Ambil Info Grup dari Kode Undangan
const response = await sock.groupGetInviteInfo(code)
console.log('info grup: ' + response)Query Metadata
const metadata = await sock.groupMetadata(jid)
console.log(metadata.id + ', judul: ' + metadata.subject + ', deskripsi: ' + metadata.desc)Ambil Semua Metadata Grup yang Diikuti
const response = await sock.groupFetchAllParticipating()
console.log(response)Toggle Ephemeral
await sock.groupToggleEphemeral(jid, 86400) // 24 jamUbah Mode Tambah
await sock.groupMemberAddMode(
jid,
'all_member_add' // atau 'admin_add'
)🔒 Privasi
Blokir/Buka Blokir Pengguna
await sock.updateBlockStatus(jid, 'block')
await sock.updateBlockStatus(jid, 'unblock')Ambil Pengaturan Privasi
const privacySettings = await sock.fetchPrivacySettings(true)
console.log(privacySettings)Ambil Daftar Blokir
const blocklist = await sock.fetchBlocklist()
console.log(blocklist)Update Privasi
await sock.updateLastSeenPrivacy('contacts')
await sock.updateOnlinePrivacy('all')
await sock.updateProfilePicturePrivacy('contacts')
await sock.updateStatusPrivacy('none')
await sock.updateReadReceiptsPrivacy('all')
await sock.updateGroupsAddPrivacy('contacts')
await sock.updateDefaultDisappearingMode(86400) // 24 jam📢 Daftar Siaran & Cerita
Kirim Siaran & Cerita
await sock.sendMessage(
jid,
{
image: {
url: url
},
caption: caption
},
{
backgroundColor: backgroundColor,
font: font,
statusJidList: statusJidList,
broadcast: true
}
)Query Penerima & Nama Daftar Siaran
const bList = await sock.getBroadcastListInfo('1234@broadcast')
console.log(`nama daftar: ${bList.name}, penerima: ${bList.recipients}`)🛠️ Fungsi Kustom
Aktifkan Level Debug
const { P } = require('levvleys')
const sock = makeWASocket({
logger: P({ level: 'debug' }),
})Daftarkan Callback untuk Event Websocket
// Untuk tag 'edge_routing'
sock.ws.on('CB:edge_routing', (node) => { })
// Dengan id 'abcd'
sock.ws.on('CB:edge_routing,id:abcd', (node) => { })
// Dengan node routing_info
sock.ws.on('CB:edge_routing,id:abcd,routing_info', (node) => { })💡 Tips & Praktik Terbaik
· Gunakan Caching – Cache metadata grup untuk performa lebih baik. · Tangani Rekoneksi – Implementasikan auto‑reconnect untuk kestabilan. · Kelola Store – Gunakan database (MongoDB, PostgreSQL) untuk produksi. · Penanganan Error – Bungkus panggilan socket dengan try‑catch. · Batas Rate – Hormati batas WhatsApp untuk hindari ban. · Keamanan – Jangan bagikan kredensial auth; gunakan variabel lingkungan.
📄 Lisensi
Didistribusikan di bawah Lisensi GPL‑3.0. Lihat file LICENSE untuk informasi lebih lanjut.
