WA Gateway API

WhatsApp Gateway berbasis Baileys (multi-device, tanpa WhatsApp Business API). Satu server bisa menjalankan banyak nomor (device) sekaligus, masing-masing punya device key sendiri.

Base URL: https://151.245.136.93:8443

1. Mulai cepat

  1. Buka Admin Panel, login dengan password admin.
  2. Klik + Device Baru → beri nama (mis. cs-bot). Simpan device key yang tampil.
  3. Pairing — dua cara:
    • QR scan: buka Kelola → tab Koneksi / QR → scan QR dari WhatsApp (Perangkat Tertaut → Tautkan perangkat). QR refresh otomatis tiap 4 detik.
    • Pairing code: masukkan nomor (628xxx) → dapat kode 8 digit → WhatsApp → Perangkat Tertaut → Tautkan dengan nomor telepon.
  4. Setelah status connected, device siap dipakai lewat REST API.

Kirim pesan pertama

curl -X POST https://151.245.136.93:8443/api/v1/send \
  -H "X-Device-Key: wag_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"to":"628123456789","type":"text","message":"Halo dari WA Gateway"}'
Response: {"success":true,"type":"text","result":{"to":"[email protected]","type":"text","wa_msg_id":"3EB0…","message_id":12}}

2. Autentikasi

