لمن: المالكون، العمليات
أين تجدها: الإعداد > التكاملات > خطافات الويب، مفاتيح API
متاحة في: لوحة التحكم على الويب · كل الدول
هذا الدليل للمطور الذي يستقبل طلبات المطعم من زيدا في نظامه الخاص، كنظام تخطيط الموارد أو نقطة البيع أو جدول البيانات. ولإرسال الطلبات إلى زيدا، انظر اربط نظامك الخاص: واجهة الطلبات وخطافات الويب.
أضف خطاف ويب
- افتح الإعداد > التكاملات > خطافات الويب في لوحة تحكم زيدا.
- اضغط إضافة خطاف وأدخل رابطك.
- اختر الأحداث التي تريدها.
- اختر أجزاء الطلب التي ترسلها زيدا (انظر «أجزاء الطلب»).
- اضغط حفظ، ثم انسخ سر الخطاف. ولا تعرضه زيدا إلا مرة واحدة، فاحفظه على خادمك وحده.
يجب أن يكون أول الرابط https://، وأن يصل إلى عنوان عام، وألا يحمل اسم مستخدم ولا كلمة مرور. وترفض زيدا العنوان الخاص أو الداخلي حين تحفظه. ولا تتبع زيدا عمليات التحويل (redirect).
ومن الصفحة نفسها يستطيع المتجر أن يرسل حدثًا تجريبيًا، ويقرأ سجل الإرسال لآخر 30 يومًا، ويعيد إرسال عملية سابقة، وينشئ سرًا جديدًا (فيتوقف القديم في الحال)، ويوقف الخطاف ويشغله.

