Dokumentasi API

v1

Referensi 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

https://maublast.net/api/v1

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

StatusArti
200Sukses. Response JSON di body.
202Accepted — pesan masuk antrian (async).
400Bad request — payload invalid / field required hilang.
401Unauthorized — token hilang / salah / expired.
403Forbidden — resource bukan milik Anda.
404Not found — session ID / resource tidak ada.
409Conflict — session sudah dalam state itu (mis: connect saat sudah connected).
422Unprocessable — session belum logged_in saat coba kirim pesan.
429Too Many Requests — rate limit. Tunggu dan retry dengan exponential backoff.
500Server 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).

GET /sessions

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"
  }
]
POST /sessions

Buat session baru. Setelah dibuat, lanjut panggil /connect untuk mulai pairing.

FieldTipeWajibDeskripsi
namestringyaNama session (untuk identifikasi).
deviceobjecttidakIdentitas perangkat di "Perangkat tertaut" WhatsApp. Hanya berlaku saat first pair.
device.osstringtidakOS label, contoh: Windows, Mac OS X, Ubuntu. Default: Windows.
device.platformstringtidakSalah 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"}}'
GET /sessions/{id}/status

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"
GET /sessions/{id}/qr

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..."] }
POST /sessions/{id}/pair

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"}}'
POST /sessions/{id}/connect

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"}}'
POST /sessions/{id}/disconnect

Putus koneksi. Session tetap tersimpan, tinggal /connect lagi kalau mau aktifin ulang.

DELETE /sessions/{id}

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

POST /sessions/{id}/messages/text

Kirim pesan teks. Support formatting: *bold*, _italic_, ~strike~, ```mono```.

FieldTipeWajibDeskripsi
tostringyaNomor tujuan.
textstringyaIsi 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."
  }'
POST /sessions/{id}/messages/image
FieldTipeWajibDeskripsi
tostringyaNomor tujuan.
image.urlstringya*URL publik gambar (JPG/PNG/WebP, max 5MB).
image.base64stringya*Alternatif: base64 data.
captionstringtidakCaption bawah gambar.
{
  "to": "628123456789",
  "image": { "url": "https://cdn.example.com/promo.jpg" },
  "caption": "Promo spesial weekend"
}
POST /sessions/{id}/messages/video

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"
}
POST /sessions/{id}/messages/audio

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
}
POST /sessions/{id}/messages/document
FieldTipeWajibDeskripsi
document.urlstringyaURL file (PDF, DOCX, XLSX, dll — max 100MB).
filenamestringyaNama file yang tampil (mis: invoice.pdf).
captionstringtidakCaption.
{
  "to": "628123456789",
  "document": { "url": "https://cdn.example.com/invoice-123.pdf" },
  "filename": "invoice-123.pdf",
  "caption": "Invoice order #123"
}
POST /sessions/{id}/messages/location
{
  "to": "628123456789",
  "latitude": -6.2088,
  "longitude": 106.8456,
  "name": "Kantor Pusat",
  "address": "Jl. Sudirman No. 1, Jakarta"
}
POST /sessions/{id}/messages/contact
{
  "to": "628123456789",
  "contact": {
    "display_name": "Customer Service",
    "phones": [
      { "number": "628555666777", "phone_type": "CELL" }
    ]
  }
}
POST /sessions/{id}/messages/poll

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
}
POST /sessions/{id}/messages/interactive

Native flow buttons. Tipe button: quick_reply, cta_url, cta_copy, cta_call.

{
  "to": "628123456789",
  "body_text": "Mau lanjut ke step mana?",
  "footer_text": "Powered by MAUBLAST",
  "buttons": [
    { "name": "quick_reply",
      "button_params_json": "{\"display_text\":\"Ya, lanjut\",\"id\":\"btn_yes\"}" },
    { "name": "cta_url",
      "button_params_json": "{\"display_text\":\"Lihat detail\",\"url\":\"https://example.com\"}" },
    { "name": "cta_call",
      "button_params_json": "{\"display_text\":\"Telepon kami\",\"phone_number\":\"+6281234567890\"}" }
  ]
}
POST /sessions/{id}/messages/cta-url

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"
}
POST /sessions/{id}/messages/quick-reply

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" }
  ]
}
POST /sessions/{id}/messages/list

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.

Lifecycle kampanye
queuedrunningcompleted
Bisa juga: paused (via /pause), cancelled (via DELETE), failed (fatal error).
POST /blast

