Notiblast
HomeApp
HomeApp
  1. Webhooks
  • API Key & Izin
  • Email
    • 1. Alur Email
    • 2. Domain & DNS
    • 3. Kirim Email
    • 4. Status Email
    • Messages
      • List Messages
      • Export Messages (CSV)
      • Detail Message
    • Send Email
      POST
  • Whatsapp
    • 1. Alur WhatsApp
    • 2. Hubungkan Nomor
    • 3. Setelah Nomor Terhubung
    • 4. Template Pesan
    • 5. Syarat Template Authentication
    • 6. Verifikasi Bisnis Meta
    • 7. Kirim & Status Pesan
    • Messages
      • List Messages
      • Detail Message
      • Export Messages (CSV)
    • Send WhatsApp
      POST
  • Reports
    • Overview (Dasbor)
      GET
    • Email Monitoring
      GET
    • WhatsApp Monitoring
      GET
    • Push Notification Monitoring
      GET
    • Deliverability Summary
      GET
  • Push
    • 1. Alur Push Notification
    • 2. Aplikasi Push & Firebase
    • 3. Pasang SDK
    • 4. List Penerima
    • 5. Kirim & Hasil Push
    • Devices
      • Register Device
      • Release Device
    • Messages
      • List Push Messages
      • Get Push Message
    • Lists
      • List Push Lists
      • List Push List Members
      • Add Push List Members
      • Remove Push List Members
    • Send Push Notification
      POST
  • Api Logs
    • List API Logs
    • Detail API Log
  • Webhooks
    • Webhook Events (Notiblast → Endpoint Anda)
  1. Webhooks

Webhook Events (Notiblast → Endpoint Anda)

Halaman ini bukan endpoint Notiblast. Ini kontrak POST yang Notiblast kirim ke URL webhook milik Anda — Anda yang mengimplementasikan endpoint penerimanya.
URL dipasang per channel (whatsapp, push) oleh admin company di dasbor Notiblast → pengaturan Webhook. Secret penanda tangan hanya ditampilkan sekali, saat URL pertama kali disimpan atau saat secret diputar ulang — simpan saat itu juga.
EventChannelKapan dikirim
message.receivedwhatsappSetiap pesan masuk, dan setiap kali pesan itu di-Replay dari dasbor
push.completedpushSekali, saat satu Pesan Push selesai diproses (sent / partial / failed)

1. Request yang kami kirim#

HeaderIsi
X-Notiblast-Event-IdSama dengan id di body. Stabil lintas percobaan dan lintas Replay — pakai sebagai kunci idempotency
X-Notiblast-TimestampUnix detik saat POST dibuat
X-Notiblast-Delivery-AttemptPercobaan ke-berapa, 1–4
X-Notiblast-Signaturet=<unix detik>,v1=<hex> — lihat §4
Semua event memakai envelope yang sama:
{
  "id": "string (24 hex)",
  "type": "message.received | push.completed",
  "channel": "whatsapp | email | push",
  "created_at": "ISO 8601",
  "data": { }
}

2. message.received#

Body#

FieldTipeKeterangan
idstring (24 hex)_id pesan masuk — kunci idempotency
type"message.received"
channel"whatsapp" | "email"
created_atstring (date-time)Saat pesan dicatat Notiblast
data.external_idstringId pesan dari provider (WhatsApp message id / Message-ID email)
data.wa_numberstring (24 hex) | null_id nomor WhatsApp penerima; null untuk email
data.fromstringPengirim
data.tostringPenerima (nomor / alamat Anda)
data.message_typestringtext, image, audio, video, document, sticker, location, contact, unsupported
data.textstring | nullIsi teks
data.mediaobject | null{ mime_type, size, filename, caption, provider_media_id } — size, filename, caption, provider_media_id boleh null
data.received_atstring (date-time)Saat provider menerima pesan
Isi mentah provider (payload) dan catatan pengiriman webhook (delivery) sengaja tidak ikut.

Contoh#

{
  "id": "507f1f77bcf86cd799439099",
  "type": "message.received",
  "channel": "whatsapp",
  "created_at": "2026-08-26T04:15:12.000Z",
  "data": {
    "external_id": "3EB0C767D26B8A1B2C3D",
    "wa_number": "507f1f77bcf86cd799439081",
    "from": "6281234567890",
    "to": "6289876543210",
    "message_type": "text",
    "text": "Halo, pesanan saya sudah dikirim?",
    "media": null,
    "received_at": "2026-08-26T04:15:11.000Z"
  }
}

