Langsung ke konten
Wbiztool

Panduan produk

Webhook pesan masuk (listener)

Listener menghubungkan salah satu nomor WhatsApp Anda ke Unibox dan dapat mengirim webhook pesan masuk ke server Anda. Di dashboard, listener dikelola di halaman Incoming Triggers (pemicu pesan masuk). Setelah sebuah nomor menjadi listener, chat-nya tersinkron ke kotak masuk Unibox, dan jika Anda menambahkan URL webhook, Wbiztool mengirim setiap pesan baru ke server Anda. Gunakan webhook untuk mencatat percakapan di CRM, memberi tahu tim Anda, atau membuat balasan otomatis.

Sebelum memulai#

  • Add-on Unibox. Biayanya $20/bulan atau $200/tahun per nomor WhatsApp, dan jumlah listener yang dapat Anda miliki sama dengan jumlah add-on. Beli di bagian Available Add-ons pada Billing & Plans di dalam dashboard. Tanpa add-on ini, halaman Incoming Triggers tetap terbuka, tetapi mengklik Add New Listener menampilkan Unibox Add-on Required dengan tombol Subscribe to Unibox Add-on.
  • Nomor WhatsApp yang terhubung di WhatsApp settings. Hanya nomor terhubung yang belum menjadi listener yang dapat ditambahkan.
  • Anda harus menjadi owner atau editor workspace.
  • Untuk webhook: URL publik (gunakan https) dengan panjang maksimal 100 karakter yang menerima permintaan POST dengan body JSON.

Menambahkan listener#

  1. Buka Incoming Triggers

    Di sidebar, buka Unibox lalu klik Incoming Triggers, atau buka Incoming Triggers.

  2. Mulai listener baru

    Klik kartu Add New Listener.

  3. Pilih nomor

    Pilih di Select WhatsApp Number. Jika daftar menampilkan No available WhatsApp numbers, berarti setiap nomor yang terhubung sudah menjadi listener, atau tidak ada nomor yang terhubung.

  4. Tambahkan webhook (opsional)

    Masukkan Webhook URL (Optional). Setelah Anda mengetik URL, Webhook Events muncul: biarkan Incoming Messages (pesan masuk), Outgoing Messages (pesan keluar), atau keduanya tercentang. Anda dapat menambahkan atau mengubah URL nanti.

  5. Simpan

    Klik Add Listener. Listener muncul sebagai kartu dengan status Active. Jika Anda memasukkan URL, secret webhook dibuat untuknya.

Mengelola listener#

Setiap kartu menampilkan nomor, statusnya, Webhook URL: (atau Not configured), Last Activity: (kapan terakhir kali nomor diperiksa untuk pesan baru, atau Never), dan Webhook Secret:, yang tersembunyi sampai Anda mengklik tombol mata.

Buka menu ⋮ pada kartu untuk:

TindakanYang terjadi
EditMengubah URL webhook, event webhook, atau secret. Nomornya tidak dapat diubah.
Disable / EnableDisable mengubah listener menjadi Inactive: nomor berhenti tersinkron ke kotak masuk dan tidak ada webhook yang dikirim. Enable membuatnya Active lagi.
DeleteMenghapus listener setelah Anda mengonfirmasi. Percakapan yang sudah ada di kotak masuk tetap ada. Menambahkan nomor yang sama lagi nanti akan memulihkan listener. Jika Anda memasukkan URL webhook saat menambahkannya kembali, listener tetap memakai secret webhook sebelumnya, jika ada, alih-alih mendapat yang baru.

Status listener#

StatusArti
ActivePesan tersinkron dan webhook dikirim selama nomor terhubung.
PendingNomor tidak terhubung saat listener dibuat, misalnya oleh Zapier. Klik Enable setelah nomor terhubung.
InactiveDinonaktifkan. Tidak ada yang tersinkron dan tidak ada webhook yang dikirim.

Statistik#

KartuYang ditampilkan
Active ListenersSemua listener di halaman, termasuk yang dinonaktifkan.
Available NumbersNomor terhubung yang belum menjadi listener. Nomor yang listener-nya sudah Anda hapus tetap dihitung sebagai terpakai di sini, sehingga angkanya bisa lebih kecil daripada yang sebenarnya dapat Anda tambahkan.
Total LimitBerapa banyak listener yang diizinkan add-on Unibox Anda.
Messages TodayBelum dilacak; selalu menampilkan 0.

Mengubah URL webhook atau event#

  1. Buka listener

    Klik ⋮ pada kartu, lalu Edit.

  2. Perbarui pengaturan

    Ubah Webhook URL (Optional) dan Webhook Events. Kosongkan URL untuk menghentikan webhook bagi nomor ini: secret-nya juga dihapus, dan secret baru dibuat jika Anda menambahkan URL lagi.

  3. Simpan

    Klik Update Listener.

Membuat ulang secret#

