@tamago19/tamaaago
v2.2.9
Published
WhatsApp API Modification By Tamaaago
Maintainers
Readme
Tama-Baileys
Tentang Tama-Baileys
Tama-Baileys (@tamago19/tamaaago) adalah library open source berbasis WebSocket yang dirancang untuk membuat bot dan sistem otomasi WhatsApp. Berbeda dengan library lain yang memerlukan browser, Tama-Baileys terhubung langsung ke WhatsApp melalui protokol WebSocket sehingga lebih ringan dan efisien.
Library ini merupakan modifikasi dari WhiskeySockets/Baileys dengan penambahan fitur interaktif dan perbaikan khusus untuk kebutuhan bot Indonesia.
Install
via npm (direkomendasikan)
npm install @tamago19/tamaaagoAtau tambahkan ke package.json:
{
"dependencies": {
"@tamago19/tamaaago": "^2.2.5"
}
}Prerequisites / Peer Dependencies
Beberapa dependency bersifat opsional. Install sesuai kebutuhan:
# Core (wajib):
npm install pino ws
# Untuk fitur media / gambar:
npm install jimp sharp
# Untuk audio:
npm install audio-decode
# Untuk link preview:
npm install link-preview-jsInfo Rilis
| Versi | Tanggal | Perubahan |
|-------|---------|----------|
| 2.2.1 | terbaru | Penambahan fungsi sendButtons untuk pesan interaktif |
| 2.2.0 | sebelumnya | Upgrade ke Baileys 7.0.0-rc14, migrasi ESM |
| 2.1.x | sebelumnya | Perbaikan pairing dan koneksi |
Fitur Utama
| Fitur | Keterangan |
|-------|-----------|
| Pesan Interaktif | Tombol, menu dropdown, native flow, CTA (URL, copy, call) |
| Album Message | Kirim beberapa gambar sekaligus |
| Pesan Event | Undangan acara dengan lokasi dan link join |
| Poll Result | Tampilkan hasil voting |
| Produk/Katalog | Kirim katalog produk WhatsApp Business |
| Request Payment | Invoice dan tagihan pembayaran |
| Dokumen Interaktif | PDF/Excel dengan tombol aksi |
| Multi-Device | Mendukung MD dan Legacy |
| Pairing Kustom | Login via kode pairing (tanpa QR) |
| Manajemen Sesi | Sesi tersimpan otomatis (useMultiFileAuthState) |
Dokumentasi Lengkap
Struktur Dasar Project
// bot.js
import { makeWASocket, useMultiFileAuthState, DisconnectReason } from '@tamago19/tamaaago';
import pino from 'pino';
async function start() {
// Simpan sesi ke folder 'session/'
const { state, saveCreds } = await useMultiFileAuthState('session');
const sock = makeWASocket({
auth: state,
printQRInTerminal: true,
logger: pino({ level: 'silent' }),
syncFullHistory: false,
});
sock.ev.on('connection.update', ({ connection, lastDisconnect }) => {
if (connection === 'open') {
console.log('Berhasil terhubung ke WhatsApp!');
}
if (connection === 'close') {
const shouldReconnect = lastDisconnect?.error?.output?.statusCode !== DisconnectReason.loggedOut;
if (shouldReconnect) start();
}
});
// Simpan kredensial setiap berubah
sock.ev.on('creds.update', saveCreds);
// Tangkap pesan masuk
sock.ev.on('messages.upsert', async ({ messages }) => {
for (const msg of messages) {
if (!msg.message) continue;
const from = msg.key.remoteJid;
const text = msg.message.conversation
|| msg.message.extendedTextMessage?.text
|| '';
console.log(`Dari: ${from} | Pesan: ${text}`);
// Balas pesan
if (text === 'ping') {
await sock.sendMessage(from, { text: 'pong!' });
}
}
});
}
start();Struktur Pesan (Message Object)
Setiap pesan yang masuk memiliki struktur seperti ini:
{
key: {
remoteJid: '[email protected]', // Chat ID pengirim
fromMe: false, // Apakah dari nomor sendiri
id: 'ABC123XYZ', // Unique message ID
participant: '[email protected]', // Pengirim (untuk grup)
},
messageTimestamp: 1712345678, // Timestamp Unix
pushName: 'Nama Pengguna', // Nama yang tersimpan di WA
message: {
conversation: 'halo' // Isi pesan
},
// Atau tipe lain:
// message: { imageMessage: { ... } }
// message: { extendedTextMessage: { text: '...' } }
// message: { videoMessage: { ... } }
// message: { documentMessage: { ... } }
// message: { audioMessage: { ... } }
// message: { stickerMessage: { ... } }
}Cara Mendapatkan Isi Pesan
// Teks biasa
const text = msg.message.conversation
|| msg.message.extendedTextMessage?.text
|| '';
// Gambar / Media
const image = msg.message.imageMessage;
const caption = image?.caption;
const mediaBuffer = await sock.downloadMediaMessage(msg);
// Video
const video = msg.message.videoMessage;
// Document
const doc = msg.message.documentMessage;
const fileName = doc?.fileName;
const mimeType = doc?.mimetype;
// Audio
const audio = msg.message.audioMessage;
// Sticker
const sticker = msg.message.stickerMessage;
// Quoted Message (pesan yang di-reply)
const quoted = msg.message.extendedTextMessage?.contextInfo?.quotedMessage;Referensi Pengiriman Pesan
1. Pesan Teks Biasa
await sock.sendMessage(jid, { text: 'Halo dunia!' });2. Pesan dengan Reply / Quoted
await sock.sendMessage(jid, { text: 'Ini adalah reply' }, { quoted: msg });3. Pesan Album (Kirim Banyak Gambar)
Kirim beberapa gambar sekaligus dalam satu pesan album:
import fs from 'fs';
await sock.sendMessage(jid, {
albumMessage: [
{
image: fs.readFileSync('./gambar1.jpg'),
caption: 'Foto pertama'
},
{
image: { url: 'https://example.com/foto.jpg' },
caption: 'Foto dari URL'
}
]
}, { quoted: msg });Parameter:
image: bisaBuffer,URL string, ataupath stringcaption: teks di bawah gambar
4. Pesan Event / Undangan Acara
Kirim undangan event dengan detail lengkap:
await sock.sendMessage(jid, {
eventMessage: {
name: "Webinar Gratis - Belajar Coding",
description: "Workshop gratis untuk pemula. Belajar JavaScript dari nol!",
location: {
degreesLatitude: -7.9666,
degreesLongitude: 112.6326,
name: "Online via Zoom"
},
joinLink: "https://zoom.us/j/123456789",
startTime: "1763019000",
endTime: "1763026200",
isCanceled: false,
extraGuestsAllowed: true
}
}, { quoted: msg });Parameter:
name: judul eventdescription: deskripsi eventlocation: lokasi event (koordinat + nama tempat)joinLink: link untuk join (Zoom, Google Meet, dll)startTime/endTime: waktu dalam format Unix timestampisCanceled: apakah event dibatalkanextraGuestsAllowed: apakah boleh menambahkan tamu tambahan
5. Pesan Interaktif dengan Tombol (sendButtons)
Ini adalah cara termudah untuk mengirim pesan dengan tombol interaktif. Tombol akan muncul di bawah pesan dan bisa diklik langsung oleh pengguna.
Tombol Quick Reply (paling umum)
import { sendButtons } from '@tamago19/tamaaago';
await sendButtons(sock, jid, {
text: 'Silakan pilih menu di bawah:',
footer: 'Bot by Tamaaago',
buttons: [
{ id: 'menu_info', text: 'Informasi' },
{ id: 'menu_help', text: 'Bantuan' },
{ id: 'menu_contact', text: 'Hubungi Kami' }
]
});Ketika pengguna mengklik tombol, bot akan menerima pesan dengan msg.message.buttonsResponseMessage?.selectedButtonId berisi ID tombol.
Tombol dengan URL (CTA URL)
await sendButtons(sock, jid, {
text: 'Selamat datang di toko kami!',
footer: 'Klik tombol untuk aksi',
buttons: [
{ id: 'opt1', text: 'Lihat Produk' },
{ name: 'cta_url', buttonParamsJson: JSON.stringify({
display_text: 'Kunjungi Website',
url: 'https://tokokami.com'
}) }
]
});Tombol dengan Copy Code
await sendButtons(sock, jid, {
text: 'Berikut kode promo eksklusif Anda:',
footer: 'Tekan tombol untuk menyalin kode',
buttons: [
{ name: 'cta_copy', buttonParamsJson: JSON.stringify({
display_text: 'Salin Kode',
id: 'promo_123',
copy_code: 'HEMAT50'
}) }
]
});Tombol dengan CTA Call (Telepon)
await sendButtons(sock, jid, {
text: 'Ada pertanyaan? Hubungi CS kami langsung.',
footer: 'Layanan 24 jam',
buttons: [
{ name: 'cta_call', buttonParamsJson: JSON.stringify({
display_text: 'Telepon Sekarang',
phone_number: '628123456789'
}) }
]
});Menangani Respon Tombol
sock.ev.on('messages.upsert', async ({ messages }) => {
for (const msg of messages) {
// Cek apakah ini response dari tombol
const buttonResponse = msg.message?.buttonsResponseMessage;
if (buttonResponse) {
const selectedId = buttonResponse.selectedButtonId;
const selectedDisplay = buttonResponse.displayText;
console.log(`Tombol diklik: ${selectedId}`);
if (selectedId === 'menu_info') {
await sock.sendMessage(msg.key.remoteJid, {
text: 'Berikut informasi lengkap...'
});
} else if (selectedId === 'menu_help') {
await sock.sendMessage(msg.key.remoteJid, {
text: 'Ketik !help untuk bantuan.'
});
}
continue;
}
}
});6. Pesan Interaktif dengan Menu Dropdown (Single Select)
Menu dropdown memungkinkan pengguna memilih dari daftar opsi:
await sock.sendMessage(jid, {
interactiveMessage: {
header: {
title: "Menu Utama",
hasMediaAttachment: false
},
body: {
text: "Pilih layanan yang Anda butuhkan:"
},
footer: {
text: "© Tama-Baileys Bot"
},
nativeFlowMessage: {
messageParamsJson: JSON.stringify({
single_select: {
title: "Daftar Menu",
list_title: "Pilih Opsi",
button_title: "Tampilkan Menu"
}
}),
buttons: [
{
name: "single_select",
buttonParamsJson: JSON.stringify({
title: "Menu Utama",
sections: [
{
title: "Layanan",
highlight_label: "Populer",
rows: [
{
header: "Customer Service",
title: "Hubungi Tim Kami",
description: "Chat langsung dengan CS kami",
id: "cs_chat"
},
{
header: "Produk",
title: "Lihat Katalog",
description: "Lihat semua produk kami",
id: "product_catalog"
},
{
header: "Promo",
title: "Kode Promo",
description: "Dapatkan diskon eksklusif",
id: "promo_codes"
}
]
},
{
title: "Lainnya",
rows: [
{
title: "Tentang Kami",
description: "Kenali lebih dekat",
id: "about_us"
},
{
title: "Cara Pemesanan",
description: "Panduan lengkap",
id: "how_to_order"
}
]
}
]
})
}
]
}
}
}, { quoted: msg });Parameter single_select:
sections: array bagian menutitle: nama bagianhighlight_label: label khusus (misal "Populer")rows: item dalam bagianheader/title: teks opsidescription: teks penjelasanid: ID yang dikirim saat dipilih
7. Pesan Produk / Katalog WhatsApp Business
Kirim pesan katalog produk:
await sock.sendMessage(jid, {
productMessage: {
product: {
productImage: { url: 'https://example.com/phone.jpg' },
productId: 'PHONE001',
title: "Smartphone XYZ Pro",
description: "RAM 8GB, Storage 256GB, Kamera 108MP",
retailerId: 'STORE001',
url: 'https://tokokami.com/phone-xyz-pro',
currencyCode: "IDR",
price_amount_1000: 4500000,
productSections: [
{
title: "Spesifikasi",
rows: [
{ title: "Layar", description: "6.7 inch AMOLED" },
{ title: "Baterai", description: "5000mAh" },
{ title: "Prosesor", description: "Snapdragon 888" }
]
}
]
},
businessOwnerJid: '[email protected]',
footer: 'Gratis ongkir seluruh Indonesia!'
}
});8. Pesan Polling / Voting
Kirim Poll (Buat Voting)
await sock.sendMessage(jid, {
pollCreationMessage: {
name: "Pilih Menu Makan Siang",
options: [
{ optionName: "Nasi Goreng" },
{ optionName: "Mie Ayam" },
{ optionName: "Soto Ayam" },
{ optionName: "Rawon" }
],
selectableOptionsCount: 1
}
});Tampilkan Hasil Poll
await sock.sendMessage(jid, {
pollResultMessage: {
name: "Pilih Menu Makan Siang",
pollVotes: [
{ optionName: "Nasi Goreng", optionVoteCount: "12" },
{ optionName: "Mie Ayam", optionVoteCount: "8" },
{ optionName: "Soto Ayam", optionVoteCount: "5" },
{ optionName: "Rawon", optionVoteCount: "3" }
]
}
}, { quoted: msg });9. Pesan dengan File Dokumen
Kirim dokumen (PDF, Excel, Word, dll) dengan tombol aksi:
import fs from 'fs';
await sock.sendMessage(jid, {
documentMessage: {
url: 'https://example.com/laporan.pdf',
mimetype: 'application/pdf',
title: 'Laporan Bulanan',
fileLength: '850000',
pageCount: 12
},
caption: 'Berikut laporan bulanan Anda. Silakan diunduh.',
footer: 'Finance Department',
buttons: [
{ id: 'download_report', text: 'Download' },
{ name: 'cta_url', buttonParamsJson: JSON.stringify({
display_text: 'Simpan ke Cloud',
url: 'https://drive.example.com/laporan'
}) }
],
headerType: 1
}, { quoted: msg });Catatan: File dokumen hanya bisa dikirim dari Buffer (baca dari sistem file):
const pdfBuffer = fs.readFileSync('./laporan.pdf');
const thumbnail = fs.readFileSync('./thumbnail.jpg');
await sock.sendMessage(jid, {
interactiveMessage: {
header: { title: 'Laporan Bulanan' },
body: { text: 'Klik tombol di bawah untuk mengunduh.' },
footer: { text: 'Finance Dept' },
nativeFlowMessage: {
buttons: [
{
name: 'cta_url',
buttonParamsJson: JSON.stringify({
display_text: 'Download PDF',
url: 'https://example.com/laporan.pdf'
})
}
]
}
}
}, { quoted: msg });10. Request Pembayaran (Invoice)
Kirim invoice atau tagihan:
await sock.sendMessage(jid, {
requestPaymentMessage: {
currency: "IDR",
amount: 1500000,
requestFrom: '[email protected]',
noteMessage: {
currency: "IDR",
amount1000: 1500000,
displayText: "Pembayaran Order #12345"
},
expiryTimestamp: Math.floor(Date.now() / 1000) + 86400 * 7 // 7 hari
}
}, { quoted: msg });Fitur Tambahan
Broadcast ke Banyak Nomor
const targets = [
'[email protected]',
'[email protected]',
'[email protected]'
];
for (const target of targets) {
try {
await sock.sendMessage(target, {
text: '📢 Pesan broadcast dari Bot!'
});
console.log(`Sent to ${target}`);
} catch (e) {
console.error(`Failed to send to ${target}:`, e);
}
}Kirim dengan Delay (Anti-Spam)
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
const targets = ['[email protected]', '[email protected]'];
for (const target of targets) {
await sock.sendMessage(target, { text: 'Pesan Anda' });
await delay(3000); // Jeda 3 detik antar pesan
}Download Media dari Pesan
async function downloadMedia(msg) {
const buffer = await sock.downloadMediaMessage(msg);
return buffer;
}
// Atau simpan ke file
import fs from 'fs';
const media = await sock.downloadMediaMessage(msg);
fs.writeFileSync('./downloaded_image.jpg', media);Handle Button Response (Generic)
sock.ev.on('messages.upsert', async ({ messages }) => {
for (const msg of messages) {
// 1. Tombol biasa (buttonsResponseMessage)
if (msg.message?.buttonsResponseMessage) {
const { selectedButtonId, displayText } = msg.message.buttonsResponseMessage;
await sock.sendMessage(msg.key.remoteJid, {
text: `Anda memilih: ${displayText} (ID: ${selectedButtonId})`
});
}
// 2. List Response (single_select)
if (msg.message?.listResponseMessage) {
const { title, description, listItemId } = msg.message.listResponseMessage;
await sock.sendMessage(msg.key.remoteJid, {
text: `Anda memilih: ${title}\nID: ${listItemId}`
});
}
// 3. Template Button Reply
if (msg.message?.templateButtonReplyMessage) {
const { selectedId } = msg.message.templateButtonReplyMessage;
await sock.sendMessage(msg.key.remoteJid, {
text: `Button ID: ${selectedId}`
});
}
}
});Referensi API Singkat
Import Utama
import {
makeWASocket, // Membuat socket/koneksi
useMultiFileAuthState, // Simpan sesi ke file
DisconnectReason, // Kode disconnect
sendButtons, // Kirim pesan tombol interaktif
sendInteractiveMessage, // Kirim pesan interaktif level lanjut
// Tipe data:
proto, // WAProto (semua tipe pesan WA)
downloadMediaMessage, // Download media dari pesan
generateMessageID, // Generate message ID
delay, // Utility delay
} from '@tamago19/tamaaago';sock.sendMessage(jid, content, options)
| Parameter | Tipe | Keterangan |
|-----------|------|-----------|
| jid | string | Chat ID (contoh: [email protected]) |
| content | object | Isi pesan |
| options | object | Opsi tambahan |
Opsi Umum
{
quoted: msg, // Reply ke pesan tertentu
mentions: ['jid1', 'jid2'], // Mention user
ephemeralExpiration: 604800, // Pesan hilang (detik)
}Struktur Project Sederhana
my-whatsapp-bot/
├── package.json
├── bot.js # Main bot file
├── session/ # Otomatis dibuat, simpan sesi
│ ├── creds.json
│ └── keys/
├── media/ # Folder untuk media
│ └── thumbnails/
└── node_modules/
└── @tamago19/tamaaagoCatatan Penting
Format JID (Chat ID)
- Pribadi:
[email protected] - Grup:
[email protected] - Broadcast:
status@broadcast - Newsletter:
[email protected]
Pairing Code Login (Tanpa QR)
// Kirim kode pairing ke nomor sendiri
const code = await sock.requestPairingCode('628123456789');
console.log('Kode pairing:', code);Debugging / Logging
const sock = makeWASocket({
auth: state,
logger: pino({ level: 'debug' }), // Tampilkan semua log
printQRInTerminal: true,
});Kenapa Tama-Baileys?
| | Tama-Baileys | Baileys Original |
|--|--|--|
| Tombol Interaktif | ✅ Built-in sendButtons | ⚠️ Butuh helper tambahan |
| ESM Native | ✅ Full ESM support | ⚠️ Butuh konfigurasi |
| Dokumentasi | ✅ Bahasa Indonesia + English | ⚠️ English only |
| Update Interaktif | ✅ Langsung integrate | ⚠️ Manual |
Dukungan
- 📖 Dokumentasi ini
- 🐛 Laporkan bug via GitHub Issues
- 💬 Diskusi di repository
Terima kasih telah menggunakan Tama-Baileys! 🚀
