Mulai cepat
- Daftar dan verifikasi email.
- Menu Device → Tambah device → scan QR dari WhatsApp di HP.
- Menu API Keys → Buat key. Simpan, key hanya tampil sekali.
- Kirim pesan:
curl -X POST https://www.watsapbro.com/api/v1/messages/text \
-H "Authorization: Bearer wsb_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"to":"08123456789","message":"Halo dari WatsapBro"}'
Base URL: https://www.watsapbro.com/api/v1. Semua request dan response memakai JSON.
Autentikasi
Kirim API key di header Authorization: Bearer <API_KEY> (atau X-Api-Key: <API_KEY>). Rate limit: 60 request/menit per API key.
Format response selalu:
{ "success": true, "message": "...", "data": { ... } }
Format nomor tujuan (to)
| Input | Keterangan |
|---|---|
08123456789 | Otomatis jadi 628123456789 |
628123456789 | Format internasional tanpa + |
120363xxxx@g.us | ID grup WhatsApp |
POST/messages/text
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
to | string | Nomor tujuan | |
message | string | Maks 4096 karakter. Mendukung *tebal* _miring_ ~coret~ | |
device_id | int | Device pengirim. Kosong = device terhubung pertama | |
typing_time | int (ms) | Tampilkan "sedang mengetik" sebelum kirim, 0–10000 |
{
"to": "08123456789",
"message": "*Pembayaran diterima*\nInvoice INV-001 sebesar Rp150.000 sudah lunas.",
"typing_time": 1500
}
Response 200:
{
"success": true,
"message": "Pesan terkirim.",
"quota_remaining": 1874,
"data": { "log_id": 1024, "message_id": "3EB0B430A2B52B67D0", "device_id": 3, "to": "08123456789" }
}
quota_remaining = sisa kuota bulan ini, null kalau paket unlimited.
POST/messages/image
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
to | string | ||
image_url | url | URL publik JPG/PNG | |
caption | string | Maks 1024 karakter | |
device_id, typing_time | Sama seperti teks |
{ "to": "08123456789", "image_url": "https://cdn.toko.com/promo.jpg", "caption": "Promo minggu ini" }
POST/messages/document
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
to | string | ||
document_url | url | URL publik file | |
filename | string | Nama file yang tampil di WhatsApp | |
mimetype | string | Default application/pdf | |
caption | string |
{
"to": "08123456789",
"document_url": "https://app.toko.com/invoice/INV-001.pdf",
"filename": "INV-001.pdf",
"caption": "Invoice Oktober"
}
POST/numbers/check
Cek apakah nomor terdaftar di WhatsApp sebelum mengirim.
{ "phone": "08123456789", "device_id": 3 }
GET/devices
Daftar device milik Anda beserta status. GET/devices/{id} untuk satu device.
{
"success": true,
"data": [
{ "id": 3, "name": "CS Toko", "phone": "628123456789", "status": "connected", "connected_at": "2026-10-17T09:12:00+07:00" }
]
}
| status | Arti |
|---|---|
connected | Siap kirim |
connecting | Sedang menyambung ulang, coba lagi beberapa detik |
qr_ready | Perlu scan QR ulang di dashboard |
disconnected | Terputus, sistem akan reconnect otomatis |
GET/me
Info akun: paket, tanggal berakhir, limit device, dan pemakaian kuota bulan ini. Kuota dihitung dari pesan yang berhasil terkirim (API, broadcast, dan pesan tes) dan direset tiap tanggal 1.
{
"success": true,
"data": {
"name": "Toko Budi",
"email": "budi@toko.com",
"plan": "Starter",
"plan_expires_at": "2026-11-17T10:00:00+07:00",
"device_limit": 1,
"devices": 1,
"quota_monthly": 2000,
"quota_used": 126,
"quota_remaining": 1874
}
}
Webhook pesan masuk
Isi URL webhook di halaman detail device (menu Device). WatsapBro mengirim POST JSON ke URL tersebut setiap ada pesan masuk ke nomor itu, dan saat status device berubah. Pesan yang Anda kirim sendiri tidak diteruskan.
| Header | Isi |
|---|---|
X-Webhook-Event | message, device.status, atau test |
X-Webhook-Delivery | UUID unik per event. Simpan untuk mencegah proses ganda saat retry. |
X-Webhook-Signature | sha256= + HMAC-SHA256 dari raw body memakai signing secret device |
Contoh body event message:
{
"event": "message",
"delivery_id": "6f1c2a0e-6c1e-4b0a-9a51-2d0f0b8e7c11",
"device": { "id": 3, "name": "CS Toko", "phone": "628123456789" },
"data": {
"id": "3EB0C767D26A8B4E1F",
"from": "6281298765432@c.us",
"text": "Halo, pesanan saya sudah dikirim?",
"timestamp": 1760668200
},
"timestamp": "2026-10-17T10:30:00+07:00"
}
Event device.status berisi data.status dan data.previous (nilai sama dengan tabel status device di atas).
Balas HTTP 2xx dalam 10 detik. Kalau URL Anda timeout, membalas 5xx, atau 429, event dikirim ulang hingga 4 kali (10 detik, 1 menit, 5 menit, 15 menit). Balasan 4xx lain dianggap ditolak dan tidak dikirim ulang. Proses berat sebaiknya dimasukkan ke queue di aplikasi Anda.
Verifikasi signature
// Laravel
$raw = $request->getContent();
$expected = 'sha256=' . hash_hmac('sha256', $raw, env('WEBHOOK_SECRET'));
abort_unless(hash_equals($expected, (string) $request->header('X-Webhook-Signature')), 401);
$event = $request->json('event');
if ($event === 'message') {
$from = $request->json('data.from'); // 6281298765432@c.us
$text = $request->json('data.text');
}
// Go
func verify(body []byte, sig, secret string) bool {
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(body)
expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(expected), []byte(sig))
}
// Node.js (Express: pakai express.raw({ type: 'application/json' }))
const crypto = require('crypto');
const expected = 'sha256=' + crypto.createHmac('sha256', process.env.WEBHOOK_SECRET).update(req.body).digest('hex');
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(req.get('X-Webhook-Signature') || ''));
GET/conversations
Daftar percakapan inbox (urut terbaru). Query opsional: device_id, unread=1, needs_human=1, per_page (maks 100), page.
{
"success": true,
"data": [
{ "id": 41, "device_id": 3, "chat_id": "6281298765432@s.whatsapp.net", "name": "Sari", "phone": "6281298765432",
"is_group": false, "unread": 2, "needs_human": false, "ai": "on",
"last_message": "Masih ada stok ukuran M?", "last_message_at": "2026-10-18T09:12:00+07:00" }
],
"meta": { "page": 1, "per_page": 30, "total": 128 }
}
GET/conversations/{id}/messages
Pesan dalam percakapan, urut lama ke baru. Query: limit (maks 100), before_id untuk halaman sebelumnya. Field source: contact (dari pelanggan), ai, autoreply, api, broadcast, dashboard, phone.
AI & auto reply
Balasan otomatis diatur dari dashboard, tidak perlu kode: Auto Reply (kata kunci) diperiksa dulu, lalu AI Agent yang dipasang di device. AI memakai API key milik Anda (OpenAI, Anthropic, Gemini, Groq, DeepSeek, OpenRouter, atau endpoint OpenAI-compatible) dan membaca Knowledge Base Anda. Balasan otomatis tercatat di inbox (bisa dibaca lewat /conversations) dan terhitung kuota pesan.
Otomasi berhenti sementara untuk sebuah chat ketika Anda membalas manual dari inbox atau dari HP, dan ketika pelanggan meminta CS manusia (handover).
Kode error
| HTTP | Arti | Retry? |
|---|---|---|
| 401 | API key tidak ada / tidak valid | Tidak |
| 402 | Paket tidak aktif atau device melebihi limit paket | Tidak, perpanjang paket |
| 403 | Email akun belum diverifikasi | Tidak |
| 404 | Device tidak ditemukan / tidak ada device terhubung | Tidak |
| 409 | Device belum terhubung | Ya, setelah device connected |
| 422 | Validasi gagal atau nomor tidak valid | Tidak |
| 429 | Rate limit terlampaui, atau kuota pesan bulan ini habis (lihat message) | Rate limit: ya, dengan jeda. Kuota: tidak, upgrade paket |
| 502 / 503 | Gateway WhatsApp sedang tidak tersedia | Ya, backoff 1s, 4s, 9s |
Contoh kode
Laravel
use Illuminate\Support\Facades\Http;
$res = Http::withToken(env('API_KEY'))
->retry(3, 1000, fn ($e) => $e instanceof \Illuminate\Http\Client\ConnectionException
|| in_array(optional($e->response)->status(), [409, 429, 502, 503]))
->post('https://www.watsapbro.com/api/v1/messages/text', [
'to' => '08123456789',
'message' => 'Kode OTP Anda: 482910',
]);
if (! $res->json('success')) {
logger()->error('WA gagal', $res->json());
}
Go
body, _ := json.Marshal(map[string]any{"to": "08123456789", "message": "Halo dari Go"})
req, _ := http.NewRequest("POST", "https://www.watsapbro.com/api/v1/messages/text", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("API_KEY"))
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
Node.js
const res = await fetch("https://www.watsapbro.com/api/v1/messages/text", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ to: "08123456789", message: "Halo dari Node" }),
});
const json = await res.json();
PHP native
$ch = curl_init('https://www.watsapbro.com/api/v1/messages/text');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('API_KEY'), 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode(['to' => '08123456789', 'message' => 'Halo']),
]);
$result = json_decode(curl_exec($ch), true);
Tips supaya nomor tidak diblokir
- Untuk kirim massal, pakai menu Broadcast (upload CSV, jeda acak otomatis) daripada loop API tanpa jeda.
- Pakai nomor khusus (sebaiknya WhatsApp Business), bukan nomor pribadi.
- Kirim ke orang yang memang kenal Anda: pelanggan, member, user aplikasi.
- Untuk banyak penerima, beri jeda minimal 3–5 detik antar pesan dan pakai
typing_time. - Hindari pesan identik ke ratusan nomor sekaligus; personalisasi dengan nama.
- Buka WhatsApp di HP utama minimal sekali tiap 2 minggu.
- Kirim lewat queue di aplikasi Anda, jangan di request user secara langsung.