Di Edit Listener, klik tombol refresh di sebelah Webhook Secret lalu konfirmasi. Secret baru langsung disimpan, bahkan jika Anda kemudian menutup dialog tanpa mengklik Update Listener, dan permintaan ditandatangani dengan secret tersebut sejak saat itu. Segera perbarui server Anda dengan secret baru.

Cara webhook dikirim#

Wbiztool mengirim satu permintaan POST ke URL Anda untuk setiap pesan baru yang ditemukan saat nomor tersinkron, yang terjadi setiap beberapa menit selama nomor terhubung dan tidak sibuk mengirim pesan.

  • Event: message_received untuk pesan yang dikirim orang ke nomor Anda, dan message_sent untuk pesan yang dikirim dari nomor tersebut (dari ponsel, kampanye, atau API). Hanya event yang dicentang di Webhook Events yang dikirim.
  • Balasan dari kotak masuk Unibox biasanya tidak memicu message_sent, karena kotak masuk sudah memilikinya saat sinkronisasi berjalan.
  • Respons: balas dengan status HTTP 2xx apa pun dalam 8 detik.
  • Percobaan ulang: timeout, error koneksi, 429, atau respons 5xx dicoba ulang hingga 3 kali, setelah 30 detik, 1 menit, dan 2 menit. Respons lain, seperti 400 atau 404, tidak dicoba ulang.
  • 410 Gone: Wbiztool menghapus URL webhook dari listener dan berhenti mengirim ke sana. Pesan tetap diimpor ke Unibox.
  • Urutan: permintaan dikirim secara independen dan dapat tiba tidak berurutan. Urutkan berdasarkan message.timestamp jika urutan penting.
HeaderNilai
Content-Typeapplication/json
X-Wbiztool-Eventmessage_received atau message_sent
X-Wbiztool-TimestampKapan webhook dikirim, dalam ISO 8601 UTC. Sama dengan timestamp di body.
X-Wbiztool-Webhook-IdID listener. Sama dengan webhook_id di body.
X-Wbiztool-Signaturesha256= diikuti tanda tangan. Dikirim setiap kali listener memiliki secret, yang selalu terjadi jika URL diatur.

Payload#

Contoh body webhook
{
  "event": "message_received",
  "timestamp": "2026-09-16T10:31:12.482913+00:00",
  "webhook_id": 42,
  "whatsapp_client_id": "678",
  "whatsapp_phone": "919812345678",
  "message": {
    "id": "[email protected]_3EB0C1A2B3D4E5F60718",
    "type": "chat",
    "content": "Hi, is my order #4821 out for delivery?",
    "from": "919876543210",
    "from_name": "Aman",
    "to": "919812345678",
    "timestamp": "2026-09-16T10:29:58+00:00",
    "whatsapp_timestamp": 1789554598,
    "direction": "incoming",
    "status": "pending",
    "is_forwarded": false,
    "forwarding_score": 0
  },
  "contact": {
    "whatsapp_id": "[email protected]",
    "phone": "919876543210",
    "lid": null,
    "phone_hidden": false,
    "name": "Aman",
    "is_group": false,
    "is_business": false
  },
  "organisation": {
    "id": "10314",
    "name": "Acme Stores"
  }
}

Nomor, ID, dan nama di atas hanyalah contoh.

Field tingkat atas#

FieldTipeDeskripsi
eventstringmessage_received atau message_sent.
timestampstringKapan webhook dikirim (ISO 8601, UTC).
webhook_idintegerID listener.
whatsapp_client_idstringID nomor WhatsApp Anda, seperti yang ditampilkan di WhatsApp settings.
whatsapp_phonestringNomor WhatsApp Anda.
messageobjectPesan. Lihat di bawah.
contactobjectOrang atau grup lawan percakapan. Lihat di bawah.
organisationobjectid (string) dan name workspace Anda.
groupobjectHanya untuk chat grup: name, nama grup.

Field message#

FieldTipeDeskripsi
idstringID WhatsApp untuk pesan. Gunakan untuk mengabaikan duplikat.
typestringchat untuk teks. Selain itu, tipe dari WhatsApp, seperti image, video, audio, ptt (pesan suara), document, sticker, atau location.
contentstringTeks untuk pesan chat. Untuk media, berupa label: 📸 Image, 🎥 Video, 🎵 Audio, 🎤 Voice Message, 😊 Sticker, Document: diikuti teks dokumen (Document jika tidak ada teks), atau nama tipe dalam huruf kapital di awal kata untuk tipe lainnya, seperti Location. Keterangan (caption) tidak disertakan.
fromstringSelalu nomor kontak (atau ID grup), di kedua arah.
from_namestringNama kontak atau grup. Bisa kosong.
tostringSelalu nomor WhatsApp Anda, di kedua arah.
timestampstringKapan pesan dikirim di WhatsApp (ISO 8601, UTC).
whatsapp_timestampintegerWaktu yang sama sebagai Unix timestamp dalam detik.
directionstringincoming atau outgoing. Gunakan field ini, bukan from dan to, untuk mengetahui arah pesan.
statusstringSaat ini selalu pending. Jangan mengandalkannya untuk status terkirim atau dibaca.
is_forwardedbooleanApakah pesan diteruskan.
forwarding_scoreintegerBerapa kali pesan diteruskan.
mediaobjectUntuk pesan media jika detailnya tersedia: filename, mimetype, dan size dalam byte. File itu sendiri tidak disertakan.
quoted_message_idstringHanya jika pesan membalas pesan lain.

