إشعارات Webhook
Webhooks
اشترك في الأحداث وتحقق من التوقيع وتعامل مع إعادة المحاولة دون تكرار المعالجة.
استخدم Webhooks عندما يحتاج backend إلى التفاعل مع تغييرات التجارة دون polling. يرتبط كل اشتراك بتثبيت تطبيق مصرح، وحدث مراجع، وعنوان HTTPS واحد.
قبل البدء
يجب أن يعلن إصدار التطبيق المنشور الحدث، وأن يوافق عليه التاجر، وأن يملك installation token نطاق webhooks:manage. يجب أن يكون المستقبل HTTPS عامًا، ويتحقق من التوقيع على النص الخام، ويرد بسرعة ويعالج الأحداث دون تكرار.
إدارة الاشتراك
استخدم GET /api/v1/webhooks وPOST /api/v1/webhooks وDELETE /api/v1/webhooks/{id} مع صلاحية webhooks:manage. يقبل الإنشاء حدثًا معلنًا في الإصدار المثبت وعنوان HTTPS. يرتبط الاشتراك بالإصدار المراجع وصلاحية الربط الحالية. إعادة إنشاء الاشتراك لنفس التطبيق والحدث والعنوان تغير مفتاح التوقيع وتعيد تفعيله.
مفتاح التوقيع
تعيد استجابة الإنشاء data.signing_secret مرة واحدة، مع آخر أربعة أحرف منه. احفظه بأمان فورًا؛ تعرض القوائم لاحقًا secret_last_four فقط. عند تغيير المفتاح، حدّث مستقبل الإشعارات بصورة متناسقة.
محتوى الرسالة والتحقق
يتكون جسم JSON من id وtype وoccurred_at وdata. تُرسل الترويسات X-Saas-Event-Id وX-Saas-Timestamp وX-Saas-Signature. يستخدم التوقيع HMAC-SHA256 بصيغة v1=<hex> للنص:
<timestamp>.<event_id>.<exact_request_body>
تحقق من الجسم الخام قبل تحليله، وقارن التوقيع بزمن ثابت، وحدد مهلة زمنية مقبولة، وامنع معالجة معرّف الحدث نفسه مرتين.
Node.js
import { createHmac, timingSafeEqual } from "node:crypto";
const expected = `v1=${createHmac("sha256", secret).update(`${timestamp}.${eventId}.${rawBody}`).digest("hex")}`;
const valid = expected.length === signature.length && timingSafeEqual(Buffer.from(expected), Buffer.from(signature));Python
message = timestamp.encode() + b"." + event_id.encode() + b"." + raw_body
expected = "v1=" + hmac.new(secret.encode(), message, hashlib.sha256).hexdigest()
valid = hmac.compare_digest(expected, signature)PHP
$expected = 'v1=' . hash_hmac('sha256', $timestamp . '.' . $eventId . '.' . $rawBody, $secret);
$valid = hash_equals($expected, $signature);الاتصال وإعادة المحاولة
يلزم HTTPS وعنوان عام. تُرفض العناوين الخاصة والمحلية والمحجوزة، ويُثبّت عنوان الشبكة الذي جرى التحقق منه بعد فحص DNS. لا يتبع المرسل إعادة التوجيه. مهلة الطلب ١٥ ثانية، وللأحداث العادية عشر محاولات كحد أقصى. بعد كل محاولة فاشلة تنتظر المحاولة التالية نحو ٣٠ ثانية، ثم دقيقتين، ثم ١٠ دقائق، ثم ٣٠ دقيقة، ثم ساعة وساعتين و٤ و٦ و٨ ساعات (بتفاوت عشوائي ±١٠٪)، فتأتي المحاولة الأخيرة بعد نحو ٢٢ ساعة من الأولى. ترويسة Retry-After مع الاستجابة 429 أو 503 تطيل الانتظار التالي حتى ٣٠ دقيقة. الاستجابات 400 و405 و410 و413 و414 و415 و422 نهائية وتنهي الإرسال فورًا، وتُعاد المحاولة لغيرها من 4xx و5xx وانتهاء المهلة وأخطاء الشبكة. يمكن إعادة إرسال ما انتهى إلى dead من لوحة المطور خلال ٧ أيام.
عقد أحداث الموارد
تعرض شاشة موافقة التاجر أحداث الإصدار المراجع بالتحديد. لا يستقبل الاشتراك حدثًا خارج هذه القائمة. يُحفظ تغيير العمل وسجل إرساله ضمن المعاملة نفسها، ويُلغيان معًا عند التراجع. يُجمع تكرار الحدث للمورد نفسه داخل المعاملة، ولا تنتج الكتابة التي لا تغير البيانات حدثًا. الاشتراكات الجديدة لا تستقبل أحداثًا تاريخية.
| الحدث | وقت الإنشاء | نوع المورد |
|---|---|---|
products.created | إضافة منتج | product |
products.updated | تغيير بيانات المنتج | product |
products.deleted | حذف منتج | product |
customers.created | إضافة عميل | customer |
customers.updated | تغيير اسم العميل أو هاتفه أو بريده (لا يصدر في المعاملة التي أنشأت العميل) | customer |
orders.created | إنشاء طلب | order |
orders.updated | تغيير بيانات الطلب | order |
orders.cancelled | انتقال الطلب إلى الإلغاء | order |
orders.fulfilled | انتقال الطلب إلى الشحن أو التسليم؛ الانتقال من الشحن للتسليم لا يكرر إشعار التنفيذ | order |
inventory.updated | إضافة مخزون غير صفري، تغيير الكمية أو الحجز، أو حذف سجل المخزون | inventory |
app.uninstalled | إلغاء التاجر ربط هذا التطبيق تحديدًا | installation |
يحتوي data على schema_version: 1 وstore_id وresource. يحتوي المورد على type وid، ويضيف المخزون product_id وvariant_id القابل للقيمة الفارغة وlocation_id. يضيف إشعار الإلغاء app_id. لا تتضمن الرسائل أسماء أو بيانات اتصال أو عناوين أو بيانات دفع أو كميات أو صفوف قاعدة البيانات كاملة. قراءة التفاصيل تحتاج صلاحية قراءة عاملة وموافقًا عليها بصورة مستقلة؛ وجود الحدث لا يفعّل واجهة مخططة وغير منفذة. وقد يكون المورد محذوفًا عند محاولة قراءته.
الإشعار الأخير عند إلغاء الربط
يمكن لاشتراك app.uninstalled المراجع استقبال إشعار أخير عن إلغاء ربط التطبيق نفسه. تُلغى أولًا صلاحية الرموز والاشتراكات والإرسالات العادية. يستخدم الإشعار الاشتراك السابق نفسه، وتنتهي صلاحيته بعد خمس دقائق، وله ثلاث محاولات بحد أقصى وبين المحاولات ٣٠ ثانية. لا يمنح وصولًا جديدًا للقراءة. إعادة الربط أو تغيير العنوان أو المفتاح أو التعليق أو إلغاء الصلاحية أو إيقاف الميزة يلغي الإشعارات المعلقة نهائيًا؛ إعادة التفعيل لا تعيدها. وصول هذا الإشعار غير مضمون عند فشل الشبكة أو انتهاء المهلة.
إلغاء الصلاحيات أثناء الإرسال
تحفظ الإرسالات هوية الاشتراك وإصدار صلاحية الربط. يتحقق السماح بالإرسال مرة واحدة بعد فحص DNS، وتحتاج تسوية النتيجة إلى المطالبة الحالية غير المنتهية. يمكن منع الطلب قبل السماح بإرساله؛ أما الطلب الذي سُمح له وخرج إلى الشبكة فلا يمكن استرجاعه. يجب أن يتحمل المستقبل التكرار ويتوقف عن التصرف نيابة عن المتجر بعد إلغاء التفويض.