3. push.completed#

Body#

FieldTipeKeterangan
idstring (24 hex)_id Pesan Push — kunci idempotency
type"push.completed"
channel"push"
created_atstring (date-time)Saat Pesan Push dibuat
data.push_appstring (24 hex)_id Push App
data.push_app_namestring
data.titlestringJudul notifikasi
data.target_typestringexternal_id, list, all, token, topic
data.target_labelstringLabel sasaran yang mudah dibaca
data.statusstringHasil akhir: sent, partial, failed
data.statsobject{ devices_targeted, devices_sent, devices_failed, devices_skipped, external_ids_unmatched } — semuanya 0 bila target_type = "topic". devices_skipped = perangkat permission_denied / unsubscribed, bukan kegagalan
data.errorstring | nullAlasan bila failed
data.finished_atstring (date-time) | nullSaat pemrosesan selesai
Isi notifikasi (body) sengaja tidak ikut — bisa memuat data pribadi penerima.

Contoh#

{
  "id": "507f1f77bcf86cd799439077",
  "type": "push.completed",
  "channel": "push",
  "created_at": "2026-09-16T04:01:31.900Z",
  "data": {
    "push_app": "507f1f77bcf86cd799439011",
    "push_app_name": "Toko Maju — Pelanggan",
    "title": "Promo akhir pekan",
    "target_type": "all",
    "target_label": "Semua perangkat",
    "status": "partial",
    "stats": {
      "devices_targeted": 4102,
      "devices_sent": 4037,
      "devices_failed": 65,
      "devices_skipped": 214,
      "external_ids_unmatched": 0
    },
    "error": null,
    "finished_at": "2026-09-16T04:01:31.900Z"
  }
}

4. Verifikasi tanda tangan#

v1 = HMAC-SHA256(secret, "<t>.<rawBody>") dalam hex.
1.
Pisahkan t dan v1 dari header X-Notiblast-Signature.
2.
Tolak bila |now − t| > 300 detik (mencegah replay lalu-lintas lama).
3.
Hitung HMAC atas raw body persis yang diterima — jangan JSON.stringify ulang hasil parse; beda satu spasi saja membuat tanda tangan selalu gagal.
4.
Bandingkan dengan timingSafeEqual, bukan ===.
import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyNotiblast(rawBody: string, header: string, secret: string): boolean {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=") as [string, string]));
  const t = Number(parts.t);
  if (!Number.isFinite(t) || Math.abs(Date.now() / 1000 - t) > 300) return false;

  const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`, "utf8").digest();
  const received = Buffer.from(parts.v1 ?? "", "hex");
  return received.length === expected.length && timingSafeEqual(received, expected);
}
Prefix v1= diberi versi: bila algoritma diganti nanti, header yang sama akan menambah v2=, bukan mengganti v1=.

5. Retry & jawaban yang kami harapkan#

Jawaban endpoint AndaYang Notiblast lakukan
2xxSelesai — delivery.status: delivered
408, 429, 5xx, timeout (10 detik), DNS / TCP errorDicoba ulang. Total 4 percobaan: langsung, +30 detik, +15 menit, +30 menit. Setelah itu failed
4xx lain (400, 401, 403, 404, 410, …)Dianggap penolakan permanen — failed seketika, tidak dicoba ulang
Belum ada webhook aktif untuk channel ituTidak dikirim — delivery.status: skipped
Body balasan Anda diabaikan; hanya status code yang dibaca.

6. Yang harus Anda lakukan#

Jawab 2xx secepatnya, proses secara asinkron. Batas kami 10 detik per percobaan.
Deduplikasi dengan id. Event yang sama bisa datang lebih dari sekali (retry, Replay).
Verifikasi tanda tangan sebelum mempercayai isi body.
Endpoint Anda yang mati tidak mempengaruhi pengiriman pesan itu sendiri — hanya pengabarannya yang gagal. Status pengirimannya terlihat di dasbor (detail pesan masuk / Pesan Push).
Modified at 2026-10-21 07:54:52
Previous
Detail API Log
Built with