تخط وانتقل إلى المحتوى الرئيسي

نظرة عامة على Webhooks

كيف تعمل webhooks في DZBuild — الأحداث التي تُطلق، آلية التسليم وإعادة المحاولة، نموذج الأمان، والحصص.

بقلم: Support

Webhooks إشعارات دفع لحظية من DZBuild إلى خادمك عند حدوث شيء على متجرك. استخدمها بدلًا من الاستعلام المتكرر (polling) — حمل أقل، تأخير أقل، وتسليمات webhook لا تُحسب من حصة الطلبات الشهرية.

ℹ️ معلومة — هناك نظاما webhooks مختلفان في DZBuild

اختر الصحيح قبل أن تبني.

إضافة Webhooks للتاجر

webhooks الخاصة بـ API v1 (هذا القسم)

كيف تُعدّها

/dashboard/webhooks — بدون كود

POST /v1/webhooks — عبر الـ API فقط

من يمكنه استعمالها

خطة Unlimited فما فوق

المتاجر على خطة Enterprise سارية، بمفتاح API خاص بالتاجر (رموز التطبيقات المثبّتة مرفوضة)

عدد النقاط لكل متجر

1 في Unlimited، 3 في Enterprise

لا يوجد حد مفروض

التوقيع

X-DZ-Signature: t=<ts>,v1=hex(hmac_sha256(secret, ts + "." + rawBody)) على الجسم الخام، ويمكنك التحقق منه. كما تُرسل ترويسة X-DZ-Token: <secret> لأدوات الـ no-code التي لا تدعم إلا المصادقة بالترويسات.

الصيغة نفسها: X-DZ-Signature: t=<ts>,v1=hex(hmac_sha256(secret, ts + "." + rawBody)) على الجسم الخام، بالسر secret الذي يُرجعه POST /v1/webhooks مرة واحدة. يمكنك التحقق منه. أما webhooks المسجّلة قبل التوقيع بسر كل webhook فتبقى على توقيع قديم لا يمكن التحقق منه: انظر التوقيع.

الطلبات التي تغطيها

order.created من كل المصادر (الواجهة، صفحة الهبوط، الإنشاء اليدوي من لوحة التحكم، الـ API) بالإضافة إلى 6 أحداث حالة، منها order.processing

الطلبات المُنشأة أو المُحدَّثة عبر الـ API، إضافة إلى التأكيد والإلغاء بأزرار إشعار Telegram بطلب جديد، بما فيها طلبات الواجهة وصفحات الهبوط

تُرسَل من

نطاقات Cloudflare

عناوين خروج DZBuild الخاصة — اطلب من الدعم القائمة الحالية

إضافات

واجهة سجل التسليمات، إعادة توليد السر، التحقق من أن الوجهة HTTPS فقط، تعطيل تلقائي بعد 10 إخفاقات متتالية

التحقق من أن الوجهة HTTPS فقط

إن كان كل ما تحتاجه إشعارات طلبات موثوقة، فالإضافة هي المنتج الأفضل. استخدم webhooks الخاصة بـ API v1 حين يكون تكاملك يتحدث أصلًا مع الـ REST API.

لماذا Webhooks

قارن:

الاستعلام المتكرر — تنادي شيفرتك GET /v1/orders?since=... كل دقيقة. 1440 نداءً يوميًا، 1440 رحلة، تستهلك حصة API بالتساوي، والتأخير من "إنشاء الطلب" حتى "علم كودك" 60 ثانية.

Webhooks — تسجّل https://yourapp/webhooks مرة واحدة. كل طلب يُنشأ عبر POST /v1/orders يضع تسليمًا في الطابور، والطابور يُستنزف باستمرار، فيكون التأخير أقل من دقيقة عادةً. صفر استعلام، صفر إهدار للحصة.

⚠️ تنبيه — webhooks الخاصة بـ API v1 لا تُطلَق عند الشراء من واجهة المتجر ولا عند التغيير من لوحة التحكم

order.created يُطلق فقط للطلبات المُنشأة عبر POST /v1/orders. طلبات واجهة المتجر وصفحات الهبوط والطلبات اليدوية من لوحة التحكم لا تُطلق شيئًا هنا. وتغييرات الحالة من لوحة التحكم لا تُطلق شيئًا كذلك؛ وحدها التغييرات عبر الـ API وزرّا التأكيد والإلغاء في إشعار Telegram بطلب جديد تُطلق حدثًا. انظر كتالوج الأحداث.

الاستعلام يتفوّق فقط حين: - نقطتك غير قابلة للوصول من الإنترنت (استعلم من داخل شبكتك). - ليس لديك خادم (استعلم من Lambda مجدوَلة / cron).

كيف يعمل التسليم

تقع كتابة عبر API v1
        │
        ▼