Semua endpoint /api/v1/* butuh device key. Tiga cara:

X-Device-Key: wag_xxxxxxxxxxxxxxxx      ← disarankan
Authorization: Bearer wag_xxxxxxxxxxxxxxxx
?device_key=wag_xxxxxxxxxxxxxxxx        ← untuk testing cepat

3. Device & pairing (bisa lewat API)

Supaya aplikasimu bisa onboarding nomor sendiri tanpa buka panel.

GET/api/v1/device/qr

Ambil QR untuk di-scan (poll tiap ±4 detik sampai connected).

{
  "success": true,
  "status": "qr",                 // connected | qr | pairing | connecting | reconnecting | disconnected | stopped | logged_out | error
  "connected": false,
  "qr": "data:image/png;base64,iVBOR…",   // tinggal 
  "qr_raw": "2@abc123…",                   // string QR mentah kalau mau generate sendiri
  "qr_expires_in_ms": 12400,
  "pairing_code": null,
  "phone": null
}
POST/api/v1/device/pairing-code

Alternatif QR — kode 8 digit untuk nomor tertentu (hanya sebelum session terdaftar).

curl -X POST .../api/v1/device/pairing-code -H "X-Device-Key: wag_xxx" \
  -d '{"phone":"628123456789"}'
{"success":true,"pairing_code":"V7H7NRKZ","phone":"628123456789"}
POST/api/v1/device/connect

Jalankan / sambungkan ulang session. Body opsional {"phone":"628xxx"} untuk langsung masuk mode pairing code.

POST/api/v1/device/disconnect

Putuskan session. Body {"logout":true} = logout dari WhatsApp (perlu pairing ulang).

POST/api/v1/device/reset-session

Hapus kredensial session (paksa pairing ulang). Wajib kirim {"confirm":true}.

GET/api/v1/device

Info device + profil WhatsApp yang login.

GET/api/v1/device/status

Cek cepat: {"status":"connected","connected":true}

POST/api/v1/device/check-number

Cek nomor terdaftar WhatsApp. Body {"phone":"08123456789"}.

POST/api/v1/device/presence

Status mengetik/online. {"to":"628xxx","type":"composing"}

POST/api/v1/device/read

Tandai sudah dibaca (centang biru). {"chat_id":"628xxx"}

4. Kirim pesan — satu endpoint

POST/api/v1/send JSONmultipart/form-data

Semua tipe pesan lewat endpoint ini. Field type menentukan jenisnya — default text.

Parameter

FieldWajibKeterangan
toyaNomor (628xxx / 0812xxx) atau ID grup
typetidaktext (default) | image | video | audio | document | sticker | location | contact | reaction
messageper tipeIsi teks; untuk media jadi caption. Alias: text, caption
urlper tipeURL media (bisa juga image/video/audio/document/sticker/media)
filetidakUpload langsung (multipart) — kalau ada, type terdeteksi otomatis dari MIME
filename / mimetypetidakUntuk document & audio
ptttidaktrue = voice note (type audio)
latitude / longitudeya (location)Koordinat, plus name & address opsional
contactsya (contact)[{"name":"Budi","phone":"628111"}] atau name+phone
message_id / emojiya (reaction)Reaksi ke pesan tertentu
reply_totidakwa_msg_id yang mau di-quote
is_grouptidaktrue kalau to diisi ID grup tanpa suffix @g.us

Contoh per tipe

# TEXT (default)
{"to":"628123456789","message":"Halo 👋"}

# IMAGE
{"to":"628123456789","type":"image","url":"https://contoh.com/foto.jpg","message":"caption"}

# VIDEO
{"to":"628123456789","type":"video","url":"https://contoh.com/video.mp4","message":"caption"}

# AUDIO (message → caption tidak dipakai; ptt:true = voice note)
{"to":"628123456789","type":"audio","url":"https://contoh.com/a.mp3","ptt":false}

# DOCUMENT
{"to":"628123456789","type":"document","url":"https://contoh.com/invoice.pdf",
 "filename":"invoice.pdf","mimetype":"application/pdf","message":"Invoice"}

# STICKER
{"to":"628123456789","type":"sticker","url":"https://contoh.com/stiker.webp"}

# LOCATION
{"to":"628123456789","type":"location","latitude":-6.2088,"longitude":106.8456,
 "name":"Kantor","address":"Jl. Contoh No. 1"}

# CONTACT
{"to":"628123456789","type":"contact","contacts":[{"name":"Budi","phone":"628111222333"}]}

# REACTION (emoji "" = hapus reaksi)
{"to":"628123456789","type":"reaction","message_id":"3EB0XXXX","emoji":"👍"}

Upload file sendiri (multipart)

curl -X POST https://151.245.136.93:8443/api/v1/send \
  -H "X-Device-Key: wag_xxxxxxxx" \
  -F "to=628123456789" \
  -F "type=image" \
  -F "message=caption dari HP" \
  -F "file=@/path/foto.jpg"

Kalau type tidak dikirim, tipenya ditebak dari MIME file (image/* → image, video/* → video, audio/* → audio, lainnya → document). Maks. ukuran: 64 MB.

Endpoint lama (/send/text, /send/image, /send/video, /send/audio, /send/document, /send/sticker, /send/location, /send/contact, /send/media, /send/reaction) masih jalan untuk kompatibilitas, tapi tidak lagi didokumentasikan di sini. Pakai /api/v1/send.

5. Bulk / broadcast

POST/api/v1/send/bulk
{
  "delay_ms": 1500,
  "messages": [
    {"to":"628111111111","message":"Promo hari ini"},
    {"to":"628222222222","message":"Promo hari ini"},
    {"to":"[email protected]","message":"Promo di grup","is_group":true}
  ]
}

Response berisi ringkasan success/failed + detail per nomor. Jeda default 1,5 detik (anti-spam). Maks 500 nomor per request.

Kirim massal ke nomor yang tidak opt-in berisiko membuat nomor diblokir WhatsApp. Pakai jeda wajar dan hanya ke kontak yang mengizinkan.

6. Grup

EndpointFungsi
GET /api/v1/groupsDaftar grup yang diikuti device
GET /api/v1/groups/:jidMetadata grup + daftar peserta
POST /api/v1/groupsBuat grup: {"subject":"Nama","participants":["628111"]}
POST /api/v1/groups/:jid/participants{"participants":["628111"],"action":"add"} — add | remove | promote | demote
POST /api/v1/groups/:jid/leaveKeluar dari grup

7. Riwayat pesan

GET/api/v1/messages?chat_id=&direction=in|out&limit=50&offset=0
{
  "success": true, "total": 128,
  "messages": [{
    "id": 128, "device_id": "cs-bot-1a2b3c", "direction": "in",
    "chat_id": "[email protected]", "chat_name": "Budi",
    "is_group": false, "type": "conversation", "body": "Halo min",
    "media_url": null, "wa_msg_id": "3EB0…", "status": "received",
    "created_at": 1792238000000, "created_at_iso": "2026-10-17T11:53:20.000Z"
  }]
}

GET /api/v1/messages/:id untuk satu pesan. Media masuk otomatis diunduh dan tersedia di media_url.

POST /api/v1/message/delete — hapus pesan untuk semua orang: {"to":"628xxx","message_id":"3EB0…","from_me":true}

8. Webhook (pesan masuk)

Set URL per device di admin panel (tab Webhook). Gateway POST JSON tiap ada pesan masuk / keluar (pilih event-nya).

POST https://app-anda.com/webhook
Content-Type: application/json
X-Webhook-Event: message
X-Device-Id: cs-bot-1a2b3c

{
  "event": "message",
  "device_id": "cs-bot-1a2b3c",
  "device_name": "cs-bot",
  "sent_at": "2026-10-17T11:53:20.000Z",
  "data": {
    "message_id": 128, "direction": "in",
    "chat_id": "[email protected]", "chat_name": "Budi",
    "sender_id": "[email protected]", "sender_name": "Budi",
    "is_group": false, "type": "conversation", "body": "Halo min",
    "media_path": null, "wa_msg_id": "3EB0…", "status": "received"
  }
}

Event: message (masuk), message.sent (keluar), test. Response 2xx = sukses; kegagalan tercatat di tab Webhook Log.

Test cepat: POST /api/v1/webhook/test body {"url":"https://app-anda.com/webhook"}

9. Admin Panel & API-nya

Panel: /admin/. Fitur: statistik, kelola device (QR, pairing code, start/stop/restart/logout/reset, rotate key, hapus), kirim uji (pilih tipe), log pesan, log webhook.

Endpoint adminFungsi
POST /admin/api/login{"password":"…"} → token admin (12 jam)
GET /admin/api/overviewStatistik + daftar device
POST /admin/api/devicesBuat device: {"name":"cs-bot","phone":"628xxx","webhook_url":"…"}
GET /admin/api/devices/:id/qrQR + pairing code + status
POST /admin/api/devices/:id/pairing-codeMinta kode 8 digit
POST …/start | stop | restart | logout | reset-sessionKontrol session
PATCH /admin/api/devices/:idUbah nama/webhook/aktif/autostart
POST /admin/api/devices/:id/rotate-keyGanti device key
DELETE /admin/api/devices/:idHapus device + session + riwayat
GET /admin/api/eventsServer-Sent Events (update realtime panel)

10. Operasional

Aplikasi jalan sebagai service systemd (wa-gateway.service) di /www/wwwroot/wa-gateway, port 8787 (internal), dan diakses publik lewat nginx 8443 (HTTPS).

sudo systemctl status wa-gateway
sudo systemctl restart wa-gateway
tail -f /www/wwwroot/wa-gateway/logs/server.out

Troubleshooting

MasalahSolusi
Status logged_outDevice dikeluarkan dari HP → Reset session di panel, pairing ulang
QR tidak munculKlik Jalankan / Restart; pastikan server bisa akses internet ke WhatsApp
409 belum terhubungPairing dulu sampai status connected
Nomor saling tendangSatu nomor tidak boleh dipakai di dua device/HP web sekaligus
HTTPS errorPort publik hanya 8443; cek sertifikat nginx (/www/server/panel/vhost/nginx/wa-gateway-https.conf)

Backup: sessions/ (kredensial WhatsApp) dan data/wa-gateway.db (device, key, riwayat). Spesifikasi mesin: /openapi.json.