خطافات الويب
يرسل اشتراك خطاف الويب الأحداث إلى نقطة نهاية HTTPS لديك لحظة وقوعها: تسجيل جهاز، واكتمال رحلة، ورفع تنبيه، ودخول
سياج جغرافي، وإتمام نقطة توقف، والإبلاغ عن شراء وقود، ودفعة مقروءة من بوابة الدفع لديك. يسرد
فهرس الأحداث كل حدث يمكنك الاشتراك فيه مع إصدار مخططه، وتعيد GET /v1/webhooks/events القائمة
نفسها مع مخطط JSON لكل حدث ومثال عليه. أدِر الاشتراكات في
استوديو المطوّرين أو عبر واجهة خطافات الويب
(webhooks:read وwebhooks:write).
الاشتراك
curl -X POST "https://api.zaitrack.app/v1/webhooks" \
-H "Authorization: Bearer zk_test_…" \
-H "Content-Type: application/json" \
-d '{
"url": "https://hooks.example.com/zaitrack",
"description": "Dispatch board",
"events": ["zaitrack.geofence.*", "zaitrack.alert.raised"],
"filters": {"severityAtLeast": "high"}
}'
- url: بـ
https، و2,048 محرفًا على الأكثر، بلا بيانات اعتماد فيه. تُرفض العناوين الخاصة وعناوين الاسترجاع والعناوين المحلية للرابط عند العنوان الذي يتصل به كل تسليم فعلًا، ولا تُتبع عمليات إعادة التوجيه. - events: من 1 إلى 50 نمطًا، يطابق كل منها حدثًا واحدًا على الأقل من الفهرس: اسم كامل
(
zaitrack.alert.raised.v1)، أو اسم بلا إصداره، أو بادئة مع حرف بدل (zaitrack.alert.*)، أو*. - filters (اختياري):
severityAtLeast: infoأوlowأوmediumأوhighأوcritical؛ وتُسقط الأحداث ذاتdata.severityالأدنى.vehicleIds: حتى 500 معرّف UUID؛ وتُسقط الأحداث المتعلقة بمركبات أخرى.divisionIds: حتى 50 معرّف قسم؛ تُبقى الأحداث المتعلقة بمركبات تلك الأقسام أو الأقسام التابعة لها فقط، ويُسقط الحدث الذي لا يذكر مركبة.predicate: تعبير JSON Logic على الغلاف (event_nameوregionوdata)، بحجم 4 KiB على الأكثر، بالمعاملاتvarو==و!=و<و<=و>و>=وinوandوorو!. مثال:{"in": [{"var": "data.severity"}, ["high", "critical"]]}.
- retryPolicy (اختياري):
maxAttemptsمن 1 إلى 24 (الافتراضي 12)، وtimeoutSمن 1 إلى 60 (الافتراضي 10)، وbackoffبقيمةexponential(الافتراضي) أوlinearأوfixed. - secret (اختياري): من 24 إلى 128 محرفًا. إن تُرك تولّد الخدمة سرًّا (
whsec_…). ويحمله الرد مرة واحدة.
تحتفظ المؤسسة بخمسين اشتراكًا على الأكثر.
التسليم
كل تسليم طلب HTTP POST بجسم JSON:
{
"schema_version": "1.0",
"event_id": "…",
"event_name": "zaitrack.geofence.entered.v1",
"tenant_id": "…",
"region": "gcc",
"occurred_at": "2026-10-28T06:12:04.512Z",
"produced_at": "2026-10-28T06:12:05.031Z",
"trace_id": "…",
"data": { … }
}
مفاتيح الغلاف snake_case، بخلاف واجهة REST. يصف data مخططُ JSON للحدث، والأوقات بصيغة RFC 3339. ولا يُسلَّم جسم
يتجاوز 256 KiB.
| الترويسة | القيمة |
|---|---|
X-Zaitrack-Signature | t=<unix seconds>,v1=<hex HMAC-SHA256>، وقيمتا v1 أثناء تدوير السرّ: راجع التحقق من التسليم |
X-Zaitrack-Event-Id | معرّف الحدث؛ هو نفسه في كل محاولة وإعادة إرسال |
X-Zaitrack-Event-Name | مثل zaitrack.alert.raised.v1 |
X-Zaitrack-Delivery-Id | هذا التسليم (حدث واحد إلى اشتراك واحد) |
X-Zaitrack-Attempt | 1 للمحاولة الأولى، ثم 2 و3 … |
X-Zaitrack-Subscription-Id وX-Zaitrack-Tenant-Id وX-Zaitrack-Region | مصدر التسليم |
X-Zaitrack-Schema-Version | 1.0 |
X-Zaitrack-Replay | true عند إعادة الإرسال |
X-Zaitrack-Test | true عند إرسال اختبار |
X-Zaitrack-Trace-Id | التتبّع، حين يكون للحدث تتبّع |
تذكر أحداث التنبيه ما حدث بالإنجليزية (title وdescription) وبصيغة مستقلة عن اللغة (code وparams)، لتعرضه
بلغة مستخدميك: انظر صياغة التنبيهات.
أجب بأي 2xx ضمن مهلة الاشتراك. أزل التكرار بالاعتماد على X-Zaitrack-Event-Id: قد يصل الحدث أكثر من مرة.
اختبار اشتراك
ترسل POST /v1/webhooks/{id}:test تسليمًا واحدًا إلى نقطة النهاية الآن، وتجيب به وبمحاولته.
- بلا جسم، ترسل
zaitrack.webhook.test.v1، ويذكرdata.messageفيه أن نقطة النهاية قابلة للوصول. - مع
{"event": "zaitrack.trip.completed.v1"}ترسل ذلك الحدث ومثاله من الفهرس فيdata، فتختبر معالج حدث حقيقي. يمكن تسمية أي حدث من الفهرس.
في الحالتين يحمل الجسم "test": true والطلب X-Zaitrack-Test: true، فيميّز معالجك الاختبار من الحدث الحقيقي. ولا
يُحتسب الاختبار ضمن إخفاقات الاشتراك.
تدوير السرّ
تمنح POST /v1/webhooks/{id}/secrets:rotate الاشتراك سرًّا جديدًا يظهر مرة واحدة في الرد. وخلال مدة تداخل يبقى السرّ
القديم يوقّع بجانب الجديد: يحمل كل تسليم توقيعَي v1، فتستمر نقطة النهاية التي ما زالت تحمل السرّ القديم في التحقق
بينما تنشر السرّ الجديد.
curl -X POST "https://api.zaitrack.app/v1/webhooks/$ID/secrets:rotate" \
-H "Authorization: Bearer zk_test_…" \
-H "Content-Type: application/json" \
-d '{"overlapHours": 48}'
قيمة overlapHours من 0 إلى 168، و24 إن تُركت؛ والقيمة 0 توقف السرّ القديم فورًا.
إعادة المحاولة
يُعاد إرسال التسليم الذي لا يتلقى 2xx (حالة خطأ، أو انتهاء المهلة، أو رفض الاتصال). مدة الانتظار بعد المحاولة
n:
| التأخير | الانتظار |
|---|---|
exponential | 30 ث × 2^(n−1): 30 ث، ثم دقيقة، ثم دقيقتان، ثم 4 دقائق … |
linear | n × 5 دقائق |
fixed | 5 دقائق |
لا يتجاوز الانتظار 60 دقيقة. بعد maxAttempts يُنقل التسليم إلى الرسائل الميتة (الحالة dlq). ونقطة النهاية التي
تجيب 410 Gone يُنقل تسليمها فورًا ويُعطَّل اشتراكها. وبعد 25 رسالة ميتة متتالية يُعطَّل الاشتراك أيضًا
(status: disabled مع disabledReason)؛ ولا يتلقى الاشتراك المعطّل شيئًا حتى تعيده إلى active بـ
PATCH /v1/webhooks/{id}. أما paused فيوقف التسليمات عمدًا.
التسليمات وإعادة الإرسال
- تسرد
GET /v1/webhooks/{id}/deliveriesتسليمات الاشتراك، الأحدث أولًا، مع حالتها:queuedأوsendingأوretryingأوdeliveredأوdlq. - تعطي
GET /v1/webhooks/{id}/deliveries/{deliveryId}الحمولة وكل محاولة: رمز الحالة، والزمن، والخطأ، وترويسات الطلب المرسلة، وترويسات رد نقطة النهاية، وأول 1 KiB من جوابها. - تعيد
POST /v1/webhooks/{id}/deliveries/{deliveryId}:replayإرساله الآن معX-Zaitrack-Replay: true. لا تستهلك إعادة الإرسال رصيد المحاولات لتسليم ما زالت محاولاته جارية، وتُرفض (409) أثناء إرسال التسليم.
الرسائل الميتة
تسرد GET /v1/webhooks/dead-letters التسليمات التي استنفدت محاولاتها عبر كل اشتراكات مؤسستك، الأحدث أولًا
(limit وcursor). وبعد إصلاح نقطة النهاية أعد إرسالها في طلب واحد:
curl -X POST "https://api.zaitrack.app/v1/webhooks/dead-letters:replay" \
-H "Authorization: Bearer zk_test_…" \
-H "Content-Type: application/json" \
-d '{"deliveryIds": ["…", "…"]}'
حتى 100 تسليم في الطلب. يُرسل كل منها قبل الرد، ويعطي الرد لكل تسليم التسليمَ ومحاولته، أو error الذي أوقفه.
تُحفظ التسليمات 30 يومًا.