מדריכי מוצר
Webhooks להודעות נכנסות (מאזינים)
מאזין (listener) מחבר את אחד ממספרי ה-WhatsApp שלכם ל-Unibox ויכול לשלוח לשרת שלכם Webhook על הודעות נכנסות. במרכז הבקרה מנהלים את המאזינים בדף Incoming Triggers (טריגרים נכנסים). ברגע שמספר הופך למאזין, הצ'אטים שלו מסונכרנים אל תיבת הדואר הנכנס של Unibox, ואם תוסיפו כתובת Webhook, המערכת של Wbiztool תשלח כל הודעה חדשה לשרת שלכם. השתמשו ב-Webhooks כדי לתעד שיחות במערכת CRM, להתריע לצוות או לבנות מענה אוטומטי.
לפני שמתחילים#
- חבילת התוספת Unibox. היא עולה 20$ לחודש או 200$ לשנה לכל מספר WhatsApp, ומספר המאזינים שאפשר להגדיר שווה לכמות של חבילת התוספת. רכשו אותה תחת Available Add-ons (חבילות תוספת זמינות) בדף Billing & Plans (חיובים ותוכניות) בתוך מרכז הבקרה. בלעדיה, הדף Incoming Triggers עדיין נפתח, אבל לחיצה על Add New Listener (הוספת מאזין חדש) מציגה Unibox Add-on Required (נדרשת חבילת התוספת Unibox) עם הכפתור Subscribe to Unibox Add-on (הרשמה לחבילת התוספת Unibox).
- מספר WhatsApp מחובר בדף WhatsApp settings (הגדרות WhatsApp). אפשר להוסיף רק מספרים מחוברים שעדיין אינם מאזינים.
- עליכם להיות בעלים או עורכים בסביבת העבודה.
- עבור Webhooks: כתובת URL ציבורית (השתמשו ב-
https) באורך של 100 תווים לכל היותר, שמקבלת בקשותPOSTעם גוף JSON.
הוספת מאזין#
פתיחת Incoming Triggers
בסרגל הצד פתחו את Unibox ולחצו על Incoming Triggers, או עברו אל Incoming Triggers.
התחלת מאזין חדש
לחצו על הכרטיס Add New Listener.
בחירת המספר
בחרו אותו ב-Select WhatsApp Number (בחירת מספר WhatsApp). אם ברשימה מופיע No available WhatsApp numbers (אין מספרי WhatsApp זמינים), כל מספר מחובר כבר משמש כמאזין, או שאין אף מספר מחובר.
הוספת Webhook (אופציונלי)
הזינו את Webhook URL (Optional) (כתובת Webhook, אופציונלי). אחרי שמקלידים כתובת, מופיע Webhook Events (אירועי Webhook): השאירו מסומנים את Incoming Messages (הודעות נכנסות), את Outgoing Messages (הודעות יוצאות) או את שניהם. אפשר להוסיף או לשנות את הכתובת מאוחר יותר.
שמירה
לחצו על Add Listener (הוספת מאזין). המאזין מופיע ככרטיס עם הסטטוס Active (פעיל). אם הזנתם כתובת, נוצר עבורה סוד Webhook.
ניהול מאזינים#
כל כרטיס מציג את המספר, את הסטטוס שלו, את Webhook URL: (כתובת Webhook, או Not configured – לא מוגדרת), את Last Activity: (פעילות אחרונה: מתי נבדקו לאחרונה הודעות במספר, או Never – אף פעם) ואת Webhook Secret: (סוד Webhook), שמוסתר עד שלוחצים על כפתור העין.
פתחו את התפריט ⋮ בכרטיס כדי:
| פעולה | מה קורה |
|---|---|
| Edit (עריכה) | שינוי כתובת ה-Webhook, אירועי ה-Webhook או הסוד. אי אפשר לשנות את המספר. |
| Disable (השבתה) / Enable (הפעלה) | השבתה מעבירה את המאזין לסטטוס Inactive (לא פעיל): המספר מפסיק להסתנכרן לתיבת הדואר הנכנס ולא נשלחים Webhooks. הפעלה מחזירה אותו לסטטוס Active. |
| Delete (מחיקה) | מסירה את המאזין אחרי אישור. שיחות שכבר נמצאות בתיבת הדואר הנכנס נשארות. הוספה מחדש של אותו מספר בהמשך משחזרת את המאזין. אם תזינו כתובת Webhook כשאתם מוסיפים אותו מחדש, המאזין שומר את סוד ה-Webhook הקודם שלו, אם היה לו, במקום לקבל סוד חדש. |
סטטוסים של מאזין#
| סטטוס | משמעות |
|---|---|
| Active | הודעות מסתנכרנות ו-Webhooks נשלחים כל עוד המספר מחובר. |
| Pending (ממתין) | המספר לא היה מחובר כשהמאזין נוצר, למשל על ידי Zapier. לחצו על Enable אחרי שהמספר מתחבר. |
| Inactive | מושבת. שום דבר לא מסתנכרן ולא נשלחים Webhooks. |
נתונים#
| כרטיס | מה הוא מציג |
|---|---|
| Active Listeners (מאזינים פעילים) | כל המאזינים בדף, כולל מושבתים. |
| Available Numbers (מספרים זמינים) | מספרים מחוברים שעדיין אינם מאזינים. מספרים שמחקתם את המאזין שלהם עדיין נספרים כאן כתפוסים, כך שהערך עשוי להיות נמוך ממה שאפשר להוסיף בפועל. |
| Total Limit (מגבלה כוללת) | כמה מאזינים חבילת התוספת Unibox שלכם מתירה. |
| Messages Today (הודעות היום) | עדיין לא נמדד; תמיד מציג 0. |
שינוי כתובת ה-Webhook או האירועים#
פתיחת המאזין
לחצו על ⋮ בכרטיס, ולאחר מכן על Edit.
עדכון ההגדרות
שנו את Webhook URL (Optional) ואת Webhook Events. מחקו את הכתובת כדי להפסיק Webhooks עבור המספר הזה: גם הסוד שלו נמחק, וסוד חדש ייווצר אם תוסיפו כתובת שוב.
שמירה
לחצו על Update Listener (עדכון מאזין).
יצירת סוד חדש#
בחלון Edit Listener (עריכת מאזין) לחצו על כפתור הרענון שליד Webhook Secret ואשרו. הסוד החדש נשמר מיד, גם אם תסגרו אחר כך את החלון בלי ללחוץ על Update Listener, ומאותו רגע הבקשות נחתמות איתו. עדכנו מיד את השרת שלכם עם הסוד החדש.
איך Webhooks נשלחים#
המערכת של Wbiztool שולחת בקשת POST אחת לכתובת שלכם עבור כל הודעה חדשה שנמצאת כשהמספר מסתנכרן. הסנכרון מתבצע כל כמה דקות, כל עוד המספר מחובר ואינו עסוק בשליחת הודעות.
- אירועים: האירוע
message_receivedעבור הודעות שאנשים שולחים למספר שלכם, והאירועmessage_sentעבור הודעות שנשלחות ממנו (מהטלפון, מקמפיינים או מה-API). נשלחים רק האירועים שמסומנים ב-Webhook Events. - תשובות מתיבת הדואר הנכנס של Unibox בדרך כלל לא מפעילות את
message_sent, כי הן כבר נמצאות בתיבה כשהסנכרון רץ. - תגובה: השיבו עם HTTP
200תוך 8 שניות. כל תגובה אחרת או חריגה מהזמן נחשבות למסירה שנכשלה. - אין ניסיונות חוזרים: כל הודעה נשלחת פעם אחת. אם השרת שלכם לא זמין, ה-Webhook הזה אובד.
- סדר: הבקשות נשלחות בנפרד זו מזו ועלולות להגיע שלא לפי הסדר. מיינו לפי
message.timestampאם הסדר חשוב.
כותרות#
| כותרת | ערך |
|---|---|
Content-Type | application/json |
X-Wbiztool-Event | message_received או message_sent |
X-Wbiztool-Timestamp | מתי ה-Webhook נשלח, בפורמט ISO 8601 ב-UTC. זהה ל-timestamp בגוף הבקשה. |
X-Wbiztool-Webhook-Id | המזהה של המאזין. זהה ל-webhook_id בגוף הבקשה. |
X-Wbiztool-Signature | הקידומת sha256= ואחריה החתימה. נשלחת בכל פעם שלמאזין יש סוד, וזה תמיד המצב כשמוגדרת כתובת. |
גוף ה-Webhook (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",
"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",
"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",
"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",
"name": "Acme Loyalty Club",
"is_group": true,
"is_business": false
},
"organisation": {
"id": "10314",
"name": "Acme Stores"
},
"group": {
"name": "Acme Loyalty Club"
}
}המספרים, המזהים והשמות שלמעלה הם דוגמאות בלבד.
שדות ברמה העליונה#
| שדה | סוג | תיאור |
|---|---|---|
event | string | message_received או message_sent. |
timestamp | string | מתי ה-Webhook נשלח (ISO 8601, UTC). |
webhook_id | integer | המזהה של המאזין. |
whatsapp_client_id | string | המזהה של מספר ה-WhatsApp שלכם, כפי שהוא מוצג בדף WhatsApp settings. |
whatsapp_phone | string | מספר ה-WhatsApp שלכם. |
message | object | ההודעה. ראו בהמשך. |
contact | object | האדם או הקבוצה שאיתם מתנהלת השיחה. ראו בהמשך. |
organisation | object | השדות id (string) ו-name של סביבת העבודה שלכם. |
group | object | רק בצ'אטים קבוצתיים: name, שם הקבוצה. |
השדות של message#
| שדה | סוג | תיאור |
|---|---|---|
id | string | המזהה של WhatsApp להודעה. השתמשו בו כדי להתעלם מכפילויות. |
type | string | הערך chat עבור טקסט. אחרת, הסוג של WhatsApp, כמו image, video, audio, ptt (הודעה קולית), document, sticker או location. |
content | string | הטקסט בהודעות chat. במדיה מופיעה במקומו תווית: 📸 Image, 🎥 Video, 🎵 Audio, 🎤 Voice Message, 😊 Sticker, Document: ואחריו הטקסט של המסמך (Document כשאין טקסט), או שם הסוג באות ראשונה גדולה בכל מקרה אחר, כמו Location. כיתובים לא נכללים. |
from | string | תמיד המספר של איש הקשר (או המזהה של הקבוצה), בשני הכיוונים. |
from_name | string | השם של איש הקשר או של הקבוצה. יכול להיות ריק. |
to | string | תמיד מספר ה-WhatsApp שלכם, בשני הכיוונים. |
timestamp | string | מתי ההודעה נשלחה ב-WhatsApp (ISO 8601, UTC). |
whatsapp_timestamp | integer | אותו זמן כחותמת זמן Unix בשניות. |
direction | string | incoming או outgoing. השתמשו בשדה הזה, ולא ב-from וב-to, כדי לזהות את הכיוון. |
status | string | כרגע תמיד pending. אל תסתמכו עליו לסטטוס מסירה או קריאה. |
is_forwarded | boolean | האם ההודעה הועברה. |
forwarding_score | integer | כמה פעמים היא הועברה. |
media | object | בהודעות מדיה, כשהפרטים זמינים: filename, mimetype ו-size בבייטים. הקובץ עצמו לא נכלל. |
quoted_message_id | string | רק כשההודעה היא תשובה להודעה אחרת. |
השדות של contact#
| שדה | סוג | תיאור |
|---|---|---|
whatsapp_id | string | מזהה ה-WhatsApp, כמו [email protected] עבור אדם או …@g.us עבור קבוצה. |
phone | string | המספר בלי +, או המזהה של הקבוצה עבור קבוצות. |
name | string | השם ש-Wbiztool שמרה לאיש הקשר, או שם הקבוצה. יכול להיות ריק. |
is_group | boolean | הערך true עבור צ'אטים קבוצתיים. |
is_business | boolean | הערך true עבור חשבונות WhatsApp Business, כשהדבר ידוע. |
אימות החתימה#
כל בקשה נחתמת בסוד של המאזין שלכם באמצעות HMAC-SHA256. החתימה מחושבת על גוף הבקשה הגולמי, בדיוק כפי שהתקבל, ונשלחת בכותרת X-Wbiztool-Signature כ-sha256= ואחריו ה-digest ההקסדצימלי באותיות קטנות.
חשבו תמיד את החתימה מהבייטים הגולמיים לפני פענוח ה-JSON. פענוח הגוף וקידודו מחדש משנים אותו (למשל, תווים שאינם באנגלית ואימוג'י מגיעים בצורה מוברחת כ-\uXXXX), והחתימה לא תתאים.
// 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);החתימה לא מכסה את כותרת חותמת הזמן, ולכן היא לא מגינה מפני שליחה חוזרת (replay) של בקשה. אם זה חשוב לכם, שמרו כל message.id שכבר עיבדתם והתעלמו מחזרות.
פתרון בעיות#
| הודעה או בעיה | מה לעשות |
|---|---|
| Unibox Add-on Required כשלוחצים על Add New Listener | לסביבת העבודה שלכם אין את חבילת התוספת Unibox. רכשו אותה תחת Available Add-ons בדף Billing & Plans בתוך מרכז הבקרה. |
You have reached your unibox numbers limit | מחקו מאזין שאינכם צריכים עוד, או הגדילו את הכמות של חבילת התוספת. |
| No available WhatsApp numbers | חברו מספר נוסף, או שהמספר כבר משמש כמאזין. |
This WhatsApp number is already a listener | ערכו במקום זאת את הכרטיס הקיים. |
Invalid WhatsApp client | המספר התנתק. חברו אותו מחדש בדף WhatsApp settings וטענו את הדף מחדש. |
שגיאה שמזכירה value too long בזמן שמירה | כתובת ה-Webhook ארוכה מ-100 תווים. השתמשו בכתובת קצרה יותר. |
| לא מגיעים Webhooks | ודאו שהמאזין Active, שהמספר מחובר, שסוג האירוע מסומן ושהכתובת שלכם היא https ציבורית עם תעודה תקפה. ההודעות נשלחות רק אחרי הסנכרון הבא, כמה דקות לאחר מכן. |
| חלק מה-Webhooks חסרים | השרת שלכם החזיר משהו שאינו 200, לקח לו יותר מ-8 שניות להגיב או שלא היה זמין. מסירות שנכשלו לא נשלחות שוב. |
| החתימה לא תואמת | השתמשו בגוף הגולמי, ולא ב-JSON שקודד מחדש, ובסוד הנוכחי. יצירת סוד חדש, או חיבור Zapier, מחליפים אותו. |
| הנתון Last Activity: מציג Never | המספר עדיין לא נבדק. הוא חייב להיות מחובר ולא עסוק בשליחת הודעות. |
