استقبال الويب هوك
يرسل الويب هوك الأحداث إلى خادمك لحظة وقوعها: عميل يراسلك، أو رسالة سُلّمت، أو جهة اتصال ألغت اشتراكها، أو محادثة تنتظر موظفًا، أو حملة انتهت. تضيف نقطة استقبال (رابطًا على خادمك)، وتختار أحداثها، ونرسل كل حدث بطلب POST بصيغة JSON.
أضف نقطة استقبال#
من البوابة (المطورون ← الويب هوك) أو عبر الواجهة (POST /webhook_endpoints). لكل نقطة:
- رابط
https://عام؛ - الأحداث التي تستقبلها: أنواع مفردة، أو مجموعات كاملة مثل
contact.*، أو*لكل الأحداث؛ - وضع: نقاط الاختبار تستقبل أحداث وضع الاختبار فقط، والنقاط الحية تستقبل الأحداث الحية فقط؛
- سر توقيع خاص بها (
whsec_…) يظهر مرة واحدة.
يمكن لمساحة العمل أن تملك حتى 10 نقاط استقبال.
مجموعات الأحداث#
| المجموعة | الأحداث | data.object |
|---|---|---|
message.* | received وsent وdelivered وread وfailed | رسالة |
contact.* | created وupdated وdeleted وopted_out وopted_in | جهة اتصال |
conversation.* | created وneeds_agent وassigned وresolved وreopened | محادثة |
template.* | status_changed | قالب |
campaign.* | started وpaused وresumed وcompleted وfailed وcancelled | حملة |
flow.* | run.started وrun.handed_off وrun.completed وrun.expired وresponse | تشغيل تدفق / رد نموذج |
تجد كل حدث مع مثاله في أنواع الأحداث. تنطلق أحداث الرسائل والقوالب لحظة حدوث التغيير، أما أحداث جهات الاتصال والمحادثات والحملات والتدفقات فتنتظر نحو ثلاث ثوانٍ لتحمل العنصر مكتملًا، وتصبح عدة تغييرات سريعة على العنصر نفسه حدثًا واحدًا.
ما الذي يصل#
{
"id": "evt_01j9x7r2m3n4p5q6r7s8t9v0w1",
"object": "event",
"type": "message.delivered",
"version": "2",
"created_at": "2026-10-01T09:30:04Z",
"livemode": true,
"workspace_id": "ws_12",
"data": {
"object": { "id": "msg_48213", "object": "message", "status": "delivered", "reference": "order-10482", "...": "..." },
"previous_attributes": { "status": "sent" }
}
}data.object هو نفسه ما تُرجعه GET /messages/{id}، فيكفيك محلل واحد للحالتين. ومع كل طلب تصل هذه الترويسات:
| الترويسة | القيمة |
|---|---|
webhook-id | معرّف الحدث، ثابت في كل إعادة محاولة: استخدمه لتجاهل التكرار. |
webhook-timestamp | وقت توقيع هذه المحاولة بثواني Unix |
webhook-signature | v1,<التوقيع بصيغة base64> (اثنان تفصل بينهما مسافة أثناء تدوير السر) |
X-Automize-Event | نوع الحدث، لتوجيهه دون تحليل الجسم |
تحقّق من كل توقيع#
يستطيع أي أحد إرسال طلب إلى رابطك. قبل أن تثق بأي طلب تحقق من أنه موقّع بسر نقطة الاستقبال. نحن نتبع معيار Standard Webhooks، لذا تتحقق مكتبات standardwebhooks الرسمية (Node وPython وPHP وGo وRuby وJava وC# وRust) من طلباتنا كما هي. أو تحقق يدويًا:
- كوّن المحتوى الموقّع:
{webhook-id}.{webhook-timestamp}.{الجسم الخام}. استخدم بايتات الجسم الخام قبل أي تحليل JSON. - احسب HMAC-SHA256 عليه بالسر: فك ترميز base64 للجزء الذي بعد
whsec_واستخدم البايتات مفتاحًا. - رمّز الناتج بـ base64 وقارنه بزمن ثابت مع كل قيمة
v1,…فيwebhook-signature. - ارفض أي طابع زمني يبعد أكثر من 5 دقائق عن الآن، لمنع إعادة الإرسال الخبيثة.
import crypto from "node:crypto";
// Use the RAW request body (a Buffer or string), before any JSON parsing.
export function verifyWebhook(rawBody, headers, secret = process.env.WEBHOOK_SECRET) {
const id = headers["webhook-id"];
const timestamp = headers["webhook-timestamp"];
const signatures = headers["webhook-signature"] ?? "";
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false; // replay guard
const key = Buffer.from(secret.replace(/^whsec_/, ""), "base64");
const expected = crypto
.createHmac("sha256", key)
.update(`${id}.${timestamp}.${rawBody}`)
.digest("base64");
// During a secret rotation there are two: "v1,abc v1,def"
return signatures.split(" ").some((sig) => {
const [, value = ""] = sig.split(",");
return value.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(value), Buffer.from(expected));
});
}أجب بسرعة#
أجب بـ 2xx خلال 15 ثانية لتأكيد الاستلام. ونفّذ العمل الفعلي (الكتابة في قاعدة البيانات، استدعاء خدمات أخرى) بعد الرد، في طابور مثلًا.
إعادة المحاولة#
أي رد غير 2xx (بما فيه انتهاء المهلة و4xx) تُعاد محاولته بعد نحو 30 ثانية، ثم دقيقتين، ثم 10 دقائق، ثم ساعة، ثم 6 ساعات، ثم 24 ساعة، مع تفاوت بسيط. بعدها تُعلَّم العملية كمنتهية. يمكنك إعادة إرسال أي عملية من البوابة أو عبر POST /webhook_deliveries/{id}/retry.
- أجب بـ
410 Goneلتطلب منا التوقف، فتُعطَّل النقطة. - النقطة التي تفشل كل عمليات إرسالها لمدة 3 أيام تُعطَّل تلقائيًا ويُبلَّغ مالك مساحة العمل. أعد تفعيلها بعد إصلاحها.
- قد تصل الأحداث بغير ترتيبها وأكثر من مرة. استخدم
webhook-idلتجاهل التكرار، وupdated_atفي العنصر (أوprevious_attributes) لتحتفظ بأحدث حالة فقط.
تدوير السر#
دوّر السر من البوابة أو عبر POST /webhook_endpoints/{id}/rotate_secret. لمدة 24 ساعة يحمل كل حدث توقيعين، القديم والجديد، لتنشر السر الجديد دون أن يفوتك أي حدث.