Quickstart
Satu API untuk mengirim dan menerima pesan WhatsApp dari aplikasi Anda. Kirim pesan pertama dalam lima menit. Base URL: https://wangsa.netbiz.id/api
- Reguler (
channel=regular) — nomor dihubungkan lewat pemindaian kode QR di dashboard. Mendukung semua tipe pesan termasuk poll, lokasi, dan kontak. - Business API (
channel=cloud) — nomor WhatsApp Business API. Mendukung teks, media, dan template.
channel? Wangsa memilihkan: nomor Business API bila ada yang aktif, selain itu jalur reguler. Integrasi lama tetap jalan tanpa perubahan.
1. Autentikasi
Ambil token dari dashboard (menu API Keys, atau token per-nomor), lalu sertakan di header Authorization. Token dikirim langsung — tanpa "Bearer".
2. Kirim pesan
Satu permintaan POST sudah cukup untuk mengirim pesan teks.
curl https://wangsa.netbiz.id/api/v1/send \ -H "Authorization: sk_live_•••" \ -d target="628123456789" \ -d message="Halo dari Wangsa 👋"
Respons mengembalikan status, jalur yang dipakai, dan sisa kuota Anda:
{ "status": true, "id": "msg_8KzQ1xR", "channel": "regular", "queued": true, "quota": 9981 }
Untuk memilih jalur secara eksplisit, sertakan channel. Di jalur Business API, pesan di luar jendela 24 jam harus berupa template:
curl https://wangsa.netbiz.id/api/v1/send \ -H "Authorization: sk_live_•••" \ -d channel="cloud" \ -d target="628123456789" \ -d template="konfirmasi_pesanan" \ -d language="id" \ -d vars="Budi,INV-2026-0912"
Bila Meta menolak (mis. di luar jendela 24 jam, atau template belum disetujui), respons berisi status:false dan reason apa adanya dari Meta.
3. Parameter utama
| Parameter | Tipe | Keterangan |
|---|---|---|
target wajib | string | Nomor tujuan (pisah koma untuk banyak) atau ID grup. Opsional bila pakai inboxid. |
message | string | Isi pesan teks; mendukung variabel {name}. Jadi caption bila ada url. |
url | string | Lampiran gambar/file/audio/video (paket media). |
type | string | text|image|document|video|audio|location|poll|sticker|contact|template (auto-deteksi bila kosong). |
channel | string | regular atau cloud. Kosong = dipilih otomatis. |
contactName / contactPhone | string | Kirim kontak (vCard). Jalur reguler. |
device | string | Jalur reguler: ID nomor; csv = rotator (acak per target). Tak perlu bila pakai token nomor. |
sender | string | Jalur Business API: phone_number_id atau nomor tampil pengirim. Kosong = nomor aktif pertama. |
template | string | Jalur Business API: nama template yang sudah disetujui Meta. |
language | string | Kode bahasa template, mis. id. Default id. |
vars | string | Isi variabel body template, urut, pisah koma. |
location | string | Kirim lokasi, format lat,lng. Jalur reguler. |
choices | string | Poll: 2–12 pilihan pisah koma. Jalur reguler. |
select | string | Poll: single / multiple. |
inboxid | int | Balas pesan masuk (target, jalur, & nomor pengirim otomatis dari inbox). |
countryCode | string | Normalisasi 0 depan; default 62; 0 = nonaktif. |
delay | string | Jeda acak antar pesan, mis. 2-5 detik. |
schedule | int | Unix timestamp untuk kirim terjadwal. |
4. Terima pesan (webhook)
Daftarkan URL webhook di dashboard (menu Webhook) untuk menerima pesan masuk dan pembaruan status. Wangsa mem-POST JSON ke URL Anda setiap kali ada kejadian. Satu akun boleh punya beberapa webhook; masing-masing bisa dibatasi ke event tertentu, atau ke satu nomor jalur reguler saja.
channel. Aplikasi Anda tidak perlu tahu lewat jalur mana pesan itu datang.Bentuk payload
Setiap kiriman berupa objek dengan event dan data:
{ "event": "message.incoming", "data": { "channel": "regular", "device": 12, "inboxid": 4821, "sender": "628123456789", "name": "Budi", "type": "text", "text": "Halo, masih ada stok?", "url": null, "location": null, "agent": "Siti", "agentid": 7, "division": "Penjualan", "timestamp": 1757049600 } }
Balas inboxid lewat POST /v1/send dengan parameter inboxid — nomor tujuan dan jalurnya diambil otomatis dari pesan itu.
Daftar event
| Event | Kapan dikirim | Field data |
|---|---|---|
message.incoming | Ada pesan masuk ke nomor Anda. | channel, device / sender_number, inboxid, sender, name, type, text, url, location, agent, agentid, division, timestamp |
message.status | Status pesan keluar berubah: sent, delivered, read, failed. | channel, device, id, messageId, target, status, waMessageId |
device.status | Nomor jalur reguler terhubung, terputus, atau dibatasi. | channel, device, status, reason |
poll.vote | Ada yang memilih pada poll yang Anda kirim. | channel, device, pollid, results, total |
device hanya terisi untuk nomor jalur reguler; pada jalur Business API pengirimnya ada di sender_number (Phone Number ID).
Menautkan nomor jalur reguler lewat API
Penautan nomor tidak harus lewat dasbor Wangsa. GET /v1/device/qr mengembalikan kode QR (atau kode pairing) sehingga Anda bisa menampilkannya di aplikasi sendiri. Endpoint ini sekaligus memicu penyambungan: bila nomor belum tersambung, Wangsa menugaskan worker dan meminta sesi baru.
Polanya polling. QR dibuat worker dan berumur ±90 detik, jadi panggilan pertama sering belum membawa QR — ulangi tiap 1–2 detik sampai qr terisi, lalu berhenti begitu connected menjadi true.
// belum tersambung, QR siap dipindai { "status": true, "connected": false, "qr": "2@AbC…", "pairing_code": null, "message": null } // QR masih dibuat — ulangi 1–2 detik lagi { "status": true, "connected": false, "qr": null, "pairing_code": null, "message": "QR sedang dibuat, coba lagi 1–2 detik." } // sudah tersambung — hentikan polling { "status": true, "connected": true, "phone": "628123456789" }
Bila nomor memakai penautan tanpa QR, isinya datang di pairing_code (bukan qr) untuk dimasukkan di menu Tautkan perangkat pada aplikasi WhatsApp. Nomor mana yang dimaksud ditentukan parameter device, atau otomatis bila Anda memakai token per-nomor.
Untuk meminta kode pairing 8 karakter alih-alih QR, tambahkan phone berisi nomor WhatsApp yang akan ditautkan (08… atau 628…), mis. GET /v1/device/qr?device=12&phone=628123456789. Sesi QR yang sedang berjalan dialihkan ke mode kode. Polling dengan phone yang sama tidak membuat kode baru; qr selalu null di mode ini dan message terisi selama kode belum terbit. Di WhatsApp pilih Tautkan dengan nomor telepon, lalu masukkan kodenya.
Nomor baru bisa dibuat lewat API juga: POST /v1/device dengan {"name": "…"} (maks. 60 karakter) membalas {"status": true, "device": {"id", "name", "status"}}. Wajib memakai API key akun — token per-nomor ditolak 403 — dan ditolak 422 bila kuota nomor paket sudah penuh.
device.status lewat webhook di bawah — sesi bisa putus kapan saja dan hanya event itu yang memberi tahu Anda.Nilai device.status
Event ini hanya ada di jalur reguler — nomor Business API tidak memakai sesi yang bisa putus. Inilah sinyal paling penting untuk dipantau: selama nomor tidak connected, pesan keluar lewat nomor itu tertahan di antrean.
status | Artinya | reason |
|---|---|---|
connected | Nomor tersambung dan siap mengirim. | — |
pairing | Menunggu kode QR dipindai atau kode pairing dimasukkan. | — |
disconnected | Sesi terputus. Antrean tertahan sampai tersambung lagi. | loggedOut (ditekan Logout dari HP — wajib pindai ulang) atau replaced (nomor dipakai di WhatsApp Web lain) |
banned | WhatsApp membatasi nomor ini. Butuh perhatian Anda, bukan sekadar sambung ulang. | Kode angka dari WhatsApp sebagai teks, mis. "403" atau "463" |
banned berbeda dari disconnected. disconnected biasanya pulih dengan menyambung ulang. banned berarti WhatsApp menjatuhkan pembatasan pada nomor itu — menyambung ulang berkali-kali justru memperburuk. Hentikan pengiriman ke nomor tersebut, periksa pola kirim Anda, lalu naikkan volumenya pelan-pelan.
{ "event": "device.status", "data": { "channel": "regular", "device": 12, "status": "banned", "reason": "463" } }
Memverifikasi tanda tangan
Setiap kiriman membawa header X-Wangsa-Event dan X-Wangsa-Signature. Tanda tangan adalah HMAC-SHA256 atas raw body memakai secret webhook Anda, berawalan sha256=. Bandingkan dengan perbandingan waktu-tetap, jangan dengan == biasa:
$raw = file_get_contents('php://input'); $expected = 'sha256=' . hash_hmac('sha256', $raw, $secret); if (! hash_equals($expected, $_SERVER['HTTP_X_WANGSA_SIGNATURE'] ?? '')) { http_response_code(401); exit; } $event = json_decode($raw, true); // … proses $event['data'], lalu balas 200 http_response_code(200);
import crypto from 'crypto'; app.post('/wangsa', express.raw({ type: 'application/json' }), (req, res) => { const expected = 'sha256=' + crypto.createHmac('sha256', SECRET).update(req.body).digest('hex'); const got = req.get('X-Wangsa-Signature') || ''; if (expected.length !== got.length || !crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(got))) { return res.sendStatus(401); } const { event, data } = JSON.parse(req.body); res.sendStatus(200); // balas dulu, proses belakangan });
- Hitung HMAC atas raw body, bukan hasil parse lalu di-encode ulang — susunan kuncinya bisa berubah dan tanda tangan jadi tidak cocok.
- Balas
200secepatnya lalu proses di belakang. Timeout kami 10 detik. - Selain
2xxdianggap gagal dan dicoba ulang sampai 6 kali dengan jeda 10 dtk, 30 dtk, 1, 2, lalu 5 menit. Buat penanganan Anda idempotent — pakaiinboxidatauwaMessageIdsebagai kunci anti-duplikat. - Riwayat tiap percobaan beserta kode HTTP-nya bisa dilihat di dashboard, lengkap dengan tombol kirim ulang yang gagal.
5. CS multi-agen
Bila akun Anda punya agen, setiap pesan masuk otomatis ditugaskan ke agen aktif dengan chat terbuka paling sedikit — berlaku untuk kedua jalur. Agen membalas dari portal terpisah di /agent dengan akun mereka sendiri, dan hanya melihat chat yang ditugaskan kepadanya. Jumlah agen dibatasi kuota seat pada paket Anda.
Daftar agen & bebannya
{ "status": true, "agents": [ { "id": 7, "name": "Siti", "email": "siti@acme.id", "active": true, "division": "Penjualan", "division_id": 2, "open_chats": 3 } ] }
open_chats = jumlah chat yang ditugaskan ke agen itu dan belum dibalas. Inilah angka yang dipakai saat memilih agen paling senggang.
Memindahkan chat ke agen
Pakai inboxid dari event message.incoming. Kosongkan agent agar Wangsa memilihkan agen paling senggang; isi division untuk membatasi pilihan pada satu divisi.
curl https://wangsa.netbiz.id/api/v1/agent/assign \ -H "Authorization: sk_live_•••" \ -d inboxid="4821" \ -d agent="7"
{ "status": true, "inboxid": 4821, "agent": { "id": 7, "name": "Siti", "division": "Penjualan" } }
Ditolak 422 bila agennya nonaktif, tidak ditemukan, atau tidak ada agen aktif sama sekali. Membalas chat tetap lewat POST /v1/send dengan inboxid.
Webhook masuk dari Meta (jalur Business API)
Ini berbeda dari webhook di atas dan tidak perlu Anda tangani — alamat ini dipasang di App Meta Anda supaya pesan masuk sampai ke Wangsa. Saat menghubungkan nomor lewat konfigurasi manual, dashboard menampilkan Callback URL https://wangsa.netbiz.id/api/meta/webhook/{slug} berikut Verify Token khusus koneksi Anda; salin keduanya ke WhatsApp → Configuration di App Meta, lalu berlangganan field messages. Sesudah itu pesan masuk mengalir ke Inbox dan diteruskan ke webhook Anda sendiri sebagai message.incoming.
Daftar endpoint
| Method | Endpoint | Fungsi |
|---|---|---|
POST | /v1/send | Kirim pesan (teks/media/template/lokasi/poll) |
GET | /v1/send?... | Kirim via URL (token boleh di query ?token=) |
POST | /v1/send (inboxid) | Balas pesan masuk via API |
GET | /v1/device | Daftar nomor jalur reguler & statusnya |
POST | /v1/device | Tambah nomor jalur reguler (name; butuh API key akun, ikut kuota nomor paket) |
GET | /v1/device/profile | Profil nomor + sisa kuota |
GET | /v1/device/qr | Kode QR / pairing untuk menautkan nomor jalur reguler (phone → kode pairing) |
POST | /v1/device/disconnect | Putuskan nomor jalur reguler |
GET | /v1/group/list | Daftar grup WhatsApp pada nomor jalur reguler |
GET | /v1/agents | Daftar agen CS + beban chat |
POST | /v1/agent/assign | Pindahkan chat ke agen |
POST | /v1/typing | Indikator mengetik ke target |
POST | /v1/order | Beli / perpanjang paket |
Webhook bisa dibatasi per-device di dashboard (kosongkan = semua device).
Integrasi — Bahasa & Library
Semua integrasi pada dasarnya sama: kirim POST ke /v1/send dengan header Authorization berisi token Anda.
https://wangsa.netbiz.id/api (SaaS). Bila self-host, gunakan https://domain-anda.com/api/v1/send.<?php
$ch = curl_init('https://wangsa.netbiz.id/api/v1/send');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: TOKEN_ANDA'],
CURLOPT_POSTFIELDS => [
'target' => '628123456789',
'message' => 'Halo dari Wangsa 👋',
],
]);
echo curl_exec($ch);await fetch('https://wangsa.netbiz.id/api/v1/send', {
method: 'POST',
headers: { 'Authorization': 'TOKEN_ANDA', 'Content-Type': 'application/json' },
body: JSON.stringify({ target: '628123456789', message: 'Halo dari Wangsa' }),
});use Illuminate\Support\Facades\Http;
Http::withHeaders(['Authorization' => 'TOKEN_ANDA'])
->post('https://wangsa.netbiz.id/api/v1/send', [
'target' => '628123456789',
'message' => 'Halo dari Wangsa',
]);Integrasi — Platform & Plugin
Hubungkan form & toko online ke WhatsApp. Ganti TOKEN_ANDA dan nama field sesuai milik Anda.
Contact Form 7 (WordPress)
Tempel di functions.php tema/child-theme. Kirim WA tiap form terkirim.
add_action('wpcf7_mail_sent', function ($cf7) {
$d = WPCF7_Submission::get_instance()->get_posted_data();
wp_remote_post('https://wangsa.netbiz.id/api/v1/send', [
'headers' => ['Authorization' => 'TOKEN_ANDA'],
'body' => [
'target' => $d['your-phone'], // nama field telp
'message' => "Halo {$d['your-name']}, pesan Anda kami terima.",
],
]);
});WooCommerce — notifikasi order
Kirim WA otomatis saat status order berubah (mis. processing).
add_action('woocommerce_order_status_processing', function ($order_id) {
$o = wc_get_order($order_id);
wp_remote_post('https://wangsa.netbiz.id/api/v1/send', [
'headers' => ['Authorization' => 'TOKEN_ANDA'],
'body' => [
'target' => $o->get_billing_phone(),
'message' => "Terima kasih! Pesanan #{$order_id} sedang diproses. Total: " . $o->get_total(),
],
]);
});Elementor Forms
Tempel snippet (Elementor Pro) — terpicu tiap submit form.
add_action('elementor_pro/forms/new_record', function ($record, $handler) {
$f = $record->get('fields');
wp_remote_post('https://wangsa.netbiz.id/api/v1/send', [
'headers' => ['Authorization' => 'TOKEN_ANDA'],
'body' => ['target' => $f['phone']['value'], 'message' => 'Halo ' . $f['name']['value']],
]);
}, 10, 2);Formidable Forms
add_action('frm_after_create_entry', function ($entry_id) {
$phone = FrmEntryMeta::get_entry_meta_by_field($entry_id, 25); // ID field telp
$name = FrmEntryMeta::get_entry_meta_by_field($entry_id, 26); // ID field nama
wp_remote_post('https://wangsa.netbiz.id/api/v1/send', [
'headers' => ['Authorization' => 'TOKEN_ANDA'],
'body' => ['target' => $phone, 'message' => "Halo $name"],
]);
}, 30, 1);Google Form (Apps Script)
Extensions → Apps Script, tempel kode, lalu buat trigger On form submit.
function onFormSubmit(e) {
var v = e.values; // [waktu, nama, no_hp, ...] sesuai urutan kolom
UrlFetchApp.fetch('https://wangsa.netbiz.id/api/v1/send', {
method: 'post',
headers: { Authorization: 'TOKEN_ANDA' },
payload: { target: v[2], message: 'Halo ' + v[1] + ', terima kasih sudah mengisi form.' },
});
}No-code (Zapier / n8n / Make)
Tambahkan langkah HTTP Request: method POST, URL https://wangsa.netbiz.id/api/v1/send, header Authorization: TOKEN_ANDA, body target & message. Selesai.
delay (mis. 3-8) saat blast dari plugin untuk mengatur laju, dan variabel {name} untuk personalisasi.