Dokumentasi API
Integrasi WhatsApp Gateway
WA Gateway menyediakan REST API JSON dan stream Server-Sent Events. Aplikasi apa pun yang bisa melakukan HTTP request bisa mengirim & menerima pesan WhatsApp.
Tautkan
POST /api/login lalu scan QR dari /api/status
Dengarkan
GET /api/events untuk pesan masuk realtime
Balas
POST /api/send ke field chat dari pesan
Base URL & format
Semua endpoint berada di bawah prefix /api. Request & response memakai JSON (Content-Type: application/json). Base URL dashboard ini:
https://wa-be.jackzstore.idError selalu berbentuk objek dengan satu field error dan status HTTP 4xx/5xx:
{ "error": "whatsapp belum terhubung" }Keamanan
CORS_ORIGINS./api/healthHealth check
Memastikan proses backend hidup. Tidak bergantung pada status WhatsApp.
curl https://wa-be.jackzstore.id/api/health{ "status": "ok" }/api/statusStatus koneksi
Mengembalikan objek WAState. Saat status qr, field qr berisi gambar PNG (data URL) yang bisa langsung dipakai di <img src>.
curl https://wa-be.jackzstore.id/api/status{
"status": "connected",
"jid": "6281234567890@s.whatsapp.net",
"pushName": "Toko Sejahtera"
}/api/loginMulai login QR
Memulai pairing. QR berganti otomatis tiap ~20 detik; ikuti lewat event state atau polling /api/status. Mengembalikan 202 Accepted.
curl -X POST https://wa-be.jackzstore.id/api/login{ "status": "connecting" }/api/pair-phoneLogin dengan kode pairing
Alternatif QR: menghasilkan kode 8 karakter yang dimasukkan di HP lewat Perangkat tertaut → Tautkan dengan nomor telepon.
| Body | Tipe | Keterangan |
|---|---|---|
| phone* | string | Nomor yang akan ditautkan. Format 08xx atau 628xx; karakter non-digit diabaikan. |
curl -X POST https://wa-be.jackzstore.id/api/pair-phone \
-H 'Content-Type: application/json' \
-d '{"phone":"6281234567890"}'{ "code": "ABCD-1234" }/api/sendKirim pesan teks
Mengirim teks ke nomor atau grup dan mengembalikan objek WAMessage yang terkirim. Nomor dicek dulu dengan IsOnWhatsApp.
| Body | Tipe | Keterangan |
|---|---|---|
| to* | string | Nomor (08xx / 628xx) atau JID lengkap: …@s.whatsapp.net untuk pribadi, …@g.us untuk grup. |
| message* | string | Isi pesan teks. |
curl -X POST https://wa-be.jackzstore.id/api/send \
-H 'Content-Type: application/json' \
-d '{"to":"081234567890","message":"Halo dari API"}'{
"id": "3EB0C431D2A1B6F1A2B3",
"chat": "6281234567890@s.whatsapp.net",
"sender": "6281234567890@s.whatsapp.net",
"text": "Halo, pesanan saya sudah dikirim?",
"type": "text",
"fromMe": true,
"isGroup": false,
"timestamp": "2026-10-13T09:41:00+07:00"
}/api/messagesDaftar pesan
Pesan masuk & keluar yang ditampung di memori (maks. 500, hilang saat backend restart). Gunakan since agar hanya pesan baru yang diambil, misalnya saat resync setelah koneksi SSE terputus.
| Query | Tipe | Keterangan |
|---|---|---|
| since | integer | Unix timestamp dalam milidetik. Hanya pesan dengan timestamp ≥ nilai ini yang dikembalikan. |
curl https://wa-be.jackzstore.id/api/messages?since=1791866460000[
{
"id": "3EB0C431D2A1B6F1A2B3",
"chat": "6281234567890@s.whatsapp.net",
"sender": "6281234567890@s.whatsapp.net",
"pushName": "Rina",
"text": "Halo, pesanan saya sudah dikirim?",
"type": "text",
"fromMe": false,
"isGroup": false,
"timestamp": "2026-10-13T09:41:00+07:00"
}
]/api/broadcastsMulai broadcast
Mengirim satu pesan ke banyak nomor secara bertahap di server (tetap berjalan walau klien terputus). Nomor duplikat dibuang, nomor tidak valid langsung ditandai gagal. Hanya satu broadcast yang boleh aktif. Progres dikirim lewat event broadcast.
| Body | Tipe | Keterangan |
|---|---|---|
| to | string[] | Daftar nomor (08xx / 628xx) atau JID tanpa personalisasi. |
| recipients | { to, vars? }[] | Penerima dengan variabel personalisasi, mis. { "to": "0812…", "vars": { "nama": "Rina" } }. Bisa digabung dengan to; total maks. 5000. |
| message* | string | Template pesan: {nama}, {nama:default}, dan spintax {Halo|Hai}. Lihat bagian Personalisasi. |
| delayMin* | integer | Delay minimum antar pesan (detik, ≥ 1). |
| delayMax* | integer | Delay maksimum (detik). Delay diacak di antara min dan max. |
| batchSize | integer | Istirahat setiap N pesan. 0 = tanpa istirahat. |
| batchSleep | integer | Lama istirahat (detik) setelah setiap batch. |
curl -X POST https://wa-be.jackzstore.id/api/broadcasts \
-H 'Content-Type: application/json' \
-d '{"recipients":[{"to":"081234567890","vars":{"nama":"Rina","kota":"Bandung"}},{"to":"089876543210","vars":{"nama":"Budi"}}],"message":"{Halo|Hai} {nama:Kak}! Promo untuk {kota:kotamu} sudah dimulai.","delayMin":10,"delayMax":20,"batchSize":20,"batchSleep":300}'{
"id": "a1b2c3d4e5f6",
"status": "running",
"total": 2, "sent": 0, "failed": 0,
"settings": { "delayMin": 10, "delayMax": 20, "batchSize": 20, "batchSleep": 300 },
"recipients": [
{ "to": "6281234567890", "vars": { "nama": "Rina", "kota": "Bandung" }, "status": "pending" },
{ "to": "6289876543210", "vars": { "nama": "Budi" }, "status": "pending" }
]
}/api/broadcasts/{id}Detail & progres broadcast
Status per nomor (pending, sent, failed + alasan). GET /api/broadcasts mengembalikan ringkasan 20 broadcast terakhir (disimpan di memori, hilang saat backend restart).
curl https://wa-be.jackzstore.id/api/broadcasts/a1b2c3d4e5f6{
"id": "a1b2c3d4e5f6",
"status": "running",
"note": "Istirahat setelah 20 pesan",
"nextAt": "2026-10-13T10:05:00+07:00",
"total": 120, "sent": 40, "failed": 1,
"recipients": [
{ "to": "6281234567890", "status": "sent", "sentAt": "…",
"text": "Hai Rina! Promo untuk Bandung sudah dimulai." },
…
]
}/api/broadcasts/{id}/{action}Jeda, lanjutkan, batalkan
action berisi pause, resume, atau cancel. Bila WhatsApp terputus di tengah jalan, broadcast otomatis dijeda dan nomor yang sedang diproses tidak dilewati; panggil resume setelah terhubung.
curl -X POST https://wa-be.jackzstore.id/api/broadcasts/a1b2c3d4e5f6/pause{ "id": "a1b2c3d4e5f6", "status": "paused", … }/api/logoutLogout
Memutus tautan perangkat dan menghapus sesi dari database. Perlu scan ulang untuk login.
curl -X POST https://wa-be.jackzstore.id/api/logout{ "status": "disconnected" }/api/eventsServer-Sent Events
Koneksi HTTP yang tetap terbuka dan mengirim event saat sesuatu terjadi. Saat tersambung, server langsung mengirim satu event state. Komentar : ping dikirim tiap 20 detik agar koneksi tidak diputus proxy.
| Event | Tipe | Keterangan |
|---|---|---|
| state | WAState | Status koneksi berubah (QR baru, terhubung, logout, …). |
| message | WAMessage | Pesan masuk, atau pesan keluar (termasuk yang dikirim dari HP). Pesan broadcast tidak dikirim lewat event ini. |
| broadcast | { broadcast, index?, recipient? } | Progres broadcast: ringkasan terbaru, plus nomor yang baru diproses. |
timestamp lama. Bandingkan timestamp dengan waktu aplikasi Anda mulai mendengarkan bila hanya ingin memproses pesan baru. Dashboard memakai cara ini.const since = Date.now()
const es = new EventSource("https://wa-be.jackzstore.id/api/events")
es.addEventListener("state", (e) => {
const state = JSON.parse(e.data)
console.log("status:", state.status)
})
es.addEventListener("message", (e) => {
const msg = JSON.parse(e.data)
// Abaikan pesan lama (mis. pesan offline yang baru tersinkron)
if (new Date(msg.timestamp).getTime() < since) return
console.log(msg.pushName ?? msg.sender, ":", msg.text)
})Objek WAState
| Field | Tipe | Keterangan |
|---|---|---|
| status* | "disconnected" | "connecting" | "qr" | "connected" | Status koneksi saat ini. |
| jid | string | JID akun yang tertaut (hanya saat connected). |
| pushName | string | Nama profil WhatsApp akun. |
| qr | string | QR code sebagai data URL PNG (hanya saat status qr). |
| qrExpiry | number | Kedaluwarsa QR, Unix milidetik. |
| error | string | Alasan terakhir terputus / gagal pairing. |
Objek WAMessage
| Field | Tipe | Keterangan |
|---|---|---|
| id* | string | ID pesan dari WhatsApp. |
| chat* | string | JID room: nomor lawan bicara atau grup (…@g.us). |
| sender* | string | JID pengirim (di grup berbeda dengan chat). |
| pushName | string | Nama profil pengirim (pesan masuk saja). |
| text* | string | Teks / caption / nama file. Kosong untuk audio, stiker, dsb. |
| type* | string | text, image, video, document, audio, sticker, location, contact, poll, reaction, other. |
| fromMe* | boolean | true bila dikirim dari akun ini. |
| isGroup* | boolean | true bila pesan grup. |
| timestamp* | string (RFC 3339) | Waktu pesan menurut server WhatsApp. |
{
"id": "3EB0C431D2A1B6F1A2B3",
"chat": "6281234567890@s.whatsapp.net",
"sender": "6281234567890@s.whatsapp.net",
"pushName": "Rina",
"text": "Halo, pesanan saya sudah dikirim?",
"type": "text",
"fromMe": false,
"isGroup": false,
"timestamp": "2026-10-13T09:41:00+07:00"
}Format nomor & JID
WhatsApp mengidentifikasi akun & grup dengan JID. Field to menerima nomor biasa atau JID:
| 081234567890 | → 6281234567890@s.whatsapp.net | 0 di depan diganti 62 |
| +62 812-3456-7890 | → 6281234567890@s.whatsapp.net | spasi & tanda diabaikan |
| 1203630…@g.us | dipakai apa adanya | grup |
| 2384…@lid | dipakai apa adanya | ID privasi (LID) bila nomor tidak diketahui |
Untuk membalas pesan, kirim ke field chat dari pesan tersebut, sehingga balasan grup masuk ke grup dan balasan pribadi ke pengirim.
Personalisasi broadcast
Field message pada broadcast adalah template yang dirender di server untuk setiap penerima. Teks hasil render disimpan di field text tiap penerima.
| {nama} | Nilai variabel nama dari vars penerima (huruf besar/kecil tidak berpengaruh). Kosong bila tidak ada. |
| {nama:Kak} | Seperti di atas, tetapi memakai “Kak” bila nilainya kosong. |
| {nomor} | Nomor tujuan (selalu tersedia). |
| {Halo|Hai|Hei} | Spintax: satu opsi dipilih acak per penerima, agar pesan tidak identik. |
Template : {Halo|Hai} {nama:Kak}! Pesanan {invoice} siap diambil di {cabang}.
vars : { "nama": "Rina", "invoice": "INV-1042", "cabang": "Bandung" }
Hasil : Hai Rina! Pesanan INV-1042 siap diambil di Bandung.Di dashboard, variabel diambil dari tabel yang ditempel: baris pertama adalah header dengan kolom nomor (nomor, no_hp, phone, wa, …), dan setiap kolom lain otomatis menjadi variabel.
Penjadwalan pesan
Gateway mengirim pesan seketika saat /api/send dipanggil, sehingga penjadwalan cukup dilakukan dari scheduler yang sudah Anda pakai: cron, task scheduler aplikasi, atau workflow tool seperti n8n.
# Setiap tanggal 1 pukul 08.00: pengingat tagihan
0 8 1 * * curl -s -X POST https://wa-be.jackzstore.id/api/send \
-H 'Content-Type: application/json' \
-d '{"to":"081234567890","message":"Tagihan bulan ini sudah terbit"}'
# Setiap hari kerja pukul 07.30: laporan ke grup tim
30 7 * * 1-5 /usr/local/bin/kirim-laporan.shContoh bot auto-reply
Mendengarkan pesan pribadi baru dan membalas ping dengan pong. Pola yang sama bisa dipakai untuk meneruskan pesan ke webhook, CRM, atau LLM.
// bot.mjs — Node 18+
import { EventSource } from "eventsource" // npm i eventsource
const API = "https://wa-be.jackzstore.id"
const startedAt = Date.now()
const es = new EventSource(`${API}/api/events`)
es.addEventListener("message", async (e) => {
const msg = JSON.parse(e.data)
if (msg.fromMe || msg.isGroup) return
if (new Date(msg.timestamp).getTime() < startedAt) return
if (msg.text.trim().toLowerCase() === "ping") {
await fetch(`${API}/api/send`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ to: msg.chat, message: "pong 🏓" }),
})
}
})