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

خطافات الويب

يرسل اشتراك خطاف الويب الأحداث إلى نقطة نهاية 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-Signaturet=<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-Attempt1 للمحاولة الأولى، ثم 2 و3 …
X-Zaitrack-Subscription-Id وX-Zaitrack-Tenant-Id وX-Zaitrack-Regionمصدر التسليم
X-Zaitrack-Schema-Version1.0
X-Zaitrack-Replaytrue عند إعادة الإرسال
X-Zaitrack-Testtrue عند إرسال اختبار
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 يومًا.