أدلة المنتج
Webhooks الرسائل الواردة (المستمعون)
يربط المستمع أحد أرقام 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: رابط عام (استخدم
https) لا يتجاوز 100 حرف ويقبل طلباتPOSTبجسم JSON.
أضف مستمعًا#
افتح المشغّلات الواردة
في الشريط الجانبي، افتح 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 من النوع
2xxخلال 8 ثوانٍ. - إعادة المحاولة: تُعاد المحاولة عند انتهاء المهلة أو خطأ الاتصال أو الاستجابة
429أو5xxحتى 3 مرات، بعد 30 ثانية ثم دقيقة ثم دقيقتين. أما الاستجابات الأخرى، مثل400أو404، فلا تُعاد محاولتها. 410 Gone: تزيل Wbiztool رابط webhook من المستمع وتتوقف عن الإرسال إليه. تظل الرسائل تُستورد إلى Unibox.- الترتيب: تُرسل الطلبات بشكل مستقل وقد تصل بغير ترتيب. رتّب حسب
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= متبوعًا بالتوقيع. يُرسل كلما كان للمستمع سر، وهذا هو الحال دائمًا عند ضبط رابط. |
الحمولة#
{
"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"
}
}الأرقام والمعرّفات والأسماء أعلاه أمثلة.
الحقول على المستوى الأعلى#
| الحقل | النوع | الوصف |
|---|---|---|
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 (نص) و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 | الرقم دون +، أو معرّف المجموعة للمجموعات. يكون فارغًا عندما يخفي WhatsApp رقم جهة الاتصال. |
lid | string أو null | معرّف الخصوصية الذي يستخدمه WhatsApp لجهة الاتصال، مثل 62337239240946@lid، عندما يستخدم WhatsApp معرّفًا كهذا. وإلا null. |
phone_hidden | boolean | true عندما لا يشارك WhatsApp رقم جهة الاتصال. تملأ Wbiztool الرقم كلما أتاحه WhatsApp. |
name | string | الاسم المسجّل لجهة الاتصال لدى Wbiztool، أو اسم المجموعة. قد يكون فارغًا. |
is_group | boolean | true لدردشات المجموعات. |
is_business | boolean | true لحسابات WhatsApp Business، عندما يكون ذلك معروفًا. |
تحقّق من التوقيع#
يُوقَّع كل طلب بسر المستمع باستخدام HMAC-SHA256. يُحسب التوقيع على جسم الطلب الخام تمامًا كما استُلم، ويُرسل في X-Wbiztool-Signature بالشكل sha256= متبوعًا بالملخص الست عشري بأحرف صغيرة.
احسب التوقيع دائمًا من البايتات الخام قبل تحليل 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 مفقودة | أعاد خادمك حالة 4xx، أو استمر في الفشل خلال المحاولات الثلاث كلها. تحقق من سجلات خادمك في وقت الرسالة المفقودة. |
| اختفى رابط webhook من المستمع | أجاب خادمك بـ 410 Gone، فتوقفت Wbiztool عن الإرسال إليه. أضف الرابط مرة أخرى في Edit Listener. |
| التوقيع لا يتطابق | استخدم الجسم الخام، لا JSON معاد ترميزه، والسر الحالي. إعادة إنشاء السر تستبدله. ما دام Zap في Zapier يستخدم الرقم، تذهب الطلبات إلى Zapier مع سر Zapier. |
| يعرض Last Activity: القيمة Never | لم يُفحص الرقم بعد. يجب أن يكون متصلًا وغير مشغول بإرسال الرسائل. |