Buat dan antrikan kampanye. Response 202 dengan ID kampanye.

FieldTipeWajibDeskripsi
messagestringyaIsi pesan. Support {{nama}}, {{phone}}, {{tanggal}}, {{jam}}, dan variasi inline {a|b|c}.
recipientsarrayyaArray of {"phone": "...", "name": "..."}. Max 10.000. Duplikat auto-skip.
namestringtidakNama kampanye untuk tracking.
session_idstring/inttidak*ID session yang dipakai kirim. * Wajib kalau tidak pakai rotator_group_id.
rotator_group_idinttidak*ID grup rotator (prioritas di atas session_id).
modestringtidakfast / balanced (default) / human / safe. Set preset delay/typing/batch.
delay_min, delay_maxint (detik)tidakOverride jeda jitter. Default tergantung mode.
typingbooltidakTyping simulation 1-3 detik sebelum tiap pesan.
batchbooltidakEnable batch pause.
batch_size, batch_pauseinttidakUkuran batch dan durasi pause (detik).
shufflebooltidakAcak urutan penerima (default: true).
skip_nightbooltidakPause kirim antara 22:00-06:00 WIB.
variationsstring[]tidakArray template alternatif. Kalau di-set, message jadi fallback saja.
fake_replyobjecttidakBungkus 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"
}
GET /blast/{id}

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
}
GET /blast

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

POST/blast/{id}/pause

Hentikan sementara kampanye yang running/queued. Progress tersimpan.

POST/blast/{id}/resume

Lanjutkan kampanye yang paused dari index terakhir.

DELETE/blast/{id}

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.

ModeJeda (detik)TypingBatchKapasitasCocok untuk
fast1-3 randomoffoff~1200/jamTest internal, nomor warm & sehat.
balanced default3-8 randomonoff~600/jamBlast harian, nomor normal.
human5-20 randomon30 / 90s~250/jamNomor baru atau yang pernah kena warning.
safe10-30 randomon20 / 180s~120/jamWarm 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.

TypeQuoted messageBest use
textPesan teks pertanyaan random ("Kak, barangnya ready ga?", "Ongkirnya berapa?", dll)Generik, paling aman
productProduct listing marketplace: nama produk + harga IDR + retailer + image countPromo / toko online
orderPesanan: order ID + item count + status + seller JIDNotifikasi order / invoice
locationLokasi mall Indonesia dengan koordinat latitude/longitude + jitterInfo cabang / event
videoVideo message dengan caption review/unboxing random, durasi 5-180 detikTestimoni / demo
documentDocument (PDF) dengan nama file invoice/katalog/sertifikatInvoice / dokumen resmi
contactvCard kontak Indonesia randomShare kontak CS / referral

Field:

FieldTipeDeskripsi
typestringWajib. Salah satu dari tabel di atas.
titlestringOpsional. Override judul default (mis: nama produk, nama lokasi). Kosong = random.
bodystringOpsional. Override deskripsi/caption default.
participantstringOpsional. JID sender dummy (format 628xxx@s.whatsapp.net). Kosong = random.
stanza_idstringOpsional. 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

GET /sessions/{id}/contacts

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
  }
]
POST /sessions/{id}/contacts/check

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 }
]
GET /sessions/{id}/groups

List grup WA. JID grup format xxxxx@g.us.

GET /sessions/{id}/chats/{jid}

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

POST /sessions/{id}/webhooks
FieldTipeWajibDeskripsi
urlstringyaEndpoint publik HTTPS Anda.
eventsstring[]tidakFilter event. Kosong = semua.
secretstringtidakSecret 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

EventTrigger
messagePesan masuk/keluar
message.ackDelivery/read receipt
message.revokePesan di-revoke/hapus
message.reactionReaksi emoji ke pesan
messages.upsertBulk sync awal koneksi
group.joinPeserta masuk grup
group.leavePeserta keluar grup
group.updateNama/foto/deskripsi grup diubah
presence.updateOnline/offline/typing
contacts.updateInfo kontak berubah
call.offerIncoming call
call.terminateCall berakhir
connection.updateStatus koneksi device
qrQR baru tersedia
poll.votePilihan polling masuk
blocklist.updateKontak 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:

AttemptDelayTimeout
1 (awal)0s10s
230s10s
32 menit10s
4 (terakhir)10 menit10s

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