يُوضع تسليم في الطابور لكل webhook مشترك في ذلك الحدث
        │
        ▼
الطابور يُستنزف باستمرار — أقل من دقيقة عادةً
        │
        ▼
جسم موقَّع  ─────►  POST لرابطك (5 ث للاتصال، 10 ث إجمالًا)
                              │
                              ├─ 2xx: علّم مسلَّمًا، انتهى
                              ├─ 5xx أو 408 أو 429 أو timeout أو فشل DNS أو TLS: يُعاد مع تباعد متزايد
                              ├─ أي 4xx آخر، أو 3xx: إلى قائمة الرسائل الميتة فورًا، بلا إعادة
                              └─ 5 محاولات فاشلة: ينتقل إلى قائمة الرسائل الميتة، بلا إعادة بعدها

سلوك إعادة المحاولة

  • تُعاد محاولة الإرسال عند استجابة 5xx أو 408 أو 429 أو فشل الشبكة (انتهاء المهلة، DNS، TLS) بعد دقيقة، ثم 5 دقائق، ثم 30 دقيقة، ثم ساعتين. بعد الفشل الخامس ينتقل الإرسال إلى قائمة الرسائل الميتة ولا يُعاد.

  • أي استجابة 4xx أخرى، وكل استجابة 3xx، تُرسَل مرة واحدة فقط: ينتقل التسليم فورًا إلى قائمة الرسائل الميتة ولا يُعاد أبدًا. لا نتبع عمليات إعادة التوجيه، لذا يُعدّ 301/302 إخفاقًا.

لا يوجد تعطيل تلقائي. يزداد failure_count الخاص بالـ webhook مرة واحدة لكل محاولة فاشلة، ويعود إلى 0 عند أي نجاح؛ وتبقى status بقيمة active.

النتائج العملية:

  • أرجِع 2xx بسرعة. إن لم تستطع معالجة الحمولة، أرجِع 2xx على أي حال وتجاهلها؛ إرجاع 5xx يكلّفك أربعة تسليمات أخرى للجسم نفسه خلال نحو ساعتين ونصف.

  • لا تعتمد على إعادة المحاولة لتغطية نقطة بطيئة. خمسة إخفاقات خلال نحو ساعتين ونصف تُسقط التسليم. خزّن الجسم في طابورك الخاص وأرجِع الإقرار فورًا.

  • طابِق بالاستعلام. بما أن التسليم يُسقط بعد خمسة إخفاقات، شغّل مسحًا دوريًا بـ GET /v1/orders?since=... كشبكة أمان. يُصفّي since حسب وقت إنشاء الطلب، فالمسح يجد الطلبات التي فاتك order.created الخاص بها؛ أما تغيير الحالة الفائت، فأعِد قراءة الطلبات التي ما زلت تتابعها وقارن status الخاص بها.

ما يُعتبر "نجاحًا"

  • HTTP 200, 201, 202, 204 (أي 2xx) — نجاح.

  • HTTP 4xx غير 408 و429 (400 و401 و403 و404 و422 وغيرها): لا تُعاد المحاولة، وينتقل التسليم مباشرة إلى قائمة الرسائل الميتة. أصلح نقطتك وأعد الاختبار عبر POST /v1/webhooks/{id}/test.

  • HTTP 3xx: لا تُعاد المحاولة، وينتقل التسليم فورًا إلى قائمة الرسائل الميتة. لا نتبع إعادة التوجيه؛ وجّه الـ webhook إلى الرابط النهائي.

  • Timeout وفشل DNS وفشل TLS: تُعاد المحاولة كما في 5xx. نتحقق من شهادات TLS بصرامة، لذا تفشل الشهادة الموقّعة ذاتيًا في كل محاولة.

  • HTTP 5xx و408 و429: تُعاد المحاولة وفق الجدول أعلاه، 5 محاولات إجمالًا.

نموذج الأمان

ما نُرسله

Content-Type:    application/json
User-Agent:      dzbuild-webhook/1
X-DZ-Timestamp:  <unix seconds>
X-DZ-Signature:  t=<unix seconds>,v1=<hex hmac-sha256>
X-DZ-Delivery-Id: <numeric delivery id>

التوقيع

يُحسب X-DZ-Signature بالسر secret الذي أرجعه POST /v1/webhooks عند تسجيل الـ webhook:

X-DZ-Signature: t=<unix seconds>,v1=<hex hmac-sha256>expected = hex( hmac_sha256( WEBHOOK_SECRET, t + "." + raw_body ) )if (!constant_time_equal(expected, v1)) reject 401
if (abs(now - t) > 300)                 reject 401   # نافذة إعادة ±5 دقائق