Field contact#

FieldTipeDeskripsi
whatsapp_idstringWhatsApp ID, seperti [email protected] untuk orang atau …@g.us untuk grup.
phonestringNomor tanpa +, atau ID grup untuk grup. Kosong jika WhatsApp menyembunyikan nomor kontak.
lidstring or nullID privasi WhatsApp untuk kontak, seperti 62337239240946@lid, jika WhatsApp menggunakannya. Jika tidak, null.
phone_hiddenbooleantrue jika WhatsApp tidak membagikan nomor kontak. Wbiztool mengisi nomor tersebut setiap kali WhatsApp menyediakannya.
namestringNama yang dimiliki Wbiztool untuk kontak, atau nama grup. Bisa kosong.
is_groupbooleantrue untuk chat grup.
is_businessbooleantrue untuk akun WhatsApp Business, jika diketahui.

Memverifikasi tanda tangan#

Setiap permintaan ditandatangani dengan secret listener Anda menggunakan HMAC-SHA256. Tanda tangan dihitung dari body permintaan mentah persis seperti yang diterima, dan dikirim sebagai sha256= ditambah digest hex huruf kecil di X-Wbiztool-Signature.

Selalu hitung tanda tangan dari byte mentah sebelum mem-parsing JSON. Mem-parsing lalu meng-encode ulang body akan mengubahnya (misalnya, karakter non-Inggris dan emoji tiba dalam bentuk escape \uXXXX), dan tanda tangan tidak akan cocok.

// Express: keep the raw body for this route
import crypto from "node:crypto";
import express from "express";

const app = express();
const SECRET = process.env.WBIZTOOL_WEBHOOK_SECRET;

app.post("/wbiztool/webhook", express.raw({ type: "application/json" }), (req, res) => {
  const expected = "sha256=" + crypto.createHmac("sha256", SECRET).update(req.body).digest("hex");
  const received = req.get("X-Wbiztool-Signature") || "";

  const valid =
    received.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected));
  if (!valid) return res.status(401).send("Invalid signature");

  const data = JSON.parse(req.body.toString("utf8"));
  if (data.event === "message_received") {
    console.log(`New message from ${data.contact.phone}: ${data.message.content}`);
  }
  res.sendStatus(200); // reply quickly; do slow work in the background
});

app.listen(3000);

Tanda tangan tidak mencakup header timestamp, sehingga tidak melindungi dari permintaan yang diputar ulang (replay). Jika hal itu penting, simpan setiap message.id yang sudah Anda proses dan abaikan pengulangannya.

Pemecahan masalah#

Pesan atau masalahYang harus dilakukan
Unibox Add-on Required saat Anda mengklik Add New ListenerWorkspace Anda tidak memiliki add-on Unibox. Beli di bagian Available Add-ons pada Billing & Plans di dalam dashboard.
You have reached your unibox numbers limitHapus listener yang tidak lagi Anda perlukan, atau tambah jumlah add-on.
No available WhatsApp numbersHubungkan nomor lain, atau nomor tersebut sudah menjadi listener.
This WhatsApp number is already a listenerUbah kartu yang sudah ada.
Invalid WhatsApp clientNomor terputus. Hubungkan ulang di WhatsApp settings lalu muat ulang halaman.
Error yang menyebutkan value too long saat menyimpanURL webhook lebih dari 100 karakter. Gunakan URL yang lebih pendek.
Tidak ada webhook yang tibaPastikan listener berstatus Active, nomor terhubung, jenis event dicentang, dan URL Anda berupa https publik dengan sertifikat yang valid. Pesan baru dikirim setelah sinkronisasi berikutnya, beberapa menit kemudian.
Beberapa webhook hilangServer Anda mengembalikan status 4xx, atau terus gagal pada ketiga percobaan ulang. Periksa log server Anda pada waktu pesan yang hilang.
URL webhook hilang dari listenerServer Anda menjawab 410 Gone, sehingga Wbiztool berhenti mengirim ke sana. Tambahkan URL lagi di Edit Listener.
Tanda tangan tidak cocokGunakan body mentah, bukan JSON yang di-encode ulang, dan secret yang berlaku saat ini. Membuat ulang secret akan menggantikannya. Selama Zap Zapier menggunakan nomor tersebut, permintaan dikirim ke Zapier dengan secret Zapier.
Last Activity: menampilkan NeverNomor belum diperiksa. Nomor harus terhubung dan tidak sibuk mengirim pesan.

Terkait#