WAG adalah aplikasi gateway WhatsApp yang memungkinkan kamu untuk menghubungkan beberapa akun WhatsApp sekaligus dan mengelolanya melalui REST API. Aplikasi ini dibangun menggunakan Bun runtime dengan framework Elysia.js untuk performa yang optimal.
- Multi-sesi WhatsApp - Hubungkan beberapa akun WhatsApp dalam satu aplikasi
- Autentikasi fleksibel - Mendukung QR Code dan Pairing Code
- Webhook notifikasi - Terima notifikasi real-time untuk setiap event
- REST API lengkap - Kelola koneksi dan kirim pesan melalui API
- Penyimpanan lokal - Data sesi tersimpan dengan SQLite
Download file executable sesuai sistem operasi kamu dari halaman releases:
| Sistem Operasi | File |
|---|---|
| Windows x64 | wag-windows-{version}.exe |
| Linux x64 | wag-linux-{version} |
| macOS ARM64 | wag-macos-{version} |
- Download
wag-windows-{version}.exe - Jalankan file executable
wag-windows-{version}.exe- Download
wag-linux-{version} - Beri permission executable
chmod +x wag-linux-{version}- Jalankan aplikasi
./wag-linux-{version}- Download
wag-macos-{version} - Beri permission executable
chmod +x wag-macos-{version}- Jalankan aplikasi
./wag-macos-{version}Aplikasi akan berjalan di http://localhost:3000 (atau port yang dikonfigurasi).
Konfigurasi dilakukan melalui environment variable:
| Variable | Deskripsi | Default |
|---|---|---|
PORT |
Port server | 3000 |
DB_PATH |
Direktori penyimpanan data | session_data |
MAX_SESSIONS |
Maksimal jumlah sesi yang diizinkan | 100 |
WAG dirancang untuk mengelola banyak akun WhatsApp secara bersamaan dengan arsitektur yang terisolasi dan efisien.
Setiap sesi WhatsApp memiliki database SQLite terpisah untuk menjamin isolasi data yang sempurna:
session_data/
├── main.sqlite # Database utama (daftar koneksi)
├── device-001/
│ └── db.sqlite # Database sesi device-001
├── device-002/
│ └── db.sqlite # Database sesi device-002
└── device-003/
└── db.sqlite # Database sesi device-003
Komponen Database:
| File | Fungsi |
|---|---|
main.sqlite |
Menyimpan metadata semua koneksi (ID, nama, webhook URL, status, dll) |
{deviceId}/db.sqlite |
Menyimpan kredensial autentikasi, kunci enkripsi, cache pesan, dan metadata grup untuk sesi tertentu |
- Isolasi Penuh - Data setiap akun WhatsApp tersimpan terpisah, menghindari konflik atau kebocoran data antar sesi
- Performa Optimal - Operasi database tidak saling mempengaruhi, mengurangi lock contention
- Manajemen Mudah - Menghapus sesi cukup dengan menghapus folder-nya, tanpa mempengaruhi sesi lain
- Skalabilitas - Mendukung hingga 100 sesi aktif secara bersamaan (dapat dikonfigurasi via
MAX_SESSIONS) - Recovery Mandiri - Jika satu database corrupt, sesi lain tetap berjalan normal
SessionManager adalah komponen singleton yang mengelola seluruh lifecycle sesi:
- Startup: Memuat semua sesi dari
main.sqlitedan melakukan auto-reconnect - Runtime: Menyimpan instance sesi aktif dalam memory Map untuk akses cepat
- Persistence: Menyimpan perubahan status ke database secara real-time
WAG menyediakan dokumentasi API interaktif yang dapat diakses langsung melalui browser:
GET /docs
Halaman ini menggunakan Scalar UI (OpenAPI) yang menampilkan:
- Daftar semua endpoint - Semua API endpoint yang tersedia beserta method HTTP-nya
- Request/Response schema - Struktur data yang diharapkan untuk setiap request dan response
- Try it out - Kemampuan untuk mencoba API langsung dari browser
- Model definitions - Definisi tipe data yang digunakan
Cukup buka http://localhost:3000/docs di browser setelah aplikasi berjalan.
Semua endpoint menggunakan format JSON untuk request dan response.
Endpoint untuk mengelola koneksi WhatsApp.
Mendapatkan daftar semua sesi WhatsApp yang tersimpan.
GET /connections
Response:
{
"success": true,
"data": [
{
"id": "device-001",
"phoneNumber": "6281234567890",
"webhookUrl": "https://example.com/webhook",
"createdAt": "2024-01-15T10:00:00.000Z"
}
],
"count": 1
}Mendapatkan detail koneksi berdasarkan ID.
GET /connections/:id
Parameter:
id(path) - ID device/sesi
Response:
{
"success": true,
"data": {
"id": "device-001",
"phoneNumber": "6281234567890",
"webhookUrl": "https://example.com/webhook",
"isActive": true,
"currentStatus": {
"connectionState": "open",
"isLoggedIn": true
}
}
}Membuat dan memulai koneksi WhatsApp baru.
POST /connections/start
Request Body:
| Field | Tipe | Wajib | Deskripsi |
|---|---|---|---|
deviceId |
string | Ya | ID unik untuk device/sesi |
phoneNumber |
string | Tidak | Nomor telepon untuk pairing code (format: 6281234567890) |
webhookUrl |
string | Tidak | URL webhook untuk menerima notifikasi |
name |
string | Tidak | Nama untuk identifikasi koneksi |
Contoh Request:
curl -X POST http://localhost:3000/connections/start \
-H "Content-Type: application/json" \
-d '{
"deviceId": "device-001",
"phoneNumber": "6281234567890",
"webhookUrl": "https://example.com/webhook"
}'Response:
{
"success": true,
"message": "Connection started successfully",
"data": {
"connectionState": "connecting",
"isLoggedIn": false
}
}Catatan:
- Jika
phoneNumberdisertakan, sistem akan otomatis generate pairing code selain QR code - Jika
webhookUrldisertakan, sistem akan memvalidasi URL dengan mengirim eventpingterlebih dahulu - Webhook harus mengembalikan HTTP status 200 agar validasi berhasil
Mengambil QR code atau pairing code untuk autentikasi.
GET /connections/qr-code?deviceId=device-001
Query Parameter:
deviceId(required) - ID device/sesi
Response:
{
"success": true,
"data": {
"qrCode": "2@abc123...",
"pairingCode": "ABCD-EFGH",
"hasQrCode": true,
"hasPairingCode": true
}
}Catatan:
qrCodeberisi string yang bisa di-render menjadi QR code imagepairingCodehanya tersedia jikaphoneNumberdisertakan saat memulai koneksi
Menghentikan koneksi WhatsApp tanpa menghapus data sesi.
POST /connections/stop
Request Body:
{
"deviceId": "device-001"
}Response:
{
"success": true,
"message": "Connection stopped successfully"
}Logout dari WhatsApp dan menghapus semua data sesi.
POST /connections/logout
Request Body:
{
"deviceId": "device-001"
}Response:
{
"success": true,
"message": "Session logged out and deleted"
}Catatan: Setelah logout, kamu perlu scan QR code atau pairing code lagi untuk menghubungkan ulang.
Mengatur status online/offline di WhatsApp.
POST /connections/set-online
Request Body:
{
"deviceId": "device-001",
"online": true
}Response:
{
"success": true,
"message": "Presence set to online"
}Endpoint untuk mengirim pesan.
Mengirim pesan teks ke kontak atau grup WhatsApp.
POST /messages/send-text-message
Request Body:
| Field | Tipe | Wajib | Deskripsi |
|---|---|---|---|
deviceId |
string | Ya | ID device yang digunakan untuk mengirim |
recipient |
string | Ya | JID penerima (lihat format di bawah) |
message |
string | Ya | Isi pesan (maksimal 4096 karakter) |
id |
string | Tidak | ID pesan kustom (otomatis di-generate jika tidak disertakan) |
Format JID Penerima:
| Tipe | Format | Contoh |
|---|---|---|
| Kontak personal | {nomor}@s.whatsapp.net |
6281234567890@s.whatsapp.net |
| Grup | {groupId}@g.us |
120363123456789@g.us |
| LID (Linked ID) | {lid}@lid |
123456789@lid |
Contoh Request:
curl -X POST http://localhost:3000/messages/send-text-message \
-H "Content-Type: application/json" \
-d '{
"deviceId": "device-001",
"recipient": "6281234567890@s.whatsapp.net",
"message": "Halo dari WAG!"
}'Response:
{
"success": true
}Catatan:
- Pesan dikirim secara asinkron untuk menghindari rate limiting
- Sistem menambahkan delay otomatis antar pesan untuk mencegah pemblokiran
- Status pengiriman pesan dikirim melalui webhook (
message_sentataumessage_error)
Webhook memungkinkan aplikasi kamu menerima notifikasi real-time tentang berbagai event yang terjadi di WhatsApp.
Saat memulai koneksi dengan POST /connections/start, sertakan parameter webhookUrl:
{
"deviceId": "device-001",
"webhookUrl": "https://example.com/webhook"
}Sistem akan memvalidasi webhook dengan mengirim request ping. Pastikan endpoint webhook kamu mengembalikan HTTP status 200.
Setiap notifikasi webhook dikirim dengan format:
POST {webhookUrl}
Content-Type: application/json
User-Agent: WAG-WhatsAppSession/{sessionId}
X-Session-ID: {sessionId}
X-Event: {eventName}
X-Timestamp: {isoTimestamp}
{
"event": "{eventName}",
"data": { ... }
}
Dikirim saat validasi webhook URL.
{
"event": "ping",
"data": {
"deviceId": "device-001"
}
}Response yang diharapkan: HTTP 200
Dikirim saat QR code atau pairing code tersedia untuk autentikasi.
QR Code:
{
"event": "auth",
"data": {
"auth": {
"via": "qr_code",
"data": "2@abc123..."
}
}
}Pairing Code:
{
"event": "auth",
"data": {
"auth": {
"via": "pair_code",
"data": "ABCD-EFGH"
}
}
}Dikirim saat proses koneksi ke WhatsApp dimulai.
{
"event": "connecting",
"data": {}
}Dikirim saat koneksi berhasil terhubung dan siap digunakan.
{
"event": "ready",
"data": {}
}Dikirim saat status koneksi berubah. Field data berisi string status koneksi.
{
"event": "state",
"data": "open"
}Kemungkinan nilai:
connecting- Sedang menghubungkanopen- Terhubung dan siapclose- Koneksi tertutup
Dikirim saat koneksi tertutup. Berisi informasi alasan dan apakah akan reconnect otomatis.
{
"event": "close",
"data": {
"reason": "Connection closed, reconnecting....",
"isRestart": true
}
}Kemungkinan alasan:
| Reason | isRestart | Deskripsi |
|---|---|---|
| WhatsApp Service is Unavailable | true |
Layanan WhatsApp tidak tersedia, akan reconnect |
| Connection Forbidden | false |
Kredensial tidak valid, perlu login ulang |
| Bad Session File | false |
File sesi rusak, perlu scan ulang |
| Connection closed | true |
Koneksi tertutup, akan reconnect |
| Connection Lost from Server | true |
Koneksi terputus dari server, akan reconnect |
| Connection Replaced | false |
Sesi digantikan sesi baru, perlu login ulang |
| Device Logged Out | false |
Perangkat logout, perlu scan ulang |
| Restart Required | true |
Perlu restart, akan reconnect |
| Multi-device Mismatch | false |
Konflik multi-device, perlu scan ulang |
| Session disconnected by user | false |
Diputus oleh user |
| Process timeout reached | false |
Timeout karena tidak ada aktivitas |
Dikirim saat pesan berhasil terkirim.
{
"event": "message_sent",
"data": {
"id": "msg-uuid-001",
"deviceId": "device-001",
"message": "Halo dari WAG!",
"recipient": "6281234567890@s.whatsapp.net"
}
}Dikirim saat terjadi error saat mengirim pesan.
{
"event": "message_error",
"data": {
"id": "msg-uuid-001",
"deviceId": "device-001",
"message": "Halo dari WAG!",
"recipient": "6281234567890@s.whatsapp.net",
"error": "Socket not connected"
}
}Berikut contoh sederhana webhook server menggunakan Express.js:
const express = require('express');
const app = express();
app.use(express.json());
app.post('/webhook', (req, res) => {
const { event, data } = req.body;
const sessionId = req.headers['x-session-id'];
console.log(`[${sessionId}] Event: ${event}`);
console.log('Data:', JSON.stringify(data, null, 2));
switch (event) {
case 'ping':
console.log('Webhook validation received');
break;
case 'auth':
if (data.auth.via === 'qr_code') {
console.log('QR Code tersedia, silakan scan');
} else if (data.auth.via === 'pair_code') {
console.log('Pairing code:', data.auth.data);
}
break;
case 'connecting':
console.log('Menghubungkan ke WhatsApp...');
break;
case 'ready':
console.log('WhatsApp siap digunakan!');
break;
case 'state':
console.log(`Status koneksi: ${data}`);
break;
case 'message_sent':
console.log(`Pesan terkirim ke ${data.recipient}`);
break;
case 'message_error':
console.log(`Gagal kirim pesan: ${data.error}`);
break;
case 'close':
console.log(`Koneksi tertutup: ${data.reason}`);
if (data.isRestart) {
console.log('Akan reconnect otomatis...');
}
break;
}
res.status(200).json({ received: true });
});
app.listen(3001, () => {
console.log('Webhook server berjalan di port 3001');
});src/
├── config.ts # Konfigurasi aplikasi
├── db.ts # Koneksi database
├── index.ts # Entry point aplikasi
├── logger.ts # Konfigurasi logging
├── shutdown.ts # Graceful shutdown handler
├── server/
│ ├── index.ts # Setup server Elysia
│ ├── connections/ # Endpoint manajemen koneksi
│ └── messages/ # Endpoint pengiriman pesan
└── whatsapp/
├── session-manager.ts # Manajemen sesi WhatsApp
├── whatsapp-session.ts # Class sesi WhatsApp
├── sqlite-auth-state.ts # Penyimpanan state autentikasi
└── ...
Proyek ini dilisensikan di bawah MIT License.