للتحقق من تسليم:

  1. قسّم الترويسة عند , واقرأ قيمتي t وv1.

  2. احسب HMAC-SHA256 للقيمة t + "." + raw_body بسر الـ webhook لديك، حيث raw_body هو البايتات التي استلمتها كما هي، ثم رمّز الناتج بالست عشري (hex).

  3. قارن الناتج مع v1 بمقارنة ذات زمن ثابت.

  4. ارفض التسليم إذا ابتعدت t عن ساعتك بأكثر من 300 ثانية.

كل محاولة تُوقَّع لحظة إرسالها، لذا تحمل إعادة المحاولة t جديدة وv1 جديدة على الجسم نفسه. الشيفرة بأربع لغات موجودة في التحقق من التواقيع.

⚠️ تنبيه — webhooks المسجّلة قبل التوقيع بسر كل webhook

الـ webhook الذي أُنشئ قبل أن تبدأ DZBuild التوقيع بالسر الخاص بكل webhook يبقى على التوقيع القديم: قيمة ست عشرية مجرّدة بلا جزء t=، محسوبة بمفتاح لا تُسلّمه DZBuild. لا يمكنك التحقق منها. احذف ذلك الـ webhook وسجّله من جديد، فالتسجيل الجديد يُرجع سرًّا يُوقَّع به كل تسليم.

ما يجب أن تفعله

  1. تحقّق من التوقيع قبل أن تتصرّف. ارفض أي تسليم لا تطابق فيه v1، قبل أن تحلّل JSON أو تلمس أي طلبية.

  2. استعمل HTTPS. يرفض POST /v1/webhooks أي url لا يبدأ بـ https://، وتُفحص الشهادات بصرامة.

  3. تأكد أن الطابع الزمني خلال 5 دقائق من ساعة خادمك — حماية رخيصة من إعادة الإرسال.

  4. استخدم بايتات الجسم الخام لحساب HMAC، ولا تُعد تسلسل JSON.

  5. كن idempotent. قد يصلك التسليم نفسه أكثر من مرة: بعد 5xx أو 408 أو 429 أو انتهاء المهلة يُرسَل من جديد بالجسم نفسه. أزل التكرار بالاعتماد على delivery_id الموجود داخل الجسم الموقَّع فقط.

ما لا نفعله

  • لا نوثّق صادراتنا بـ mTLS. إن تطلّبت نقطتك ذلك، اعتمد reverse proxy يُجرّد/يضيف mTLS أمام معالجك.

  • لا نُرسل تسليمات API v1 من نطاقات Cloudflare، لذا فإن السماح بتلك النطاقات فقط يحجب كل تسليم. إن احتجت قائمة IP مسموحة، راسل الدعم للحصول على عناوين الخروج الحالية — فهي قابلة للتغيير. (إضافة Webhooks للتاجر عكس ذلك تمامًا: تسليماتها تأتي من نطاقات Cloudflare.)

مظروف الحمولة

كل جسم webhook له نفس الشكل الخارجي:

{
  "event":       "order.confirmed",
  "store_id":    13,
  "occurred_at": "2026-04-30T21:18:21+00:00",
  "data":        { "order_id": 6894, "old_status": "pending", "new_status": "confirmed" },
  "delivery_id": "9f2c41ab77e05d18"
}

الحقل

ملاحظات

event

نوع الحدث (القائمة الكاملة في كتالوج الأحداث).

store_id

معرّف متجرك — مفيد إن كان لديك عدة webhooks لنفس المعالج.

occurred_at

متى حدث الأمر في نظامنا، ISO 8601 مع المنطقة.

data

حمولة خاصة بالحدث. انظر كتالوج الأحداث لشكل كل حدث.

delivery_id

سلسلة من 16 خانة ست عشرية، فريدة لكل تسليم (webhook واحد × حدث واحد). وهي متطابقة بايتًا ببايت في كل إعادة محاولة — وهذا ما يجعلها صالحة لإزالة التكرار.

ترويسة X-DZ-Delivery-Id قيمة مختلفة: معرّف تسليم رقمي، مثلًا 4127. وهي ثابتة عبر إعادات المحاولة، لكن التوقيع لا يشملها، فيستطيع أي أحد يصل إلى رابطك أن يضع فيها ما يشاء. أزل التكرار بالاعتماد على delivery_id الموجود في الجسم الموقَّع فقط.

الحصة

تسليمات webhook غير محسوبة وغير محدودة اليوم. يُبلَّغ عن رقم webhooks_per_month في GET /v1/usage و GET /v1/quotas، لكن لا شيء يزيده ولا شيء يفرضه. كما أن محاولات التسليم لا تستهلك حصة requests_per_month الخاصة بالـ API.

هذا ليس ترخيصًا بالبطء: النقطة التي تُرجع 5xx تستقبل الجسم نفسه حتى أربع مرات إضافية خلال نحو ساعتين ونصف (انظر سلوك إعادة المحاولة).

التالي

هل أجاب هذا عن سؤالك؟