Webhooks
يرسل الـ webhook أحداث الأعمال (Business Events) الخاصة بمتجرك إلى عنوان على خادمك لحظة وقوعها: طلب جديد، طلب مؤكَّد، تسليم إلى شركة توصيل، توصيل ناجح. يُرسَل كل حدث بطلب POST بصيغة JSON، موقَّعًا وفق مواصفة Standard Webhooks، وتُعاد المحاولة إلى أن يقبله خادمك.
أما شركات التوصيل التي تبلّغ متجرك عن التسليمات فهي الاتجاه الآخر: اقرأ Webhooks شركات التوصيل.
إضافة webhook
في لوحة التحكم افتح التكاملات من القائمة الجانبية واختر إضافة webhook، وأعطه اسمًا وعنوان URL لخادمك والأحداث التي يستقبلها. وعبر الـ API، POST /api/event-consumers بصلاحية integrations:manage (وتعرض integrations:read الـ webhooks وعمليات تسليمها):
Code
يحتوي الرد على الـ webhook ومفتاح التوقيع الخاص به، whsec_…. لا يُعرض إلا هذه المرة: احفظه ضمن أسرار خادمك. وكل رد بعده يعرضه مُقنَّعًا.
- يجب أن يكون العنوان
https، عامًا على الإنترنت (لا عنوان خاصًا أو محليًا أو محجوزًا)، بلا اسم مستخدم ولا كلمة مرور. - للمتجر 10 webhooks على الأكثر.
- يستقبل الـ webhook الأحداث المسجَّلة بعد إضافته. ولإرسال أحداث أقدم إليه استعمل إعادة الإرسال (Replay، انظر أدناه).
يسمّي الاشتراك أنواع الأحداث بدقة (order.confirmed)، أو حسب الموضوع (order.*، shipment.*)، أو كلها (*). والموضوع أو * يشمل أيضًا الأنواع التي تُضاف إلى الكتالوج لاحقًا.
ما يستقبله خادمك
كل إرسال هو طلب POST واحد إلى عنوانك:
| الترويسة | القيمة |
|---|---|
content-type | application/json |
user-agent | CodFlow-Webhooks/1 |
webhook-id | معرّف الحدث. هو نفسه في كل محاولة وكل إعادة إرسال. |
webhook-timestamp | وقت إرسال هذه المحاولة، بثواني Unix. |
webhook-signature | v1,<signature>، واحد لكل مفتاح توقيع، تفصل بينها مسافات. |
جسم الطلب هو حدث الأعمال نفسه، تمامًا كما تعيده API سجل الأحداث:
Code
| الحقل | معناه |
|---|---|
id | المعرّف الفريد للحدث. به تتعرّف على حدث عالجته من قبل. |
sequence | موضعه في سجل أحداث المتجر: الحدث الأحدث رقمه أكبر. |
type، version | نوع الحدث ونسخة data الخاصة به. |
subject | موضوع الحدث: طلب أو شحنة. |
orderId | الطلب المعني. |
occurredAt | متى وقع: قد تبلّغ شركة التوصيل عن تسليم بعد ساعات. |
recordedAt | متى سجّله المتجر. |
actor، origin | من تسبّب فيه (الفريق، وكيل ذكاء اصطناعي، الزبون، شركة التوصيل، النظام) وعبر ماذا (لوحة التحكم، الـ API، واجهة المتجر، webhook شركة التوصيل…). |
data | الطلب، والشحنة في أحداث التوصيل، كما كانا لحظة وقوعه. |
المبالغ نصوص عشرية مع عملتها: { "amount": "9000.00", "currency": "DZD" }. ولا يتجاوز أي حدث 64 كيلوبايت.
التحقق من التوقيع
تحقّق من كل طلب قبل أن تتصرف بناءً عليه. التوقيع هو HMAC-SHA256 بترميز base64 للنص <webhook-id>.<webhook-timestamp>.<الجسم الخام>، ومفتاحه البايتات التي يرمّزها مفتاح التوقيع: الجزء الذي بعد whsec_ بعد فكّ ترميز base64.
- اقرأ الجسم الخام كما وصل. تحليل الـ JSON ثم إعادة كتابته يغيّر البايتات فلا يطابق التوقيع.
- ارفض أي
webhook-timestampيبعد أكثر من خمس دقائق عن ساعتك، حتى لا يُعاد إرسال طلب مُعترَض لاحقًا. - اقبل الطلب إذا طابق أحدُ توقيعات
v1,المفصولة بمسافات، بمقارنة ثابتة الزمن.
Node.js
Code
مرّر الجسم الخام نصًّا، مثلًا عبر express.text({ type: "application/json" }).
PHP
Code
الجسم الخام هو file_get_contents('php://input') (وفي Laravel $request->getContent())؛ ومرّر الترويسات بأسماء بأحرف صغيرة.
Python
Code
الجسم الخام هو request.get_data() في Flask، أو await request.body() في FastAPI.
وتتحقق أي مكتبة Standard Webhooks من هذه الطلبات أيضًا، مثل new Webhook(secret).verify(rawBody, headers) مع حزمة standardwebhooks.
تغيير مفتاح التوقيع
تغيير مفتاح التوقيع في لوحة التحكم، أو POST /api/event-consumers/{id}/rotate-secret، يعطي مفتاحًا جديدًا مرة واحدة. ولمدة 24 ساعة يحمل كل طلب توقيعًا بكل مفتاح، فانقل خادمك إلى الجديد خلالها ولن يُرفض شيء. بعدها لا يوقّع إلا المفتاح الجديد.
أجب بسرعة
جوابك يحدّد ما يحدث بعد ذلك:
| يجيب خادمك | ما يفعله المتجر |
|---|---|
أي 2xx خلال 15 ثانية | تمّ التسليم. |
410 Gone | يوقف هذا الـ webhook ولا يرسل إليه شيئًا حتى تعيد تشغيله. |
| غير ذلك: حالة أخرى، أو إعادة توجيه، أو لا جواب في الوقت، أو تعذّر الاتصال | يعيد المحاولة لاحقًا وفق الجدول أدناه. |
أجب بـ 2xx بمجرد حفظ الحدث، ثم أنجز العمل. لا تُتَّبع إعادات التوجيه: أعطِ العنوان النهائي. وتُحترَم ترويسة Retry-After في الرفض، حتى يوم واحد.
إعادة المحاولة والتكرار والترتيب
يُحاوَل تسليم كل إرسال 8 مرات. تنطلق المحاولة الأولى بعد ثوانٍ من الحدث، وكل فشل ينتظر قبل التالية:
| المحاولة | الانتظار بعد السابقة |
|---|---|
| 1 | لا انتظار: بعد ثوانٍ من الحدث |
| 2 | 5 دقائق |
| 3 | 30 دقيقة |
| 4 | ساعتان |
| 5 | 6 ساعات |
| 6 | 12 ساعة |
| 7 | 24 ساعة |
| 8 | 24 ساعة |
بعد آخر فشل يصير الإرسال متخلًّى عنه: يبقى في لوحة التحكم حيث يمكنك إعادة محاولته. تجري إعادات المحاولة كل خمس دقائق، فقد يطول الانتظار حتى خمس دقائق إضافية. والـ webhook الذي تفشل كل محاولاته طوال ثلاثة أيام يُوقَف؛ أعد تشغيله من لوحة التحكم بعد إصلاح خادمك.
التسليم مرة واحدة على الأقل وبلا ترتيب مضمون:
- قد تستقبل الحدث مرتين. احفظ
webhook-idما عالجته وتجاهله في المرة الثانية. - قد يصل حدثان بغير ترتيبهما. رتّبهما حسب
sequence، أو حسبoccurredAtلوقت وقوعهما.
الإرسال من جديد
من التكاملات ← الإرسالات في لوحة التحكم، أو عبر الـ API:
- أعد المحاولة لإرسال واحد:
POST /api/event-deliveries/{id}/retry. - أعد الإرسال… لمجال من الأحداث:
POST /api/event-consumers/{id}/replayمعfromSequenceوtoSequence، بحد أقصى 1000 حدث في كل مرة. وتُشمل الأحداث المسجَّلة أثناء توقف الـ webhook.
الحدث المُرسَل من جديد يحتفظ بمعرّفه، فيتعرّف عليه خادمك.
الأحداث التجريبية
إرسال حدث تجريبي في لوحة التحكم، أو POST /api/event-consumers/{id}/test مع type اختياري، يرسل فورًا إلى خادمك مثالًا لنوع حدث، موقَّعًا كغيره، ويعرض ما أجاب به خادمك. للحدث التجريبي sequence يساوي 0 وid يبدأ بـ test_؛ وهو ليس في سجل أحداثك.
أنواع الأحداث
| نوع الحدث | متى |
|---|---|
order.created | تم تقديم طلب: في المتجر، أو في لوحة التحكم، أو عبر الـ API، أو بواسطة وكيل ذكاء اصطناعي. |
order.updated | عُدّل زبون الطلب أو وجهته أو ملاحظاته. |
order.confirmed | أكّد الزبون الطلب، عادةً عبر الهاتف. |
order.unreachable | تعذّر الوصول إلى الزبون لتأكيد الطلب. |
order.preparing | الطلب قيد التحضير. |
order.ready | الطلب مغلَّف وجاهز للتسليم إلى التوصيل. |
order.cancelled | أُلغي الطلب. |
order.line_returned | رُفضت وحدات من سطر في الطلب عند الباب وعادت. |
order.deleted | حُذف الطلب؛ ويحمله الحدث كما كان. |
shipment.handed_off | سُلّم الطلب إلى شركة توصيل أو إلى أحد سائقي المتجر. |
shipment.out_for_delivery | خرج الطرد نحو الزبون. |
shipment.delivery_failed | فشلت محاولة لتوصيل الطرد. |
shipment.delivered | سُلّم الطرد ودُفع ثمنه عند الاستلام. |
shipment.return_started | الطرد في طريق العودة إلى المتجر. |
shipment.returned | عاد الطرد إلى المتجر. |
shipment.cancelled | أُلغيت الشحنة قبل توصيلها. |
shipment.voided | أُلغي التسليم: الطلب لم يعد لدى التوصيل. |
المخطط الكامل لكل نوع في مرجع الـ API تحت Webhooks.
انظر أيضًا
- المصادقة لمفاتيح الـ API وصلاحيتي
integrations:readوintegrations:manage - الأخطاء لصيغة الأخطاء
- Webhooks شركات التوصيل للتسليمات التي تبلّغ عنها شركات التوصيل