Dokumentasi API
v1Referensi lengkap REST API MAUBLAST: session, kirim pesan, blast, webhook, dan integrasi.
https://maublast.net/api/v1
Buat token
Pengantar
MAUBLAST REST API memungkinkan Anda mengontrol session WhatsApp secara programatik: kirim pesan (teks, media, interaktif), kelola kontak, terima event real-time lewat webhook, dan eksekusi blast massal.
Semua request dikirim sebagai HTTP(S) dengan body JSON dan auth Bearer token.
Base URL
Autentikasi
Setiap request wajib menyertakan header Authorization: Bearer YOUR_TOKEN. Buat token di halaman API Key.
curl https://maublast.net/api/v1/sessions \
-H "Authorization: Bearer YOUR_TOKEN"
Error & status code
| Status | Arti |
|---|---|
200 | Sukses. Response JSON di body. |
202 | Accepted — pesan masuk antrian (async). |
400 | Bad request — payload invalid / field required hilang. |
401 | Unauthorized — token hilang / salah / expired. |
403 | Forbidden — resource bukan milik Anda. |
404 | Not found — session ID / resource tidak ada. |
409 | Conflict — session sudah dalam state itu (mis: connect saat sudah connected). |
422 | Unprocessable — session belum logged_in saat coba kirim pesan. |
429 | Too Many Requests — rate limit. Tunggu dan retry dengan exponential backoff. |
500 | Server error. |
Response error format:
{
"error": "Session not connected",
"code": "SESSION_NOT_READY"
}
Rate limit
60 request/menit per token. Header response memuat X-RateLimit-Remaining dan X-RateLimit-Reset. Untuk volume tinggi, aktifkan Rotator dengan beberapa session.
Sessions
Session mewakili 1 nomor WhatsApp yang terhubung. Satu akun bisa punya banyak session (untuk blast pakai rotator, multi-brand, dll).
List semua session Anda.
curl https://maublast.net/api/v1/sessions \
-H "Authorization: Bearer YOUR_TOKEN"Response:
[
{
"session_id": "sess_abc123",
"name": "Marketing Utama",
"status": "logged_in",
"phone_number": "628123456789",
"push_name": "MAUBLAST",
"created_at": "2026-04-20T08:00:00Z"
}
]
Buat session baru. Setelah dibuat, lanjut panggil /connect untuk mulai pairing.
| Field | Tipe | Wajib | Deskripsi |
|---|---|---|---|
name | string | ya | Nama session (untuk identifikasi). |
device | object | tidak | Identitas perangkat di "Perangkat tertaut" WhatsApp. Hanya berlaku saat first pair. |
device.os | string | tidak | OS label, contoh: Windows, Mac OS X, Ubuntu. Default: Windows. |
device.platform | string | tidak | Salah satu: desktop (default), uwp, chrome, firefox, edge, safari, opera, ipad, ios_phone, android_phone, android_tablet. |
curl -X POST https://maublast.net/api/v1/sessions \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Marketing Utama", "device": {"os": "Windows", "platform": "desktop"}}'Cek status koneksi. Nilai status: disconnected, waiting_for_qr, waiting_for_pairing_code, logged_in.
curl https://maublast.net/api/v1/sessions/SESSION_ID/status \
-H "Authorization: Bearer YOUR_TOKEN"Ambil QR code terkini (saat status waiting_for_qr). QR auto-rotate tiap ~20 detik — polling tiap 2-3s.
{ "qr_codes": ["2@abc...", "2@def..."] }
Generate kode pairing 8 digit (alternatif scan QR). Field device opsional (sama seperti di create session).
curl -X POST https://maublast.net/api/v1/sessions/SESSION_ID/pair \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"phone": "628123456789", "device": {"os": "Windows", "platform": "desktop"}}'Mulai proses pairing. Setelah ini, poll /qr atau pakai /pair. Body opsional untuk override identitas perangkat.
curl -X POST https://maublast.net/api/v1/sessions/SESSION_ID/connect \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"device": {"os": "Windows", "platform": "desktop"}}'Putus koneksi. Session tetap tersimpan, tinggal /connect lagi kalau mau aktifin ulang.
Hapus session permanen (logout dari WA + hapus record).
Kirim pesan
Semua endpoint kirim berbentuk POST /sessions/{id}/messages/<tipe>. Field to wajib: nomor target format internasional tanpa + (contoh: 628123456789) atau JID lengkap (628123456789@s.whatsapp.net, untuk grup 12345@g.us).
Kirim pesan teks. Support formatting: *bold*, _italic_, ~strike~, ```mono```.
| Field | Tipe | Wajib | Deskripsi |
|---|---|---|---|
to | string | ya | Nomor tujuan. |
text | string | ya | Isi pesan (max ~4096 char). |
curl -X POST https://maublast.net/api/v1/sessions/SESSION_ID/messages/text \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": "628123456789",
"text": "Halo, ini pesan dari API."
}'| Field | Tipe | Wajib | Deskripsi |
|---|---|---|---|
to | string | ya | Nomor tujuan. |
image.url | string | ya* | URL publik gambar (JPG/PNG/WebP, max 5MB). |
image.base64 | string | ya* | Alternatif: base64 data. |
caption | string | tidak | Caption bawah gambar. |
{
"to": "628123456789",
"image": { "url": "https://cdn.example.com/promo.jpg" },
"caption": "Promo spesial weekend"
}Struktur sama dengan image, field video.url atau video.base64. MP4 direkomendasikan, max 16MB.
{
"to": "628123456789",
"video": { "url": "https://cdn.example.com/demo.mp4" },
"caption": "Demo produk"
}
Kirim audio/voice note (format OGG, MP3, AAC). Set ptt: true untuk voice note.
{
"to": "628123456789",
"audio": { "url": "https://cdn.example.com/voice.ogg" },
"ptt": true
}
| Field | Tipe | Wajib | Deskripsi |
|---|---|---|---|
document.url | string | ya | URL file (PDF, DOCX, XLSX, dll — max 100MB). |
filename | string | ya | Nama file yang tampil (mis: invoice.pdf). |
caption | string | tidak | Caption. |
{
"to": "628123456789",
"document": { "url": "https://cdn.example.com/invoice-123.pdf" },
"filename": "invoice-123.pdf",
"caption": "Invoice order #123"
}
{
"to": "628123456789",
"latitude": -6.2088,
"longitude": 106.8456,
"name": "Kantor Pusat",
"address": "Jl. Sudirman No. 1, Jakarta"
}
{
"to": "628123456789",
"contact": {
"display_name": "Customer Service",
"phones": [
{ "number": "628555666777", "phone_type": "CELL" }
]
}
}
Max 12 opsi. selectable_count: 0 = unlimited (multi-select).
{
"to": "628123456789",
"name": "Produk mana yang paling menarik?",
"options": ["Produk A", "Produk B", "Produk C"],
"selectable_count": 1
}
Single tombol Call-To-Action yang membuka URL di browser. Lebih sederhana dari /messages/interactive karena tidak perlu construct button_params_json manual.
{
"to": "628123456789",
"body_text": "Lihat katalog terbaru kami",
"footer_text": "Promo bulan ini",
"display_text": "Buka katalog",
"url": "https://example.com/katalog",
"merchant_url": "https://example.com"
}
1–3 tombol reply cepat. Modern native-flow — pengganti /messages/buttons legacy, lebih reliable di iOS & WA versi baru. id dikirim balik ke webhook saat tombol ditekan.
{
"to": "628123456789",
"body_text": "Ada yang bisa kami bantu?",
"footer_text": "Reply kapan saja",
"buttons": [
{ "id": "support", "display_text": "Hubungi support" },
{ "id": "billing", "display_text": "Tagihan" },
{ "id": "feedback", "display_text": "Beri masukan" }
]
}
Menu dropdown multi-section.
{
"to": "628123456789",
"title": "Menu utama",
"description": "Silakan pilih layanan",
"footer": "MAUBLAST",
"button_text": "Lihat menu",
"sections": [
{
"title": "Layanan",
"rows": [
{ "row_id": "order", "title": "Pesan produk", "description": "Order & bayar" },
{ "row_id": "track", "title": "Cek status", "description": "Status pesanan" }
]
}
]
}
Blast massal
Blast dikerjakan di sisi server. Anda cukup POST sekali ke /blast dengan daftar nomor + pesan + pengaturan, server otomatis: antrikan, throttle dengan jitter, typing simulation, batch pause, rotasi pesan, skip jam malam. Anda bisa tutup koneksi — kampanye tetap jalan.
Polling GET /blast/{id} untuk dapat progress real-time, atau pakai webhook message.ack untuk tracking per-pesan.
queued → running → completedBisa juga:
paused (via /pause), cancelled (via DELETE), failed (fatal error).
Buat dan antrikan kampanye. Response 202 dengan ID kampanye.
| Field | Tipe | Wajib | Deskripsi |
|---|---|---|---|
message | string | ya | Isi pesan. Support {{nama}}, {{phone}}, {{tanggal}}, {{jam}}, dan variasi inline {a|b|c}. |
recipients | array | ya | Array of {"phone": "...", "name": "..."}. Max 10.000. Duplikat auto-skip. |
name | string | tidak | Nama kampanye untuk tracking. |
session_id | string/int | tidak* | ID session yang dipakai kirim. * Wajib kalau tidak pakai rotator_group_id. |
rotator_group_id | int | tidak* | ID grup rotator (prioritas di atas session_id). |
mode | string | tidak | fast / balanced (default) / human / safe. Set preset delay/typing/batch. |
delay_min, delay_max | int (detik) | tidak | Override jeda jitter. Default tergantung mode. |
typing | bool | tidak | Typing simulation 1-3 detik sebelum tiap pesan. |
batch | bool | tidak | Enable batch pause. |
batch_size, batch_pause | int | tidak | Ukuran batch dan durasi pause (detik). |
shuffle | bool | tidak | Acak urutan penerima (default: true). |
skip_night | bool | tidak | Pause kirim antara 22:00-06:00 WIB. |
variations | string[] | tidak | Array template alternatif. Kalau di-set, message jadi fallback saja. |
fake_reply | object | tidak | Bungkus pesan seolah membalas pesan dummy. Lihat Fake Reply di bawah. |
curl -X POST https://maublast.net/api/v1/blast \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Kampanye Promo Lebaran",
"message": "Halo {{nama}}, ada {diskon 20%|promo spesial} buat kamu!",
"mode": "balanced",
"rotator_group_id": 3,
"recipients": [
{"phone": "628111111111", "name": "Budi"},
{"phone": "628222222222", "name": "Ani"},
{"phone": "628333333333", "name": "Charlie"}
],
"skip_night": true
}'Response (202):
{
"id": 47,
"name": "Kampanye Promo Lebaran",
"status": "queued",
"total": 3,
"sent": 0,
"ok": 0,
"failed": 0,
"progress_pct": 0,
"mode": "balanced",
"created_at": "2026-04-22T10:00:00Z"
}
Cek progress kampanye. Poll tiap 2-5 detik untuk update real-time.
curl https://maublast.net/api/v1/blast/47 \
-H "Authorization: Bearer YOUR_TOKEN"{
"id": 47,
"status": "running",
"total": 3,
"sent": 2,
"ok": 2,
"failed": 0,
"progress_pct": 66,
"last_error": null,
"started_at": "2026-04-22T10:00:04Z",
"completed_at": null
}
List kampanye Anda. Query: limit (default 20, max 100), status (filter).
curl "https://maublast.net/api/v1/blast?status=running&limit=10" \
-H "Authorization: Bearer YOUR_TOKEN"Pause, resume, cancel
Hentikan sementara kampanye yang running/queued. Progress tersimpan.
Lanjutkan kampanye yang paused dari index terakhir.
Batalkan kampanye yang sedang jalan (ubah status ke cancelled). Kalau kampanye sudah completed/cancelled/failed, ini akan hapus record permanen.
Mode preset
Shortcut setting siap pakai. Anda bisa override field individual kalau perlu.
| Mode | Jeda (detik) | Typing | Batch | Kapasitas | Cocok untuk |
|---|---|---|---|---|---|
fast | 1-3 random | off | off | ~1200/jam | Test internal, nomor warm & sehat. |
balanced default | 3-8 random | on | off | ~600/jam | Blast harian, nomor normal. |
human | 5-20 random | on | 30 / 90s | ~250/jam | Nomor baru atau yang pernah kena warning. |
safe | 10-30 random | on | 20 / 180s | ~120/jam | Warm up nomor fresh, campaign sensitif. |
Fake reply (anti-ban)
Bungkus tiap pesan blast seolah-olah balasan ke pesan dummy sebelumnya (produk listing, order, lokasi, video review, dll). WhatsApp melihatnya sebagai conversational context — mengurangi risiko terdeteksi sebagai broadcast spam. Data dummy (nama produk, harga, lokasi mall, nama kontak Indonesia) ter-random tiap pesan.
| Type | Quoted message | Best use |
|---|---|---|
text | Pesan teks pertanyaan random ("Kak, barangnya ready ga?", "Ongkirnya berapa?", dll) | Generik, paling aman |
product | Product listing marketplace: nama produk + harga IDR + retailer + image count | Promo / toko online |
order | Pesanan: order ID + item count + status + seller JID | Notifikasi order / invoice |
location | Lokasi mall Indonesia dengan koordinat latitude/longitude + jitter | Info cabang / event |
video | Video message dengan caption review/unboxing random, durasi 5-180 detik | Testimoni / demo |
document | Document (PDF) dengan nama file invoice/katalog/sertifikat | Invoice / dokumen resmi |
contact | vCard kontak Indonesia random | Share kontak CS / referral |
Field:
| Field | Tipe | Deskripsi |
|---|---|---|
type | string | Wajib. Salah satu dari tabel di atas. |
title | string | Opsional. Override judul default (mis: nama produk, nama lokasi). Kosong = random. |
body | string | Opsional. Override deskripsi/caption default. |
participant | string | Opsional. JID sender dummy (format 628xxx@s.whatsapp.net). Kosong = random. |
stanza_id | string | Opsional. Message ID dummy. Kosong = random. |
Contoh launch dengan fake reply product:
curl -X POST https://maublast.net/api/v1/blast \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"message": "Kak, produk ini masih ready ya? Mau order 2",
"mode": "balanced",
"session_id": "SESSION_ID",
"recipients": [{"phone": "628111111111", "name": "Budi"}],
"fake_reply": {
"type": "product",
"title": "Sepatu Nike Air Max 270",
"body": "Ready stock, bisa COD"
}
}'Cara kerja: gateway membangun ContextInfo dengan stanza_id, participant, dan quoted_message lengkap (ProductMessage/OrderMessage/LocationMessage/dll). WhatsApp render di penerima seperti balasan ke pesan yang ada sebelumnya — padahal pesan aslinya tidak pernah ada.
Kalau title / body kosong, server pilih random dari pool data Indonesia (nama produk lokal, mall, kontak, dll).
Contoh lengkap: launch + monitor
Node.js:
const TOKEN = process.env.MAUBLAST_TOKEN;
const BASE = "https://maublast.net/api/v1";
async function launch() {
const res = await fetch(`${BASE}/blast`, {
method: "POST",
headers: {
"Authorization": `Bearer ${TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Promo weekend",
message: "Halo {{nama}}, {diskon 20%|promo spesial} buat kamu hari ini",
mode: "balanced",
session_id: "SESSION_ID",
skip_night: true,
recipients: [
{ phone: "628111111111", name: "Budi" },
{ phone: "628222222222", name: "Ani" },
],
}),
});
return await res.json();
}
async function waitComplete(id) {
while (true) {
const res = await fetch(`${BASE}/blast/${id}`, {
headers: { "Authorization": `Bearer ${TOKEN}` },
});
const c = await res.json();
console.log(`[${c.status}] ${c.sent}/${c.total} (OK:${c.ok}, Fail:${c.failed})`);
if (["completed", "cancelled", "failed"].includes(c.status)) return c;
await new Promise(r => setTimeout(r, 3000));
}
}
const campaign = await launch();
console.log("Launched:", campaign.id);
const final = await waitComplete(campaign.id);
console.log("Done:", final);Python:
import os, time, requests
TOKEN = os.environ["MAUBLAST_TOKEN"]
BASE = "https://maublast.net/api/v1"
HEADERS = {"Authorization": f"Bearer {TOKEN}"}
def launch():
r = requests.post(f"{BASE}/blast", headers=HEADERS, json={
"name": "Promo weekend",
"message": "Halo {{nama}}, promo spesial buat kamu",
"mode": "balanced",
"session_id": "SESSION_ID",
"skip_night": True,
"recipients": [
{"phone": "628111111111", "name": "Budi"},
{"phone": "628222222222", "name": "Ani"},
],
})
r.raise_for_status()
return r.json()
def wait_complete(id):
while True:
c = requests.get(f"{BASE}/blast/{id}", headers=HEADERS).json()
print(f"[{c['status']}] {c['sent']}/{c['total']} OK:{c['ok']} Fail:{c['failed']}")
if c["status"] in ("completed", "cancelled", "failed"):
return c
time.sleep(3)
campaign = launch()
print("Launched:", campaign["id"])
final = wait_complete(campaign["id"])
print("Done:", final)PHP:
<?php
$TOKEN = getenv("MAUBLAST_TOKEN");
$BASE = "https://maublast.net/api/v1";
function req($method, $path, $token, $body = null) global $BASE;
function apiCall($method, $path, $token, $body = null) {
global $BASE;
$ch = curl_init($BASE . $path);
$headers = ["Authorization: Bearer $token"];
if ($body !== null) {
$headers[] = "Content-Type: application/json";
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
}
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_RETURNTRANSFER => true,
]);
$resp = curl_exec($ch);
curl_close($ch);
return json_decode($resp, true);
}
$campaign = apiCall("POST", "/blast", $TOKEN, [
"name" => "Promo weekend",
"message" => "Halo {{nama}}, promo spesial",
"mode" => "balanced",
"session_id" => "SESSION_ID",
"recipients" => [
["phone" => "628111111111", "name" => "Budi"],
["phone" => "628222222222", "name" => "Ani"],
],
]);
$id = $campaign["id"];
echo "Launched: $id\n";
while (true) {
$c = apiCall("GET", "/blast/$id", $TOKEN);
echo "[{$c['status']}] {$c['sent']}/{$c['total']}\n";
if (in_array($c["status"], ["completed", "cancelled", "failed"])) break;
sleep(3);
}Data
List semua kontak yang tersimpan di session. Query param: limit, offset.
[
{
"jid": "628123456789@s.whatsapp.net",
"phone": "628123456789",
"push_name": "Budi S",
"is_business": false
}
]
Cek apakah nomor terdaftar di WhatsApp (sebelum blast).
// Request
{ "phones": ["628111111111", "628222222222"] }
// Response
[
{ "phone": "628111111111", "exists": true, "jid": "628111111111@s.whatsapp.net" },
{ "phone": "628222222222", "exists": false }
]
List grup WA. JID grup format xxxxx@g.us.
Ambil riwayat chat untuk JID tertentu. Query: limit, before_id.
Webhooks
Daftarkan URL endpoint untuk terima event real-time (pesan masuk, delivery, connection state, dll).
| Field | Tipe | Wajib | Deskripsi |
|---|---|---|---|
url | string | ya | Endpoint publik HTTPS Anda. |
events | string[] | tidak | Filter event. Kosong = semua. |
secret | string | tidak | Secret untuk HMAC signature. Sangat disarankan. |
curl -X POST https://maublast.net/api/v1/sessions/SESSION_ID/webhooks \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourdomain.com/webhook",
"events": ["message", "message.ack", "call.offer"],
"secret": "s3cr3t_str0ng_key"
}'Daftar event
| Event | Trigger |
|---|---|
message | Pesan masuk/keluar |
message.ack | Delivery/read receipt |
message.revoke | Pesan di-revoke/hapus |
message.reaction | Reaksi emoji ke pesan |
messages.upsert | Bulk sync awal koneksi |
group.join | Peserta masuk grup |
group.leave | Peserta keluar grup |
group.update | Nama/foto/deskripsi grup diubah |
presence.update | Online/offline/typing |
contacts.update | Info kontak berubah |
call.offer | Incoming call |
call.terminate | Call berakhir |
connection.update | Status koneksi device |
qr | QR baru tersedia |
poll.vote | Pilihan polling masuk |
blocklist.update | Kontak diblokir/unblock |
Format payload
Semua payload dikirim sebagai POST application/json. Struktur dasar:
{
"event": "message",
"session_id": "SESSION_ID",
"timestamp": 1734000000,
"data": {
"from": "628123456789@s.whatsapp.net",
"from_me": false,
"push_name": "John Doe",
"message_id": "3EB0ABC...",
"type": "text",
"text": "Halo admin"
}
}
Payload media (image/video/document) tambah field media:
{
"event": "message",
"data": {
"type": "image",
"caption": "Invoice",
"media": {
"mime_type": "image/jpeg",
"file_length": 45678,
"url": "https://cdn.maublast.net/media/abc.jpg"
}
}
}
Verifikasi signature HMAC
Kalau secret diset, tiap request membawa header X-MAUBLAST-Signature berisi HMAC SHA256 dari raw body. Verifikasi di server Anda:
import crypto from "crypto";
import express from "express";
const app = express();
// IMPORTANT: pakai raw body, bukan parsed JSON
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
const sig = req.headers["x-maublast-signature"];
const expected = crypto
.createHmac("sha256", process.env.WEBHOOK_SECRET)
.update(req.body)
.digest("hex");
if (sig !== expected) return res.status(401).end();
const payload = JSON.parse(req.body);
console.log(payload.event, payload.session_id);
res.json({ ok: true });
});
Retry policy
Kalau endpoint Anda tidak balas 2xx dalam 10 detik, kami retry:
| Attempt | Delay | Timeout |
|---|---|---|
| 1 (awal) | 0s | 10s |
| 2 | 30s | 10s |
| 3 | 2 menit | 10s |
| 4 (terakhir) | 10 menit | 10s |
Idempotency: karena ada retry, endpoint Anda bisa terima event yang sama lebih dari sekali. Gunakan data.message_id untuk dedupe di Redis/DB (TTL 24 jam).