أحداث خطافات الويب
| الحدث | متى ترسله زيدا |
|---|---|
order.created |
عند إرسال الطلب، وهي أول مرة يصل فيها إلى المتجر. |
order.status_changed |
مع كل تغير في الحالة بعد ذلك: accepted وready وdispatched وdelivered وfulfilled وcanceled وreturned وdeleted. وكذلك حين يرجع فريق المتجر الطلب إلى حالة سابقة تصحيحًا. |
order.paid |
حين يصل المال: عند إرسال طلب دفع مقدمًا، أو بعده عند تسجيل دفع أونلاين، أو حين يحدد فريق المتجر أنه استلم المبلغ نقدًا أو بالبطاقة عند التسليم، أو أنه استلم ثمن طلب على الحساب. |
order.canceled |
عند إلغاء الطلب. وترسله زيدا مع حدث order.status_changed الخاص به. |
ترسل كل طلبات المتجر أحداثًا، من أي مصدر جاءت، ومنها الطلبات الحية التي أرسلتها بواجهة الطلبات. ولا يرسل شيئًا ما يلي:
- طلب لم يكتمل إرساله قط، كطلب أونلاين لم يدفعه العميل فانتهت مهلته؛
- بيع مسجل أرسلته بواجهة الطلبات؛
- جولة طلب على طاولة في الطلب من الطاولة، لأن العميل يدفع ثمنها على الطاولة.
ولا تضمن زيدا ترتيب وصول عمليات الإرسال، فقد تصل إعادة محاولة بعد حدث أحدث منها. فاستعمل occurred_at وorder.status لتعرف أي الحالات أحدث.
طلب خطاف الويب
ترسل زيدا طلب HTTP من نوع POST بمحتوى JSON.
| الترويسة | القيمة |
|---|---|
Content-Type |
application/json |
User-Agent |
Zyda-Webhooks/1 |
X-Zyda-Event |
اسم الحدث، مثل order.created. |
X-Zyda-Delivery |
معرف عملية الإرسال، وهو أيضًا delivery_id في المحتوى. ولا يتغير في كل إعادة محاولة للعملية نفسها. |
X-Zyda-Signature |
t=<unix seconds>,v1=<signature>. انظر «تحقق من التوقيع». |
محتوى خطاف الويب
للأحداث كلها شكل واحد، وهذه نسخته الأولى.
order.statusهي الحالة التي يتحدث عنها هذا الحدث.order.previous_statusهي الحالة التي قبلها. وهيpendingفيorder.created.- الأوقات بصيغة ISO 8601، بتوقيت UTC.
- المبالغ أرقام، بعملة المتجر.
- لا تكون قيمة
testهيtrueإلا في الحدث التجريبي.
مثال على order.status_changed:
{
"version": 1,
"event": "order.status_changed",
"delivery_id": "6f1c2a9e-0b7d-4c55-9a51-2f0e8d3b7c14",
"occurred_at": "2026-10-14T10:32:00Z",
"test": false,
"store": { "id": 4321, "name": "Sample Store" },
"order": {
"id": 880123,
"number": "1042",
"status": "accepted",
"previous_status": "submitted",
"created_at": "2026-10-14T10:20:05Z",
"submitted_at": "2026-10-14T10:20:06Z",
"due_at": "2026-10-14T10:50:06Z",
"is_scheduled": false,
"time_slot": null,
"delivery_type": "pickup",
"origin": "manual_order",
"is_manual_order": true,
"branch": { "id": 101, "name": "Main Branch" },
"channel": "whatsapp",
"captured_by": "api",
"taken_by": "staff",
"customer": { "name": "Sample Customer", "phone": "+96550000000" },
"address": {
"area": null, "city": null, "block": null, "street": null, "avenue": null, "building": null,
"floor": null, "unit_no": null, "unit_type": null, "notes": null, "lat": null, "lng": null
},
"items": [
{
"id": 5550001,
"menu_item_id": "a1b2c3d4-0000-4000-8000-000000000001",
"variant_id": "123456",
"name": "Burger patties, 6 pieces",
"name_ar": null,
"variant_name": "Regular",
"quantity": 2,
"unit_price": 4.75,
"total_price": 9.5,
"notes": "Extra fat",
"options": []
}
],
"payment": {
"method": "CASH",
"status": "paid",
"cash_collected_at": null,
"currency": "KWD",
"subtotal": 9.5,
"discount": 0.0,
"voucher_code": null,
"delivery_fee": 0.0,
"service_fee": null,
"tax": 0.0,
"total": 9.5
}
}
}
لا يتغير بين الأحداث إلا event وorder.status وorder.previous_status:
| الحدث | order.status |
order.previous_status |
|---|---|---|
order.created |
submitted |
pending |
order.status_changed |
الحالة الجديدة | الحالة التي قبلها |
order.paid |
حالة الطلب في ذلك الوقت | الحالة التي قبلها، إن كان التغيير نفسه قد نقل الحالة. وإلا فهي null. |
order.canceled |
canceled |
الحالة التي قبلها |
ملاحظات على الحقول:
channelمفتاح مصدر الطلب، مثلwebsiteأوphoneأوtalabat. انظر «مصادر الطلبات».captured_byالنظام الذي سجل الطلب، وهوapiفي الطلب الذي ترسله أنت.taken_byمن أخذ الطلب:customerأوstaffأوring_agentأوai_agent.- كل عنصر في
items[].optionsفيهnameوname_arوquantityوprice. - في الدفع نقدًا أو بالبطاقة عند التسليم، قد تكون قيمة
payment.statusهيpaidقبل التحصيل. وتملأ زيداcash_collected_atوترسلorder.paidحين يحدد فريق المتجر أنه استلم المبلغ. - يشمل
discountالقسيمة. - قد تكون
channelوcaptured_byوtaken_byوcash_collected_atبقيمةnullفي الطلبات القديمة.
أجزاء الطلب
يستطيع كل خطاف أن يستثني أيًا من هذه الأجزاء: customer (الاسم والهاتف) وaddress وitems وpayment. ويبقى للجزء المستثنى مفاتيحه، لكن قيمة كل منها null، وقيمة items هي []. فلا يتغير شكل المحتوى أبدًا.
تحقق من التوقيع
تحقق من كل طلب قبل أن تثق به.
- اقرأ
tوv1من ترويسةX-Zyda-Signature. - كون هذا النص: قيمة
t، ثم نقطة، ثم محتوى الطلب الخام كما وصلك تمامًا. مثل1760437920.{"version":1,...}. - احسب HMAC-SHA256 لهذا النص، واجعل سر الخطاف المفتاح. واكتب النتيجة بالنظام الست عشري بحروف صغيرة.
- قارن نتيجتك بقيمة
v1مقارنة ثابتة الزمن. فإن اختلفتا، فارفض الطلب. - ارفض الطلب إذا ابتعد
tعن ساعتك أكثر من بضع دقائق. فبهذا تمنع من يعيد إرسال طلب قديم.
استعمل المحتوى الخام. فإذا حللت JSON ثم كتبته من جديد، تغيرت البايتات ولم يعد التوقيع يطابق.
مثال بلغة Node.js (والخطوات السابقة واحدة في كل لغة):
const crypto = require('crypto');
function verifyZydaSignature(rawBody, signatureHeader, secret, toleranceSeconds = 300) {
const parts = Object.fromEntries(
String(signatureHeader || '').split(',').map((part) => {
const at = part.indexOf('=');
return [part.slice(0, at).trim(), part.slice(at + 1).trim()];
})
);
const t = parts.t;
if (!t || !parts.v1) return false;
if (Math.abs(Date.now() / 1000 - Number(t)) > toleranceSeconds) return false;
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
const a = Buffer.from(expected, 'utf8');
const b = Buffer.from(parts.v1, 'utf8');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
رد سريعًا، وإعادة المحاولة
- رد بأي حالة
2xxخلال 10 ثوان. وتنتظر زيدا الاتصال 5 ثوان. وأجل الأعمال البطيئة إلى ما بعد الرد، في طابور مثلًا. - يرى المتجر أول 2 KB من ردك في سجل الإرسال.
- إذا انتهت المهلة، أو وقع خطأ في الشبكة، أو جاء رد
5xxأو429، أعادت زيدا المحاولة بعد دقيقة، ثم 5 دقائق، ثم 15 دقيقة، ثم ساعة، ثم 3 ساعات، ثم 6 ساعات، ثم 14 ساعة: 8 محاولات في نحو يوم. - أي رد آخر، ومنه سائر ردود
4xxوالتحويل، يفشل عملية الإرسال في الحال. إلا أن تطبيق ويب في Google Apps Script (script.google.com) إذا رد برمز302أو303، عدته زيدا إرسالًا ناجحًا، لأن البرنامج النصي قد عمل. ومع ذلك لا تتبع زيدا التحويل. - قد تصلك عملية الإرسال نفسها أكثر من مرة، فأسقط المكرر منها بقيمة
X-Zyda-Delivery. - بعد 50 عملية إرسال فاشلة متتالية، توقف زيدا الخطاف. ولا تعد العملية فاشلة إلا بعد أن تستنفد محاولاتها. ويشغل المتجر الخطاف مرة أخرى من إرسال الأحداث.
والحدث التجريبي الذي يرسله المتجر من لوحة التحكم فيه "test": true، وdelivery_id أوله test_، وطلب مختلق قيمة id فيه 0 وقيمة number هي TEST-0001.