📚 Spesifikasi API Terpadu

Dokumentasi ini menyediakan spesifikasi lengkap, skema parameter, dan contoh *code snippet* untuk semua endpoint WA Gateway. Dibuat interaktif untuk memudahkan proses integrasi client/sistem Anda.

Sistem Anti-Banned & Queue Terpusat Aktif
Gateway ini memproses pengiriman layaknya manusia. API tidak mengirimkan pesan seketika, melainkan memasukkannya ke dalam Antrian (Queue) tersentralisasi. Sistem akan mengkalkulasi jeda waktu antar pesan (3-8 detik), waktu "mengetik", dan memberikan istirahat (break) otomatis. Bahkan jika server mati/restart, antrian akan tersimpan dan dilanjutkan kembali secara otomatis (Queue Persistence).

🔐 Autentikasi (Headers)

Setiap *request* ke sebagian besar endpoint WAJIB menyertakan Header autentikasi berikut:

Header Key Nilai (Value) Deskripsi
x-api-key rahasia_negara_123 Kunci API rahasia Anda. (Sesuaikan dengan file .env)
Content-Type application/json Tipe payload yang Anda kirimkan.

1. Mengirim Pesan (Send Message)

POST /api/send Base URL: http://localhost:3000

Endpoint utama untuk mengirimkan pesan ke satu nomor (Single) atau banyak nomor (Batch). Pesan otomatis masuk antrian dan dikelola oleh server agar tidak terkena Banned.

Parameter JSON Body API /api/send

Parameter Tipe Wajib? Penjelasan Lengkap
phone string | array Ya Nomor penerima (Personal/Grup). Bisa berupa string tunggal atau array of strings (Maks 1000 nomor). Format: "62812...", "0812...", atau grup "123456789@g.us".
message string Tidak* Isi teks pesan. Mendukung emoji, format bawaan WA, dan Mention (@6289...).
*Wajib jika Anda tidak melampirkan media.
webhookUrl string Tidak URL Publik (http/https) untuk menerima notifikasi status pengiriman (Callback). Sangat disarankan jika mengirim ke banyak nomor (array).
mediaUrl string Tidak URL Publik gambar/video/file. Sistem otomatis mendownload dan menjadikannya lampiran.
mediaBase64 string Tidak Data mentah file berformat Base64 string (Misal hasil export PDF di memory). Jangan sertakan header data:....
mimetype string Tidak** Format tipe MIME dari file Base64 Anda (contoh: image/png, video/mp4).
**Wajib disi jika menggunakan mediaBase64.

Skenario Pengiriman 🚀

Klik tab di bawah ini untuk melihat contoh detail dari setiap skenario pengiriman yang didukung.

📝 1. Mengirim Teks Saja (Single Nomor)
Skenario paling dasar. Mengirimkan pesan teks ke 1 nomor. Karena tidak menggunakan webhookUrl, API akan berjalan secara Synchronous (koneksi ditahan sampai pesan berhasil dikirim).
curl -X POST "http://localhost:3000/api/send" \
     -H "x-api-key: rahasia_negara_123" \
     -H "Content-Type: application/json" \
     -d '{
           "phone": "081234567890",
           "message": "Halo! Tagihan bulan ini sudah keluar. Cek di web."
         }'
fetch("http://localhost:3000/api/send", {
  method: "POST",
  headers: { "x-api-key": "rahasia_negara_123", "Content-Type": "application/json" },
  body: JSON.stringify({
    phone: "081234567890",
    message: "Halo! Tagihan bulan ini sudah keluar. Cek di web."
  })
}).then(res => res.json()).then(console.log);
{
  "success": true,
  "message": "Pesan berhasil dikirim",
  "messageId": "true_6281234567890@c.us_3A32D659ABCDEF123"
}
📣 2. Mengirim Teks Saja (Multiple Nomor / Array)
Mengirimkan pesan broadcast ke banyak nomor sekaligus (Maksimal 1000). Parameter phone beruba array. Request otomatis menjadi Asynchronous (mengembalikan 202 Accepted) dan disarankan menggunakan webhookUrl untuk memantau status setiap nomor.
curl -X POST "http://localhost:3000/api/send" \
     -H "x-api-key: rahasia_negara_123" \
     -H "Content-Type: application/json" \
     -d '{
           "phone": ["08123456789", "628987654321", "08555666777"],
           "message": "Pengumuman: Server akan maintenance malam ini.",
           "webhookUrl": "https://domain-anda.com/api/wa-callback"
         }'
