Dokumentasi API
Panduan integrasi kirim pesan WhatsApp — kompatibel dengan client yang sudah ada, plus webhook opsional untuk hasil pengiriman. Referensi endpoint publik untuk mengirim pesan WhatsApp. Untuk mengirim dari panel, Masuk.
Pengenalan API
Autentikasi setiap request memakai token_device dari perangkat tertaut. Semua endpoint memakai JSON dan header application/json. Kirim teks (default) atau media (gambar, dokumen, video, audio) lewat POST /v1/messages yang sama. Pengiriman selalu masuk antrian (wa-worker → WhatsApp); client teks saja yang tidak mengirim type tetap sama.
Alur pengiriman
- Client POST /v1/messages → HiWA membalas HTTP 200 { ok: true, job_id, message, quota }.
- Pesan diproses di belakang layar (wa-worker → WhatsApp).
- Saat selesai: jika perangkat punya URL Webhook, HiWA POST hasil akhir (success/failed) ke URL itu dengan job_id yang sama.
Base URL
https://hiwa.my.id/api
Header
Header: Accept: application/json, Content-Type: application/json
token_device
Token kirim perangkat dari alur Perangkat (ditampilkan sekali saat perangkat pertama kali terhubung, atau setelah dibuat ulang).
https://hiwa.my.id/api/v1/messages
Kirim teks ke satu nomor WhatsApp (chat 1–1). Tanpa field type = teks (default). Untuk gambar, dokumen, video, atau audio lihat bagian Kirim media.
Body JSON
{
"token_device": "YOUR_DEVICE_TOKEN_HERE",
"to": "6281234567890",
"message": "Hello from HiWA API"
}
token_device— Token kirim perangkat dari alur Perangkat (ditampilkan sekali saat perangkat pertama kali terhubung, atau setelah dibuat ulang).to— Nomor internasional (mis. 62812…) atau JID @c.us / @s.whatsapp.net. Nomor diawali 0 diubah ke 62.message— Isi teks biasa. (max 4096)
Respons POST sukses selalu berisi ok, job_id, message, dan quota pada HTTP 200.
Client integrasi cukup cek ok: true (boolean) pada HTTP 200.
Respons sukses
{
"ok": true,
"job_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"message": "Pesan sudah masuk antrian pengiriman.",
"quota": {
"messages_remaining": 99,
"messages_limit_per_month": 100
}
}
ok: true berarti pesan diterima HiWA (masuk antrian), bukan berarti sudah terkirim ke WhatsApp. Field message menjelaskan status antrian. Simpan job_id untuk hasil akhir via webhook atau cek status.
Kuota bulanan di respons API
Respons sukses dan sebagian besar error menyertakan objek `quota` untuk pengguna pemilik perangkat: `messages_remaining` dan `messages_limit_per_month`. Setelah sukses, nilai remaining sudah dikurangi untuk pesan yang baru dikirim.
401 `token_device` tidak valid — hanya `ok` dan `message`, tanpa `quota`. 403 akun tidak aktif — ada `quota` (nol jika perangkat tanpa pemilik). 403 paket anggota BillingHub dari IP yang tidak diizinkan — ada `quota`. 422 — validasi Laravel memakai `errors` dan `message`; perangkat belum terhubung, nomor tidak valid, kuota bulanan habis, dan banyak kegagalan gateway tetap menyertakan `quota` agar counter di aplikasi Anda bisa diperbarui. 404 / 409 / 5xx — gateway atau server; field `message` menjelaskan bila tersedia dan `quota` sering tetap ada setelah gagal kirim yang mengembalikan reservasi kuota.
Contoh — kuota bulanan habis (422)
{
"ok": false,
"job_id": null,
"message": "Kuota pesan bulanan paket Anda sudah habis. Coba lagi bulan depan atau naikkan paket.",
"quota": {
"messages_remaining": 0,
"messages_limit_per_month": 100
}
}
https://hiwa.my.id/api/v1/messages
Endpoint sama: POST /v1/messages. Isi to dengan JID grup. Akun WhatsApp yang tertaut harus masih anggota grup itu.
Body JSON
{
"token_device": "YOUR_DEVICE_TOKEN_HERE",
"to": "120363012345678901@g.us",
"message": "Hello group from HiWA API"
}
to— JID grup lengkap berakhiran @g.us (salin dari menu Grup kontak).
ID grup bisa dilihat di dashboard menu Grup kontak setelah perangkat terhubung.
Respons POST sukses selalu berisi ok, job_id, message, dan quota pada HTTP 200.
Client integrasi cukup cek ok: true (boolean) pada HTTP 200.
Respons sukses
{
"ok": true,
"job_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"message": "Pesan sudah masuk antrian pengiriman.",
"quota": {
"messages_remaining": 99,
"messages_limit_per_month": 100
}
}
ok: true berarti pesan diterima HiWA (masuk antrian), bukan berarti sudah terkirim ke WhatsApp. Field message menjelaskan status antrian. Simpan job_id untuk hasil akhir via webhook atau cek status.
Kuota bulanan di respons API
Respons sukses dan sebagian besar error menyertakan objek `quota` untuk pengguna pemilik perangkat: `messages_remaining` dan `messages_limit_per_month`. Setelah sukses, nilai remaining sudah dikurangi untuk pesan yang baru dikirim.
401 `token_device` tidak valid — hanya `ok` dan `message`, tanpa `quota`. 403 akun tidak aktif — ada `quota` (nol jika perangkat tanpa pemilik). 403 paket anggota BillingHub dari IP yang tidak diizinkan — ada `quota`. 422 — validasi Laravel memakai `errors` dan `message`; perangkat belum terhubung, nomor tidak valid, kuota bulanan habis, dan banyak kegagalan gateway tetap menyertakan `quota` agar counter di aplikasi Anda bisa diperbarui. 404 / 409 / 5xx — gateway atau server; field `message` menjelaskan bila tersedia dan `quota` sering tetap ada setelah gagal kirim yang mengembalikan reservasi kuota.
Contoh — kuota bulanan habis (422)
{
"ok": false,
"job_id": null,
"message": "Kuota pesan bulanan paket Anda sudah habis. Coba lagi bulan depan atau naikkan paket.",
"quota": {
"messages_remaining": 0,
"messages_limit_per_month": 100
}
}
https://hiwa.my.id/api/v1/messages
Endpoint sama: POST /v1/messages. Isi type dan media_url HTTPS yang bisa diakses publik. Berlaku untuk nomor personal dan JID grup. Client teks saja tidak berubah jika type diabaikan.
Body JSON — Gambar
{
"token_device": "YOUR_DEVICE_TOKEN_HERE",
"to": "6281234567890",
"type": "image",
"media_url": "https://example.com/photos/product.jpg",
"message": "Optional caption"
}
Body JSON — Dokumen
{
"token_device": "YOUR_DEVICE_TOKEN_HERE",
"to": "120363012345678901@g.us",
"type": "document",
"media_url": "https://example.com/files/invoice.pdf",
"filename": "invoice.pdf",
"mimetype": "application/pdf",
"message": "Invoice bulan ini"
}
type— text (default), image, document, video, atau audiomedia_url— URL HTTPS publik yang bisa dijangkau server (maks. 500 karakter). URL privat/localhost ditolak.message— Keterangan opsional untuk image, document, dan video (maks. 4096). Tidak dipakai untuk audio.mimetype— MIME type opsional (mis. application/pdf). Default diterapkan jika dikosongkan.filename— Nama tampilan opsional untuk type document.ptt— Boolean opsional untuk audio — true mengirim sebagai voice note WhatsApp (PTT).
Di halaman Kirim pesan dashboard Anda bisa unggah file alih-alih media_url; HiWA menyimpan file dan meneruskan URL publik ke antrian.
Respons POST sukses selalu berisi ok, job_id, message, dan quota pada HTTP 200.
Client integrasi cukup cek ok: true (boolean) pada HTTP 200.
Respons sukses
{
"ok": true,
"job_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"message": "Pesan sudah masuk antrian pengiriman.",
"quota": {
"messages_remaining": 99,
"messages_limit_per_month": 100
}
}
ok: true berarti pesan diterima HiWA (masuk antrian), bukan berarti sudah terkirim ke WhatsApp. Field message menjelaskan status antrian. Simpan job_id untuk hasil akhir via webhook atau cek status.
Kuota bulanan di respons API
Respons sukses dan sebagian besar error menyertakan objek `quota` untuk pengguna pemilik perangkat: `messages_remaining` dan `messages_limit_per_month`. Setelah sukses, nilai remaining sudah dikurangi untuk pesan yang baru dikirim.
401 `token_device` tidak valid — hanya `ok` dan `message`, tanpa `quota`. 403 akun tidak aktif — ada `quota` (nol jika perangkat tanpa pemilik). 403 paket anggota BillingHub dari IP yang tidak diizinkan — ada `quota`. 422 — validasi Laravel memakai `errors` dan `message`; perangkat belum terhubung, nomor tidak valid, kuota bulanan habis, dan banyak kegagalan gateway tetap menyertakan `quota` agar counter di aplikasi Anda bisa diperbarui. 404 / 409 / 5xx — gateway atau server; field `message` menjelaskan bila tersedia dan `quota` sering tetap ada setelah gagal kirim yang mengembalikan reservasi kuota.
Contoh — kuota bulanan habis (422)
{
"ok": false,
"job_id": null,
"message": "Kuota pesan bulanan paket Anda sudah habis. Coba lagi bulan depan atau naikkan paket.",
"quota": {
"messages_remaining": 0,
"messages_limit_per_month": 100
}
}
https://hiwa.my.id/api/v1/messages/{job_id}
Alternatif webhook: cek status pengiriman dengan job_id dari respons POST /v1/messages. Kirim POST dengan JSON body (sama seperti kirim pesan).
Body JSON
{
"token_device": "YOUR_DEVICE_TOKEN_HERE"
}
job_id— UUID dari respons POST /v1/messages (URL path)token_device— Token kirim perangkat dari alur Perangkat (ditampilkan sekali saat perangkat pertama kali terhubung, atau setelah dibuat ulang).
GET dengan query ?token_device=... juga didukung, tetapi POST disarankan agar konsisten dengan endpoint lain.
Respons sukses 200
{
"ok": true,
"job_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"status": "success",
"message_id": "120363012345678901@g.us_ABC123",
"error_message": null,
"quota": {
"messages_remaining": 99,
"messages_limit_per_month": 100
}
}
status: queued, processing, success, atau failed. message_id terisi setelah sukses; error_message setelah gagal.
Masih dalam antrian atau diproses
{
"ok": true,
"job_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"status": "queued",
"message_id": null,
"error_message": null,
"quota": {
"messages_remaining": 99,
"messages_limit_per_month": 100
}
}
Poll ulang sampai status menjadi success atau failed. Atau gunakan webhook agar tidak perlu poll.
Opsional. Hanya dikirim jika URL Webhook diisi pada perangkat. Tanpa URL, tidak ada notifikasi push — client cukup cek ok: true pada POST.
Cara mengaktifkan
- Buka Perangkat → Tambah perangkat, atau klik Webhook pada perangkat yang sudah ada.
- Isi URL Webhook (HTTPS), misalnya https://example.com/handle-hiwa
- Saat kirim API, simpan job_id dari respons POST untuk dicocokkan dengan webhook.
Kapan webhook dipanggil?
Hanya setelah pengiriman benar-benar selesai (status success atau failed), bukan saat POST /v1/messages. Jika URL Webhook kosong, tidak ada callback.
HiWA mengirim POST application/json ke URL Webhook perangkat Anda. Balas HTTP 2xx agar dianggap diterima.
Contoh payload
Pengiriman sukses (status: success)
{
"event": "message.delivery",
"job_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"status": "success",
"message_id": "120363012345678901@g.us_ABC123",
"to": "6281234567890@c.us",
"error_message": null,
"device_id": 1,
"channel": "api",
"delivered_at": "2026-06-11T08:30:00+00:00"
}
Pengiriman gagal (status: failed)
{
"event": "message.delivery",
"job_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"status": "failed",
"message_id": null,
"to": "6281234567890@c.us",
"error_message": "Session not connected",
"device_id": 1,
"channel": "api",
"delivered_at": "2026-06-11T08:30:15+00:00"
}
Field payload
| Field | Tipe | Keterangan |
|---|---|---|
event | string | Selalu message.delivery |
job_id | string (UUID) | Sama dengan job_id dari respons POST /v1/messages — gunakan untuk mencocokkan record di sistem Anda |
status | string | success atau failed (hasil akhir pengiriman) |
message_id | string|null | ID pesan dari WhatsApp jika sukses; null jika gagal |
to | string | Penerima (nomor @c.us atau JID grup @g.us) |
error_message | string|null | Penjelasan gagal jika status failed; null jika sukses |
device_id | integer | ID perangkat HiWA |
channel | string | Sumber kirim, misalnya api |
delivered_at | string (ISO 8601) | Waktu hasil akhir (ISO 8601) |
Di handler Anda: cari record berdasarkan job_id, lalu update status dari field status, message_id, atau error_message.
401— token_device tidak valid atau tidak dikenal. Respons ini tidak menyertakan field `quota`.403— Akun Anda tidak aktif. Hubungi administrator untuk mengaktifkan akun.403— Paket keanggotaan ini hanya mengizinkan permintaan API dari localhost (127.0.0.1 / ::1) atau server BillingHub. Berlaku jika paket layanan pemilik perangkat adalah paket anggota BillingHub.422— Body tidak valid (error validasi Laravel), perangkat tidak terhubung, penerima tidak valid, atau WhatsApp menolak pengiriman. Periksa pesan JSON (dan field errors jika validasi gagal).422— Kuota pesan bulanan habis; respons memuat objek quota yang sama dengan messages_remaining bernilai 0.503— Antrian pesan tidak tersedia (RabbitMQ/worker). Coba lagi sebentar.404/409— Gateway hulu: sesi WhatsApp belum termuat di Node atau belum terhubung. Restart wa-gateway (npm start) setelah pembaruan kode dan pastikan perangkat tampil terhubung di aplikasi.4xx/5xx lainnya— Kegagalan gateway atau server; field message menjelaskan masalah bila tersedia.
curl -X POST "https://hiwa.my.id/api/v1/messages" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d "{\"token_device\":\"YOUR_DEVICE_TOKEN_HERE\",\"to\":\"6281234567890\",\"message\":\"Hello\"}"
curl -X POST "https://hiwa.my.id/api/v1/messages" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d "{\"token_device\":\"YOUR_DEVICE_TOKEN_HERE\",\"to\":\"120363012345678901@g.us\",\"message\":\"Hello group\"}"
curl -X POST "https://hiwa.my.id/api/v1/messages" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d "{\"token_device\":\"YOUR_DEVICE_TOKEN_HERE\",\"to\":\"6281234567890\",\"type\":\"image\",\"media_url\":\"https://example.com/photo.jpg\",\"message\":\"Caption\"}"
curl -X POST "https://hiwa.my.id/api/v1/messages/9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d "{\"token_device\":\"YOUR_DEVICE_TOKEN_HERE\"}"