Dokumentasi API

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

Dua jalur pengiriman. Setiap nomor di akun Anda berjalan di salah satu jalur, dan API-nya sama:
  • 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.
Tidak menyebut channel? Wangsa memilihkan: nomor Business API bila ada yang aktif, selain itu jalur reguler. Integrasi lama tetap jalan tanpa perubahan.
Kepatuhan WhatsApp. Layanan tunduk pada WhatsApp Business Messaging Policy. Kirim hanya ke penerima yang telah opt-in. Khusus jalur Business API, pesan bebas (free-form) hanya diizinkan dalam 24-jam customer service window sejak balasan terakhir pengguna; di luar jendela itu wajib memakai template yang telah disetujui Meta. Dilarang spam, konten menyesatkan, dan barang/jasa terlarang.

1. Autentikasi

Ambil token dari dashboard (menu API Keys, atau token per-nomor), lalu sertakan di header Authorization. Token dikirim langsung — tanpa "Bearer".

Punya beberapa nomor jalur reguler? Pisahkan beberapa token dengan koma untuk merotasi pengirim secara acak.

2. Kirim pesan

Satu permintaan POST sudah cukup untuk mengirim pesan teks.

cURL
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:

200 OK
{
  "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 — 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

ParameterTipeKeterangan
target wajibstringNomor tujuan (pisah koma untuk banyak) atau ID grup. Opsional bila pakai inboxid.
messagestringIsi pesan teks; mendukung variabel {name}. Jadi caption bila ada url.
urlstringLampiran gambar/file/audio/video (paket media).
typestringtext|image|document|video|audio|location|poll|sticker|contact|template (auto-deteksi bila kosong).
channelstringregular atau cloud. Kosong = dipilih otomatis.
contactName / contactPhonestringKirim kontak (vCard). Jalur reguler.
devicestringJalur reguler: ID nomor; csv = rotator (acak per target). Tak perlu bila pakai token nomor.
senderstringJalur Business API: phone_number_id atau nomor tampil pengirim. Kosong = nomor aktif pertama.
templatestringJalur Business API: nama template yang sudah disetujui Meta.
languagestringKode bahasa template, mis. id. Default id.
varsstringIsi variabel body template, urut, pisah koma.
locationstringKirim lokasi, format lat,lng. Jalur reguler.
choicesstringPoll: 2–12 pilihan pisah koma. Jalur reguler.
selectstringPoll: single / multiple.
inboxidintBalas pesan masuk (target, jalur, & nomor pengirim otomatis dari inbox).
countryCodestringNormalisasi 0 depan; default 62; 0 = nonaktif.
delaystringJeda acak antar pesan, mis. 2-5 detik.
scheduleintUnix 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.

Kedua jalur mengirim event yang sama. Bentuk payload identik untuk nomor jalur reguler maupun WhatsApp Business API — pembedanya hanya field channel. Aplikasi Anda tidak perlu tahu lewat jalur mana pesan itu datang.

Bentuk payload

Setiap kiriman berupa objek dengan event dan data:

POST ke URL Anda
{
  "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

EventKapan dikirimField data
message.incomingAda pesan masuk ke nomor Anda.channel, device / sender_number, inboxid, sender, name, type, text, url, location, agent, agentid, division, timestamp
message.statusStatus pesan keluar berubah: sent, delivered, read, failed.channel, device, id, messageId, target, status, waMessageId
device.statusNomor jalur reguler terhubung, terputus, atau dibatasi.channel, device, status, reason
poll.voteAda 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.

GET /v1/device/qr?device=12
// 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.

Setelah tersambung, pantau 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.

statusArtinyareason
connectedNomor tersambung dan siap mengirim.—
pairingMenunggu kode QR dipindai atau kode pairing dimasukkan.—
disconnectedSesi terputus. Antrean tertahan sampai tersambung lagi.loggedOut (ditekan Logout dari HP — wajib pindai ulang) atau replaced (nomor dipakai di WhatsApp Web lain)
bannedWhatsApp membatasi nomor ini. Butuh perhatian Anda, bukan sekadar sambung ulang.Kode angka dari WhatsApp sebagai teks, mis. "403" atau "463"
Tangani 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.
device.status
{
  "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:

PHP
$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);
Node.js (Express)
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
});
Yang harus diperhatikan.
  • Hitung HMAC atas raw body, bukan hasil parse lalu di-encode ulang — susunan kuncinya bisa berubah dan tanda tangan jadi tidak cocok.
  • Balas 200 secepatnya lalu proses di belakang. Timeout kami 10 detik.
  • Selain 2xx dianggap gagal dan dicoba ulang sampai 6 kali dengan jeda 10 dtk, 30 dtk, 1, 2, lalu 5 menit. Buat penanganan Anda idempotent — pakai inboxid atau waMessageId sebagai 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.

Agen dan divisi dibuat dari dashboard (menu Team), bukan lewat API — keduanya menyangkut kuota seat dan kata sandi. Yang tersedia lewat API adalah melihat beban tiap agen dan memindahkan chat, agar Wangsa bisa mengikuti pembagian kerja yang sudah diatur sistem lain (helpdesk, CRM, jadwal shift).

Daftar agen & bebannya

GET /v1/agents
{
  "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
curl https://wangsa.netbiz.id/api/v1/agent/assign \
  -H "Authorization: sk_live_•••" \
  -d inboxid="4821" \
  -d agent="7"
200 OK
{
  "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

MethodEndpointFungsi
POST/v1/sendKirim 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/deviceDaftar nomor jalur reguler & statusnya
POST/v1/deviceTambah nomor jalur reguler (name; butuh API key akun, ikut kuota nomor paket)
GET/v1/device/profileProfil nomor + sisa kuota
GET/v1/device/qrKode QR / pairing untuk menautkan nomor jalur reguler (phone → kode pairing)
POST/v1/device/disconnectPutuskan nomor jalur reguler
GET/v1/group/listDaftar grup WhatsApp pada nomor jalur reguler
GET/v1/agentsDaftar agen CS + beban chat
POST/v1/agent/assignPindahkan chat ke agen
POST/v1/typingIndikator mengetik ke target
POST/v1/orderBeli / 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.

Base URL: https://wangsa.netbiz.id/api (SaaS). Bila self-host, gunakan https://domain-anda.com/api/v1/send.
PHP (cURL)
<?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);
Node.js
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' }),
});
Laravel (HTTP)
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.

functions.php
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).

functions.php
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.

functions.php
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

functions.php
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.

Apps Script
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.

Tips: gunakan parameter delay (mis. 3-8) saat blast dari plugin untuk mengatur laju, dan variabel {name} untuk personalisasi.

Dapatkan token & mulai