fetch("http://localhost:3000/api/send", {
  method: "POST",
  headers: { "x-api-key": "rahasia_negara_123", "Content-Type": "application/json" },
  body: JSON.stringify({
    phone: ["08123456789", "628987654321", "08555666777"],
    message: "Pengumuman: Server akan maintenance malam ini.",
    webhookUrl: "https://domain-anda.com/api/wa-callback"
  })
}).then(res => res.json()).then(console.log);
{
  "success": true,
  "message": "3 pesan masuk antrian, 0 gagal validasi",
  "batchId": "batch_1720700000000_a1b2c3d4",
  "totalQueued": 3,
  "totalFailed": 0,
  "failedNumbers": [],
  "queueTotal": 3,
  "webhookUrl": "https://domain-anda.com/api/wa-callback"
}
🖼️ 3. Mengirim Teks + Gambar
Skenario mengirim lampiran gambar beserta caption. Teks pada parameter message akan otomatis menjadi caption (keterangan) dari gambar tersebut. Gunakan parameter mediaUrl.
curl -X POST "http://localhost:3000/api/send" \
     -H "x-api-key: rahasia_negara_123" \
     -H "Content-Type: application/json" \
     -d '{
           "phone": "08123456789",
           "message": "Katalog produk bulan ini, silakan dilihat ya Kak!",
           "mediaUrl": "https://images.unsplash.com/photo-1575936123452-b67c3203c357?q=80"
         }'
fetch("http://localhost:3000/api/send", {
  method: "POST",
  headers: { "x-api-key": "rahasia_negara_123", "Content-Type": "application/json" },
  body: JSON.stringify({
    phone: "08123456789",
    message: "Katalog produk bulan ini, silakan dilihat ya Kak!",
    mediaUrl: "https://images.unsplash.com/photo-1575936123452-b67c3203c357?q=80"
  })
}).then(res => res.json()).then(console.log);
{
  "success": true,
  "message": "Pesan berhasil dikirim",
  "messageId": "true_628123456789@c.us_8A71D888ABCDEF999"
}
🖼️ 4. Mengirim Gambar Saja (Tanpa Teks)
Anda dapat menghilangkan parameter message jika hanya ingin mengirimkan gambar polos tanpa caption.
curl -X POST "http://localhost:3000/api/send" \
     -H "x-api-key: rahasia_negara_123" \
     -H "Content-Type: application/json" \
     -d '{
           "phone": "08123456789",
           "mediaUrl": "https://images.unsplash.com/photo-1575936123452-b67c3203c357?q=80"
         }'
fetch("http://localhost:3000/api/send", {
  method: "POST",
  headers: { "x-api-key": "rahasia_negara_123", "Content-Type": "application/json" },
  body: JSON.stringify({
    phone: "08123456789",
    mediaUrl: "https://images.unsplash.com/photo-1575936123452-b67c3203c357?q=80"
  })
}).then(res => res.json()).then(console.log);
{
  "success": true,
  "message": "Pesan berhasil dikirim",
  "messageId": "true_628123456789@c.us_8A71D888ABCDEF999"
}
🎬 5. Mengirim Teks + Video
Sama seperti mengirim gambar, parameter mediaUrl mendukung URL Video (mp4). Sertakan message untuk caption.
curl -X POST "http://localhost:3000/api/send" \
     -H "x-api-key: rahasia_negara_123" \
     -H "Content-Type: application/json" \
     -d '{
           "phone": "08123456789",
           "message": "Tonton tutorial video terbaru kami di bawah ini!",
           "mediaUrl": "https://www.w3schools.com/html/mov_bbb.mp4"
         }'
fetch("http://localhost:3000/api/send", {
  method: "POST",
  headers: { "x-api-key": "rahasia_negara_123", "Content-Type": "application/json" },
  body: JSON.stringify({
    phone: "08123456789",
    message: "Tonton tutorial video terbaru kami di bawah ini!",
    mediaUrl: "https://www.w3schools.com/html/mov_bbb.mp4"
  })
}).then(res => res.json()).then(console.log);
{
  "success": true,
  "message": "Pesan berhasil dikirim",
  "messageId": "true_628123456789@c.us_9B82E999ABCDEF000"
}
🎬 6. Mengirim Video Saja
Mengirim file video polos tanpa caption teks.
curl -X POST "http://localhost:3000/api/send" \
     -H "x-api-key: rahasia_negara_123" \
     -H "Content-Type: application/json" \
     -d '{
           "phone": "08123456789",
           "mediaUrl": "https://www.w3schools.com/html/mov_bbb.mp4"
         }'
fetch("http://localhost:3000/api/send", {
  method: "POST",
  headers: { "x-api-key": "rahasia_negara_123", "Content-Type": "application/json" },
  body: JSON.stringify({
    phone: "08123456789",
    mediaUrl: "https://www.w3schools.com/html/mov_bbb.mp4"
  })
}).then(res => res.json()).then(console.log);
{
  "success": true,
  "message": "Pesan berhasil dikirim",
  "messageId": "true_628123456789@c.us_9B82E999ABCDEF000"
}
👥 7. Mengirim ke Grup + Mention Pengguna
Mengirimkan pesan ke Grup (ID berakhiran @g.us) dan me-mention (tag) anggota tertentu. Format mention WAJIB ditulis dengan awalan @ diikuti nomor tanpa spasi (misal: @628123456789). Sistem Gateway akan otomatis mendeteksi format tersebut dan membuatkan *tagging* WhatsApp. Anda bisa mencari ID Grup di endpoint /api/groups.
curl -X POST "http://localhost:3000/api/send" \
     -H "x-api-key: rahasia_negara_123" \
     -H "Content-Type: application/json" \
     -d '{
           "phone": "1203631234567890@g.us",
           "message": "Pengumuman untuk @628123456789 dan @628987654321, tolong segera join ke ruang meeting ya! 🚀"
         }'
