Panduan produk
Webhook mesej masuk (listener)
Listener menyambungkan salah satu nombor WhatsApp anda ke Unibox dan boleh menghantar webhook mesej masuk ke pelayan anda. Dalam papan pemuka, listener diurus di halaman Incoming Triggers (Pencetus masuk). Setelah sesuatu nombor menjadi listener, sembangnya disegerakkan ke peti masuk Unibox, dan, jika anda menambah URL webhook, Wbiztool menghantar setiap mesej baharu ke pelayan anda. Gunakan webhook untuk merekod perbualan dalam CRM, memaklumkan pasukan anda atau membina balasan automatik.
Sebelum anda bermula#
- Tambahan Unibox. Harganya $20/bulan atau $200/tahun bagi setiap nombor WhatsApp, dan bilangan listener yang boleh anda miliki sama dengan kuantiti tambahan. Belinya di bawah Available Add-ons di Billing & Plans dalam papan pemuka. Tanpanya, halaman Incoming Triggers masih boleh dibuka, tetapi mengklik Add New Listener menunjukkan Unibox Add-on Required dengan butang Subscribe to Unibox Add-on.
- Nombor WhatsApp yang bersambung di WhatsApp settings. Hanya nombor bersambung yang belum menjadi listener boleh ditambah.
- Anda mesti menjadi pemilik (owner) atau editor ruang kerja.
- Untuk webhook: URL awam (gunakan
https) yang tidak melebihi 100 aksara dan menerima permintaanPOSTdengan badan JSON.
Tambah listener#
Buka Incoming Triggers
Di bar sisi, buka Unibox dan klik Incoming Triggers, atau pergi ke Incoming Triggers.
Mulakan listener baharu
Klik kad Add New Listener.
Pilih nombor
Pilihnya dalam Select WhatsApp Number. Jika senarai menyatakan No available WhatsApp numbers, setiap nombor bersambung sudah menjadi listener, atau tiada nombor yang bersambung.
Tambah webhook (pilihan)
Masukkan Webhook URL (Optional) anda. Sebaik sahaja anda menaip URL, Webhook Events muncul: biarkan Incoming Messages (Mesej masuk), Outgoing Messages (Mesej keluar) atau kedua-duanya ditandakan. Anda boleh menambah atau menukar URL kemudian.
Simpan
Klik Add Listener. Listener muncul sebagai kad dengan status Active. Jika anda memasukkan URL, rahsia webhook dicipta untuknya.
Urus listener#
Setiap kad menunjukkan nombor, statusnya, Webhook URL: (atau Not configured), Last Activity: (bila nombor itu kali terakhir disemak untuk mesej, atau Never) dan Webhook Secret:, yang disembunyikan sehingga anda mengklik butang mata.
Buka menu ⋮ pada kad untuk:
| Tindakan | Apa yang berlaku |
|---|---|
| Edit | Tukar URL webhook, peristiwa webhook atau rahsia. Nombor tidak boleh ditukar. |
| Disable / Enable | Melumpuhkan menetapkan listener kepada Inactive: nombor itu berhenti disegerakkan ke peti masuk dan tiada webhook dihantar. Mendayakan menjadikannya Active semula. |
| Delete | Mengalih keluar listener selepas anda mengesahkan. Perbualan yang sudah ada dalam peti masuk kekal. Menambah nombor yang sama semula kemudian memulihkan listener itu. Jika anda memasukkan URL webhook semasa menambahnya semula, listener mengekalkan rahsia webhook sebelumnya, jika ada, dan bukannya mendapat yang baharu. |
Status listener#
| Status | Maksud |
|---|---|
| Active | Mesej disegerakkan dan webhook dihantar semasa nombor itu bersambung. |
| Pending | Nombor itu tidak bersambung semasa listener dicipta, contohnya oleh Zapier. Klik Enable setelah nombor itu bersambung. |
| Inactive | Dilumpuhkan. Tiada apa-apa disegerakkan dan tiada webhook dihantar. |
Statistik#
| Kad | Apa yang ditunjukkan |
|---|---|
| Active Listeners | Semua listener di halaman, termasuk yang dilumpuhkan. |
| Available Numbers | Nombor bersambung yang belum menjadi listener. Nombor yang listenernya telah anda padam masih dikira sebagai digunakan di sini, jadi angka ini boleh lebih rendah daripada yang sebenarnya boleh anda tambah. |
| Total Limit | Berapa banyak listener yang dibenarkan oleh tambahan Unibox anda. |
| Messages Today | Belum dijejaki; sentiasa menunjukkan 0. |
Tukar URL webhook atau peristiwa#
Buka listener
Klik ⋮ pada kad, kemudian Edit.
Kemas kini tetapan
Tukar Webhook URL (Optional) dan Webhook Events. Kosongkan URL untuk menghentikan webhook bagi nombor ini: rahsianya juga dialih keluar, dan rahsia baharu dicipta jika anda menambah URL semula.
Simpan
Klik Update Listener.
Jana semula rahsia#
Dalam Edit Listener, klik butang muat semula di sebelah Webhook Secret dan sahkan. Rahsia baharu disimpan serta-merta, walaupun anda kemudian menutup dialog tanpa mengklik Update Listener, dan permintaan ditandatangani dengannya mulai saat itu. Kemas kini pelayan anda dengan rahsia baharu dengan segera.
Cara webhook dihantar#
Wbiztool menghantar satu permintaan POST ke URL anda bagi setiap mesej baharu yang ditemui semasa nombor itu disegerakkan, yang berlaku setiap beberapa minit semasa nombor itu bersambung dan tidak sibuk menghantar mesej.
- Peristiwa:
message_receiveduntuk mesej yang orang hantar ke nombor anda, danmessage_sentuntuk mesej yang dihantar daripadanya (dari telefon, kempen atau API). Hanya peristiwa yang ditandakan dalam Webhook Events dihantar. - Balasan dari peti masuk Unibox biasanya tidak mencetuskan
message_sent, kerana peti masuk sudah mempunyainya semasa penyegerakan berjalan. - Respons: balas dengan sebarang status HTTP
2xxdalam masa 8 saat. - Cubaan semula: tamat masa, ralat sambungan,
429atau respons5xxdicuba semula sehingga 3 kali, selepas 30 saat, 1 minit dan 2 minit. Respons lain, seperti400atau404, tidak dicuba semula. 410 Gone: Wbiztool mengalih keluar URL webhook daripada listener dan berhenti menghantar kepadanya. Mesej masih diimport ke Unibox.- Susunan: permintaan dihantar secara berasingan dan boleh tiba tidak mengikut susunan. Isih mengikut
message.timestampjika susunan penting.
Pengepala#
| Pengepala | Nilai |
|---|---|
Content-Type | application/json |
X-Wbiztool-Event | message_received atau message_sent |
X-Wbiztool-Timestamp | Bila webhook dihantar, dalam ISO 8601 UTC. Sama dengan timestamp dalam badan. |
X-Wbiztool-Webhook-Id | ID listener. Sama dengan webhook_id dalam badan. |
X-Wbiztool-Signature | sha256= diikuti tandatangan. Dihantar setiap kali listener mempunyai rahsia, yang sentiasa berlaku apabila URL ditetapkan. |
Payload#
{
"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"
}
}{
"event": "message_sent",
"timestamp": "2026-09-16T10:33:40.117205+00:00",
"webhook_id": 42,
"whatsapp_client_id": "678",
"whatsapp_phone": "919812345678",
"message": {
"id": "[email protected]_3EB0F9E8D7C6B5A40312",
"type": "chat",
"content": "Yes, it will reach you today by 6 PM.",
"from": "919876543210",
"from_name": "Aman",
"to": "919812345678",
"timestamp": "2026-09-16T10:31:04+00:00",
"whatsapp_timestamp": 1789554664,
"direction": "outgoing",
"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"
}
}{
"event": "message_received",
"timestamp": "2026-09-16T10:36:02.904311+00:00",
"webhook_id": 42,
"whatsapp_client_id": "678",
"whatsapp_phone": "919812345678",
"message": {
"id": "[email protected]_3EB0A7B6C5D4E3F20109",
"type": "image",
"content": "📸 Image",
"from": "919876543210",
"from_name": "Aman",
"to": "919812345678",
"timestamp": "2026-09-16T10:34:51+00:00",
"whatsapp_timestamp": 1789554891,
"direction": "incoming",
"status": "pending",
"is_forwarded": false,
"forwarding_score": 0,
"media": {
"filename": "",
"mimetype": "image/jpeg",
"size": 245760
}
},
"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"
}
}{
"event": "message_received",
"timestamp": "2026-09-16T10:40:15.330187+00:00",
"webhook_id": 42,
"whatsapp_client_id": "678",
"whatsapp_phone": "919812345678",
"message": {
"id": "[email protected][email protected]",
"type": "chat",
"content": "Is the store open on Sunday?",
"from": "120363041234567890",
"from_name": "Acme Loyalty Club",
"to": "919812345678",
"timestamp": "2026-09-16T10:39:02+00:00",
"whatsapp_timestamp": 1789555142,
"direction": "incoming",
"status": "pending",
"is_forwarded": false,
"forwarding_score": 0
},
"contact": {
"whatsapp_id": "[email protected]",
"phone": "120363041234567890",
"lid": null,
"phone_hidden": false,
"name": "Acme Loyalty Club",
"is_group": true,
"is_business": false
},
"organisation": {
"id": "10314",
"name": "Acme Stores"
},
"group": {
"name": "Acme Loyalty Club"
}
}Nombor, ID dan nama di atas ialah contoh.
Medan peringkat atas#
| Medan | Jenis | Penerangan |
|---|---|---|
event | string | message_received atau message_sent. |
timestamp | string | Bila webhook dihantar (ISO 8601, UTC). |
webhook_id | integer | ID listener. |
whatsapp_client_id | string | ID nombor WhatsApp anda, seperti yang ditunjukkan di WhatsApp settings. |
whatsapp_phone | string | Nombor WhatsApp anda. |
message | object | Mesej. Lihat di bawah. |
contact | object | Orang atau kumpulan yang terlibat dalam perbualan. Lihat di bawah. |
organisation | object | id (string) dan name ruang kerja anda. |
group | object | Hanya untuk sembang kumpulan: name, nama kumpulan. |
Medan message#
| Medan | Jenis | Penerangan |
|---|---|---|
id | string | ID WhatsApp bagi mesej itu. Gunakannya untuk mengabaikan pendua. |
type | string | chat untuk teks. Selain itu, jenis WhatsApp, seperti image, video, audio, ptt (nota suara), document, sticker atau location. |
content | string | Teks bagi mesej chat. Bagi media, label sebagai ganti: 📸 Image, 🎥 Video, 🎵 Audio, 🎤 Voice Message, 😊 Sticker, Document: diikuti teks dokumen (Document apabila tiada teks), atau nama jenis dalam huruf besar awal bagi yang lain, seperti Location. Kapsyen tidak disertakan. |
from | string | Sentiasa nombor kenalan (atau ID kumpulan), dalam kedua-dua arah. |
from_name | string | Nama kenalan atau kumpulan. Boleh kosong. |
to | string | Sentiasa nombor WhatsApp anda, dalam kedua-dua arah. |
timestamp | string | Bila mesej dihantar di WhatsApp (ISO 8601, UTC). |
whatsapp_timestamp | integer | Masa yang sama sebagai cap masa Unix dalam saat. |
direction | string | incoming atau outgoing. Gunakan ini, bukan from dan to, untuk menentukan arah. |
status | string | Buat masa ini sentiasa pending. Jangan bergantung padanya untuk status penghantaran atau dibaca. |
is_forwarded | boolean | Sama ada mesej itu dimajukan. |
forwarding_score | integer | Berapa kali ia telah dimajukan. |
media | object | Bagi mesej media apabila butiran tersedia: filename, mimetype dan size dalam bait. Fail itu sendiri tidak disertakan. |
quoted_message_id | string | Hanya apabila mesej itu membalas mesej lain. |
Medan contact#
| Medan | Jenis | Penerangan |
|---|---|---|
whatsapp_id | string | ID WhatsApp, seperti [email protected] untuk individu atau …@g.us untuk kumpulan. |
phone | string | Nombor tanpa +, atau ID kumpulan bagi kumpulan. Kosong apabila WhatsApp menyembunyikan nombor kenalan. |
lid | string atau null | ID privasi WhatsApp untuk kenalan, seperti 62337239240946@lid, apabila WhatsApp menggunakannya. Jika tidak, null. |
phone_hidden | boolean | true apabila WhatsApp tidak berkongsi nombor kenalan. Wbiztool mengisi nombor itu setiap kali WhatsApp menyediakannya. |
name | string | Nama yang Wbiztool ada untuk kenalan, atau nama kumpulan. Boleh kosong. |
is_group | boolean | true untuk sembang kumpulan. |
is_business | boolean | true untuk akaun WhatsApp Business, apabila diketahui. |
Sahkan tandatangan#
Setiap permintaan ditandatangani dengan rahsia listener anda menggunakan HMAC-SHA256. Tandatangan dikira ke atas badan permintaan mentah tepat seperti yang diterima, dan dihantar sebagai sha256= serta ringkasan hex huruf kecil dalam X-Wbiztool-Signature.
Sentiasa kira tandatangan daripada bait mentah sebelum menghuraikan JSON. Menghuraikan dan mengekod semula badan akan mengubahnya (contohnya, aksara bukan Inggeris dan emoji tiba dalam bentuk \uXXXX), dan tandatangan tidak akan sepadan.
// 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);# Flask
import hashlib
import hmac
import json
import os
from flask import Flask, abort, request
app = Flask(__name__)
SECRET = os.environ["WBIZTOOL_WEBHOOK_SECRET"].encode()
@app.post("/wbiztool/webhook")
def wbiztool_webhook():
raw_body = request.get_data() # raw bytes, before parsing
expected = "sha256=" + hmac.new(SECRET, raw_body, hashlib.sha256).hexdigest()
received = request.headers.get("X-Wbiztool-Signature", "")
if not hmac.compare_digest(expected, received):
abort(401)
data = json.loads(raw_body)
if data["event"] == "message_received":
print(f"New message from {data['contact']['phone']}: {data['message']['content']}")
return "", 200<?php
$secret = getenv('WBIZTOOL_WEBHOOK_SECRET');
$rawBody = file_get_contents('php://input');
$expected = 'sha256=' . hash_hmac('sha256', $rawBody, $secret);
$received = $_SERVER['HTTP_X_WBIZTOOL_SIGNATURE'] ?? '';
if (!hash_equals($expected, $received)) {
http_response_code(401);
exit('Invalid signature');
}
$data = json_decode($rawBody, true);
if ($data['event'] === 'message_received') {
error_log('New message from ' . $data['contact']['phone'] . ': ' . $data['message']['content']);
}
http_response_code(200);Tandatangan tidak meliputi pengepala cap masa, jadi ia tidak melindungi daripada permintaan yang dimainkan semula. Jika itu penting, simpan setiap message.id yang telah anda proses dan abaikan ulangan.
Penyelesaian masalah#
| Mesej atau masalah | Apa yang perlu dilakukan |
|---|---|
| Unibox Add-on Required apabila anda mengklik Add New Listener | Ruang kerja anda tiada tambahan Unibox. Belinya di bawah Available Add-ons di Billing & Plans dalam papan pemuka. |
You have reached your unibox numbers limit | Padam listener yang tidak lagi diperlukan, atau tingkatkan kuantiti tambahan. |
| No available WhatsApp numbers | Sambung nombor lain, atau nombor itu sudah menjadi listener. |
This WhatsApp number is already a listener | Edit kad sedia ada sebaliknya. |
Invalid WhatsApp client | Nombor itu terputus. Sambungkannya semula di WhatsApp settings dan muat semula halaman. |
Ralat yang menyebut value too long semasa menyimpan | URL webhook lebih panjang daripada 100 aksara. Gunakan URL yang lebih pendek. |
| Tiada webhook tiba | Pastikan listener Active, nombor bersambung, jenis peristiwa ditandakan, dan URL anda ialah https awam dengan sijil yang sah. Mesej hanya dihantar selepas penyegerakan seterusnya, beberapa minit kemudian. |
| Sesetengah webhook hilang | Pelayan anda memulangkan status 4xx, atau terus gagal untuk kesemua 3 cubaan semula. Semak log pelayan anda pada masa mesej yang hilang itu. |
| URL webhook hilang daripada listener | Pelayan anda menjawab 410 Gone, jadi Wbiztool berhenti menghantar kepadanya. Tambah URL semula dalam Edit Listener. |
| Tandatangan tidak sepadan | Gunakan badan mentah, bukan JSON yang dikod semula, dan rahsia semasa. Menjana semula rahsia menggantikannya. Semasa Zap Zapier menggunakan nombor itu, permintaan pergi ke Zapier dengan rahsia Zapier. |
| Last Activity: menyatakan Never | Nombor itu belum disemak. Ia mesti bersambung dan tidak sibuk menghantar mesej. |