fetch("http://localhost:3000/api/send", {
  method: "POST",
  headers: { "x-api-key": "rahasia_negara_123", "Content-Type": "application/json" },
  body: JSON.stringify({
    phone: "1203631234567890@g.us",
    message: "Pengumuman untuk @628123456789 dan @628987654321, tolong segera join ke ruang meeting ya! 🚀"
  })
}).then(res => res.json()).then(console.log);
{
  "success": true,
  "message": "Pesan berhasil dikirim",
  "messageId": "true_1203631234567890@g.us_9A82D123ABCDEF123"
}


2. Webhook Event Payloads (Callback)

Jika Anda menyertakan parameter webhookUrl pada endpoint pengiriman pesan, server kami akan melakukan POST ke URL Anda setiap kali ada perubahan status. Berikut adalah bentuk payload (JSON) yang akan diterima URL Anda.

Event: batch.started
{
  "event": "batch.started",
  "batchId": "batch_1720700000000_a1b2c3d4",
  "totalQueued": 3,
  "totalFailed": 0,
  "timestamp": "2026-07-11T12:00:00.000Z"
}
Event: message.sent
{
  "event": "message.sent",
  "phone": "628123456789",
  "batchId": "batch_1720700000000_a1b2c3d4",
  "messageId": "true_628123456789@c.us_3A32D659ABCDEF",
  "success": true,
  "timestamp": "2026-07-11T12:00:10.000Z"
}
Event: message.failed
{
  "event": "message.failed",
  "phone": "628999999999",
  "batchId": "batch_1720700000000_a1b2c3d4",
  "error": "Nomor tidak terdaftar di WhatsApp",
  "success": false,
  "timestamp": "2026-07-11T12:00:15.000Z"
}


3. Endpoint Monitoring & Status

Gunakan endpoint GET di bawah ini untuk memantau performa, status antrian, dan status bot.

GET /api/queue/status Base URL: http://localhost:3000

Melihat kondisi antrian pesan gateway dan status pembatasan pesan keluar.

curl -X GET "http://localhost:3000/api/queue/status" -H "x-api-key: rahasia_negara_123"
fetch("http://localhost:3000/api/queue/status", { headers: { "x-api-key": "rahasia_negara_123" } })
.then(res => res.json()).then(console.log);
{
  "success": true,
  "queue": {
    "queueLength": 25,
    "processing": true,
    "totalProcessed": 105,
    "totalFailed": 2,
    "hourlyCount": 42
  },
  "health": { "healthy": true },
  "rateLimiter": {
    "messagesLastMinute": 15,
    "maxPerMinute": 20
  }
}
GET /api/status Base URL: http://localhost:3000

Melihat statistik penggunaan Quota AI Harian, uptime server, dan RAM.

curl -X GET "http://localhost:3000/api/status" -H "x-api-key: rahasia_negara_123"
fetch("http://localhost:3000/api/status", { headers: { "x-api-key": "rahasia_negara_123" } })
.then(res => res.json()).then(console.log);
{
  "success": true,
  "status": "ready",
  "uptime": "2j 30m",
  "memory": "85 MB",
  "ai_quota": {
    "gemini": 450,
    "openrouter": 20,
    "total": 470
  }
}
GET /api/groups Base URL: http://localhost:3000

Mendapatkan list semua grup yang bot ikuti. Berguna untuk mencari ID Grup berakhiran @g.us.

curl -X GET "http://localhost:3000/api/groups" -H "x-api-key: rahasia_negara_123"
fetch("http://localhost:3000/api/groups", { headers: { "x-api-key": "rahasia_negara_123" } })
.then(res => res.json()).then(console.log);
{
  "success": true,
  "count": 2,
  "groups": [
    {
      "id": "1203631234567890@g.us",
      "name": "Grup IT Support Pusat"
    },
    {
      "id": "628123456789-1612345678@g.us",
      "name": "Keluarga Besar"
    }
  ]
}
GET /health NO AUTH Base URL: http://localhost:3000

Ping ringan untuk Load Balancer atau UptimeRobot. Tidak memerlukan header x-api-key.

curl -X GET "http://localhost:3000/health"
fetch("http://localhost:3000/health")
.then(res => res.json()).then(console.log);
{
  "status": "ok"
}