Back to docs

Webhooks

الـ Webhooks

استقبل إشعارات HTTP موقّعة عند تغيّر الروابط والحملات والمنشورات في مساحة عملك.

ترسل Webhooks في Styrar إشعارات HTTP موقّعة عند تغيّر الموارد في مساحة عملك. استخدمها لمزامنة الروابط والنقرات مع نظام CRM، أو لتشغيل أتمتة في منظومتك التقنية، أو لتدفّق أحداث مسار التحويل إلى مستودع بيانات.

هذا يحل محل واجهة webhooks الخاصة بالروابط فقط والتي تم إيقافها (/v1/link-webhooks). يجب أن تستخدم التكاملات الجديدة /v1/webhooks/* فقط.

إعداد webhook

اتبع هذه الخطوات للانتقال من الصفر إلى نقطة نهاية موثّقة وجاهزة للإنتاج.

1. جهّز عنوان URL لاستقبال الطلبات

يحتاج خادمك إلى عنوان HTTPS عام يستقبل طلبات POST بجسم JSON. في بيئة الإنتاج، يجب أن تستخدم عناوين رد الاتصال HTTPS. يُسمح باستخدام HTTP فقط في بيئة التطوير المحلية.

يجب أن يقوم المعالج (handler) لديك بما يلي:

  • قراءة جسم الطلب الخام كسلسلة نصية أو buffer (لا تقم بتحليل JSON قبل التحقق من التوقيع).
  • قراءة رؤوس Styrar-Signature و Styrar-Event-Id و Styrar-Event-Type.
  • التحقق من التوقيع (انظر قسم التحقق من التوقيعات أدناه).
  • إعادة استجابة 2xx بسرعة بعد قبول الحدث. ضع الأعمال الثقيلة في طابور للمعالجة بشكل غير متزامن.

مثال على المسار: https://your-app.com/webhooks/styrar

لا يمكن لـ Styrar التسليم إلى عناوين خاصة أو loopback مثل localhost.

2. الحصول على صلاحية الوصول إلى الـ API (للإعداد البرمجي)

إذا كنت تنشئ نقاط النهاية عبر الـ API بدلًا من لوحة التحكم، فستحتاج إلى رمز Bearer يحمل:

الصلاحيةالوصول
webhooks:readعرض نقاط النهاية، عمليات التسليم، وأنواع الأحداث
webhooks:writeإنشاء، تحديث، حذف، اختبار، تدوير السر، وإعادة محاولة عمليات التسليم

أنشئ مفتاح API من الإعدادات ← مفاتيح API بصلاحيتي webhooks:read و webhooks:write، أو استخدم رمز وصول OAuth من تطبيق متصل يحمل نفس الصلاحيات.

بالنسبة لـ مساحات عمل الشركات، مرّر companyId في طلبات العرض والإنشاء.

3. إنشاء نقطة نهاية من لوحة التحكم

  1. سجّل الدخول وافتح الإعدادات ← الـ Webhooks (/settings/webhooks).
  2. تحت نقاط النهاية، أدخل عنوان نقطة النهاية (عنوان رد الاتصال HTTPS العام).
  3. أضف وصفًا اختياريًا (مثل "مزامنة CRM للإنتاج").
  4. اختر الأحداث التي تريدها (يجب اختيار حدث واحد على الأقل). من الاختيارات الشائعة:
    • link.clicked لتتبع النقرات
    • link.created / link.updated / link.deleted لدورة حياة الروابط
    • post.published و campaign.created لأحداث مسار التحويل
  5. اضغط إضافة نقطة نهاية.

بعد الإنشاء، تعرض Styrar السر الخاص بالتوقيع (whsec_live_… أو whsec_test_…). انسخه فورًا واحفظه في مدير الأسرار الخاص بك. يظهر مرة واحدة فقط. إذا فقدته، استخدم تدوير السر على نقطة النهاية وحدّث خادمك.

4. إنشاء نقطة نهاية عبر الـ API

RequestPOST
Authorization: Bearer sty_live_your_api_key
Content-Type: application/json

{
  "companyId": "cmxyz_company",
  "url": "https://your-app.com/webhooks/styrar",
  "description": "Production CRM sync",
  "eventTypes": [
    "link.clicked",
    "link.created"
  ]
}
Response201 Created
{
  "id": "wh_ep_abc123",
  "url": "https://your-app.com/webhooks/styrar",
  "description": "Production CRM sync",
  "enabled": true,
  "eventTypes": [
    "link.clicked",
    "link.created"
  ],
  "secretPrefix": "whsec_l",
  "companyId": "cmxyz_company",
  "userId": null,
  "disabledAt": null,
  "createdAt": "2026-06-22T12:00:00.000Z",
  "updatedAt": "2026-06-22T12:00:00.000Z",
  "secret": "whsec_live_abc123onlyShownOnce"
}

احفظ secret فورًا. لن يُرجَع في طلبات GET اللاحقة. إذا كانت مصفوفة eventTypes فارغة فهذا يعني الاشتراك في جميع أنواع الأحداث؛ بينما تتطلب لوحة التحكم اختيار حدث واحد صريح على الأقل.

5. إرسال حدث اختباري

تأكد من أن خادمك قابل للوصول قبل الاعتماد على حركة البيانات الفعلية.

لوحة التحكم: في صف نقطة النهاية، اضغط إرسال اختبار. ترسل Styrar حدث webhook.test. يجب أن تشاهد رسالة نجاح (toast) مع رمز حالة HTTP.

الـ API:

RequestPOST
Authorization: Bearer sty_live_your_api_key
Response200 OK
{
  "ok": true,
  "statusCode": 200
}

عند نجاح الاختبار، يجب أن يكون خادمك قد استلم حدث webhook.test (انظر استقبال حدث على خادمك أدناه).

تحقق من عمليات التسليم الأخيرة في لوحة التحكم (أو GET /v1/webhooks/deliveries) إذا فشل الاختبار. المشاكل الشائعة:

المشكلةما يجب فحصه
رفض الاتصال / انتهاء المهلةتأكد أن العنوان HTTPS عام، والجدار الناري يسمح بـ Styrar، والنفق (tunnel) يعمل
HTTP 4xx/5xx من تطبيقكيجب أن يُرجع المعالج 2xx بعد التحقق؛ سجّل الجسم الخام والرؤوس
فشل التحقق من التوقيعاستخدم الجسم الخام، السر الصحيح، ومقارنة بزمن ثابت
نقطة النهاية معطّلةأعد التفعيل من لوحة التحكم أو أصلح السبب الذي أدى إلى HTTP 410

6. التحقق من عمليات التسليم ومعالجتها

عند كل POST إلى عنوانك:

  1. حلّل Styrar-Signature إلى الطابع الزمني t والـ digest v1.
  2. ارفض إذا كان t أقدم من نطاق التسامح الخاص بك (يُنصح بـ 5 دقائق).
  3. احسب HMAC-SHA256 لـ "{t}.{raw_body}" باستخدام السر الخاص بنقطة النهاية.
  4. قارن مع v1 باستخدام فحص بزمن ثابت.
  5. حلّل JSON فقط بعد نجاح التحقق.
  6. احذف التكرارات بالاعتماد على Styrar-Event-Id (التسليم يحدث مرة واحدة على الأقل).

انظر قسم التحقق من التوقيعات أدناه لمثال بلغة Node.js.

7. الانتقال إلى الإنتاج

  • حافظ على نقطة النهاية مفعّلة في لوحة التحكم.
  • اشترك فقط في الأحداث التي تحتاجها (يقلل من الضجيج والتكلفة).
  • راقب عمليات التسليم الأخيرة بحثًا عن الفشل واستخدم إعادة المحاولة عند الحاجة.
  • دوّر السر إذا كان من المحتمل أنه تسرّب (تدوير السر في لوحة التحكم أو POST …/rotate-secret).

بداية سريعة

  1. احصل على صلاحية الوصول للـ API بصلاحيتي webhooks:read و webhooks:write (مفتاح API أو OAuth).
  2. اكشف نقطة استقبال HTTPS عامة وأنشئ نقطة نهاية في الإعدادات ← الـ Webhooks أو عبر POST /v1/webhooks/endpoints.
  3. انسخ سر التوقيع عند ظهوره واحفظه بأمان.
  4. أرسل حدثًا اختباريًا وتأكد من أن خادمك يحقق Styrar-Signature ويُرجع 2xx.
  5. عالج الأحداث الفعلية مع إزالة التكرار بالاعتماد على Styrar-Event-Id.

المصادقة

تتطلب إدارة الـ webhooks رمز Bearer يحمل الصلاحيات المذكورة في الخطوة 2 أعلاه. تعمل مفاتيح API ذات الصلاحيات المطابقة بنفس طريقة رموز وصول OAuth.

أنواع الأحداث

استدعِ GET /v1/webhooks/event-types للحصول على الكتالوج الفعلي في بيئتك. اشترك في أنواع محددة لكل نقطة نهاية، أو مرّر مصفوفة eventTypes فارغة لاستقبال جميع الأحداث.

webhook.test يُرسل فقط عند الضغط على إرسال اختبار؛ لا يُصدر من النشاط الطبيعي لمساحة العمل.

مغلّف الحدث (Event envelope)

تستخدم كل عملية تسليم نفس الشكل الأعلى مستوى. تعيش الحقول الخاصة بكل حدث تحت data.object:

الحقلالنوعالوصف
idstringمعرّف الحدث الفريد. نفس القيمة الموجودة في رأس Styrar-Event-Id.
typestringاسم الحدث (مثل link.clicked).
api_versionstringإصدار مخطط الحمولة (2026-06-22).
created_atstringطابع زمني ISO 8601 عند إنشاء الحدث.
workspace.typestringcompany أو personal.
workspace.company_idstring | nullمعرّف الشركة عندما يكون workspace.type هو company.
data.objectobjectحمولة الحدث (موثّقة لكل حدث أدناه).

مثال كامل على التسليم (المغلّف + حمولة link.created):

JSON
{
  "id": "evt_outbox_abc123",
  "type": "link.created",
  "api_version": "2026-06-22",
  "created_at": "2026-06-22T12:00:00.000Z",
  "workspace": {
    "type": "company",
    "company_id": "cmxyz_company"
  },
  "data": {
    "object": {
      "id": "clink_abc123",
      "short_code": "summer",
      "title": "Summer sale",
      "original_url": "https://example.com/sale",
      "is_active": true,
      "company_id": "cmxyz_company",
      "campaign_id": "ccamp_abc",
      "link_group_id": null,
      "created_at": "2026-06-22T12:00:00.000Z"
    }
  }
}

بالنسبة لمساحات العمل الشخصية، تكون workspace.type هي personal وتكون workspace.company_id هي null. قد تتضمن الحمولة company_id: null على كائنات الروابط.

ملخص الأحداث

الحدثعند حدوثهالحجم المعتاد
link.createdعند إنشاء رابط مختصر (POST /v1/links، إنشاء جماعي، أو upsert جماعي)منخفض
link.updatedعند تحديث رابط مختصر (PATCH /v1/links/:id، تحديث جماعي، أو upsert جماعي)منخفض
link.deletedعند حذف رابط مختصر حذفًا ناعمًا (DELETE /v1/links/:id أو حذف جماعي)منخفض
link.clickedعند تسجيل نقرة متتبَّعة (بشكل غير متزامن، بعد إعادة التوجيه عبر عامل النقرات)مرتفع
link.experiment.completedعند اكتمال تجربة A/B على رابط واختيار فائزمنخفض
campaign.createdعند إنشاء حملة (POST /v1/campaigns)منخفض
post.publishedعند نشر منشور اجتماعي بنجاح على جميع أهداف المنصاتمنخفض
webhook.testعند تشغيلك إرسال اختبار على نقطة نهايةعند الطلب

link.created

يحدث عند حفظ رابط مختصر جديد في مساحة عملك.

الاستخدامات الشائعة: مزامنة الروابط الجديدة مع CRM، تشغيل أتمتة ترحيب، أو فهرسة الروابط في متجر بحث خارجي.

حقول data.object:

الحقلالنوعالوصف
idstringمعرّف الرابط
short_codestringالرمز المختصر العام
titlestring | nullعنوان الرابط
original_urlstring | nullعنوان الوجهة
is_activebooleanما إذا كان الرابط نشطًا
company_idstring | nullالشركة المالكة (مساحة عمل الشركة)
campaign_idstring | nullالحملة المرتبطة، إن وجدت
link_group_idstring | nullمعرّف المجلد/المجموعة، إن وجد
created_atstringوقت الإنشاء بصيغة ISO 8601
JSON
{
  "id": "clink_abc123",
  "short_code": "summer",
  "title": "Summer sale",
  "original_url": "https://example.com/sale",
  "is_active": true,
  "company_id": "cmxyz_company",
  "campaign_id": "ccamp_abc",
  "link_group_id": null,
  "created_at": "2026-06-22T12:00:00.000Z"
}

link.updated

يحدث عند تعديل رابط مختصر موجود (الوجهة، العنوان، الوسوم، المجلد، إعدادات UTM، إلخ).

الاستخدامات الشائعة: الحفاظ على مزامنة الأنظمة الخارجية عند تغيّر رابط دون إعادة إنشائه.

حقول data.object: نفس حقول link.created (انظر أعلاه).

JSON
{
  "id": "clink_abc123",
  "short_code": "summer",
  "title": "Summer sale (updated)",
  "original_url": "https://example.com/sale-v2",
  "is_active": true,
  "company_id": "cmxyz_company",
  "campaign_id": "ccamp_abc",
  "link_group_id": "lgrp_promos",
  "created_at": "2026-06-22T12:00:00.000Z"
}

link.deleted

يحدث عند حذف رابط مختصر حذفًا ناعمًا (تعيين isActive إلى false). يتوقف الرابط عن العمل علنًا لكنه يظل في سجل مساحة عملك.

الاستخدامات الشائعة: إزالة الروابط من الكتالوجات الخارجية أو إيقاف الأتمتة المرتبطة بذلك الرمز المختصر.

حقول data.object: نفس شكل link.created، مع is_active دائمًا false.

الحقلالنوعالوصف
idstringمعرّف الرابط
short_codestringالرمز المختصر وقت الحذف
titlestring | nullعنوان الرابط
original_urlstring | nullعنوان الوجهة
is_activebooleanfalse بعد الحذف الناعم
company_idstring | nullالشركة المالكة
campaign_idstring | nullالحملة المرتبطة، إن وجدت
link_group_idstring | nullمعرّف المجلد/المجموعة، إن وجد
created_atstringوقت الإنشاء الأصلي
JSON
{
  "id": "clink_abc123",
  "short_code": "summer",
  "title": "Summer sale",
  "original_url": "https://example.com/sale",
  "is_active": false,
  "company_id": "cmxyz_company",
  "campaign_id": "ccamp_abc",
  "link_group_id": null,
  "created_at": "2026-06-22T12:00:00.000Z"
}

link.clicked

يحدث بعد تسجيل نقرة زائر. يُسلَّم بشكل غير متزامن (وليس في مسار إعادة التوجيه)، لذا توقع تأخيرًا طفيفًا تحت الحمل العالي.

الاستخدامات الشائعة: تحليلات النقرات الفورية، التوجيه الجغرافي في منظومتك التقنية، تغذية نشاط CRM، أو الإدخال إلى مستودع البيانات.

الخصوصية: تتضمن الحمولات أبعاد الموقع الجغرافي والجهاز، وليس عناوين IP الخام.

حقول data.object:

الحقلالنوعالوصف
idstringمعرّف الرابط
link_idstringنفس id
short_codestringالرمز المختصر الذي تم النقر عليه
titlestring | nullعنوان الرابط
countrystring | nullرمز الدولة بصيغة ISO (بحث جغرافي)
citystring | nullالمدينة من البحث الجغرافي
devicestring | nullفئة الجهاز (مثل mobile، desktop)
browserstring | nullاسم المتصفح
osstring | nullنظام التشغيل
platformstring | nullإشارة المنصة من تحليل وكيل المستخدم
referrerstring | nullعنوان المُحيل عند توفره
routing_rule_idstring | nullقاعدة التوجيه الجغرافي/الجهاز المطابقة، إن وجدت
experiment_variant_idstring | nullمعرّف نسخة A/B عندما تكون النقرة قد مرّت عبر تجربة
clicked_atstringوقت النقرة بصيغة ISO 8601
JSON
{
  "id": "clink_abc123",
  "link_id": "clink_abc123",
  "short_code": "summer",
  "title": "Summer sale",
  "country": "NL",
  "city": "Amsterdam",
  "device": "mobile",
  "browser": "Chrome",
  "os": "iOS",
  "platform": null,
  "referrer": "https://instagram.com/",
  "routing_rule_id": null,
  "experiment_variant_id": null,
  "clicked_at": "2026-06-22T12:00:00.000Z"
}

link.experiment.completed

يحدث عند وضع علامة "مكتمل" على اختبار A/B لرابط مختصر واختيار نسخة فائزة.

الاستخدامات الشائعة: تسجيل نتائج التجارب، تحديث لوحات المعلومات، أو تشغيل حملات متابعة بناءً على الفائز.

حقول data.object:

الحقلالنوعالوصف
idstringمعرّف التجربة
link_idstringمعرّف الرابط الأب
short_codestring | nullالرمز المختصر للرابط الأب
statusstringcompleted
assignment_modestring | nullكيفية تقسيم حركة البيانات (مثل التوزيع الموزون)
winning_variant_idstring | nullمعرّف النسخة الفائزة
ended_atstring | nullوقت الاكتمال بصيغة ISO 8601
variantsarrayنتائج كل نسخة (انظر أدناه)

كل عنصر في variants:

الحقلالنوعالوصف
idstringمعرّف النسخة
labelstringتسمية مقروءة للبشر
weightnumberوزن حركة البيانات المستخدم في الاختبار
destination_urlstringعنوان URL الذي وجّهت هذه النسخة الزوار إليه
clicksnumberإجمالي النقرات المسجلة لهذه النسخة
JSON
{
  "id": "lexp_abc123",
  "link_id": "clink_abc123",
  "short_code": "summer",
  "status": "completed",
  "assignment_mode": "weighted",
  "winning_variant_id": "lvar_b",
  "ended_at": "2026-06-22T14:00:00.000Z",
  "variants": [
    {
      "id": "lvar_a",
      "label": "Control",
      "weight": 50,
      "destination_url": "https://example.com/a",
      "clicks": 120
    },
    {
      "id": "lvar_b",
      "label": "Variant B",
      "weight": 50,
      "destination_url": "https://example.com/b",
      "clicks": 184
    }
  ]
}

campaign.created

يحدث عند إنشاء حملة جديدة في مساحة عملك.

الاستخدامات الشائعة: تجهيز مجلدات حملات في أدوات خارجية، بدء سير عمل الإسناد (attribution)، أو إشعار مديري الحسابات.

حقول data.object:

الحقلالنوعالوصف
idstringمعرّف الحملة
namestringاسم الحملة
descriptionstring | nullوصف الحملة
company_idstring | nullالشركة المالكة
user_idstring | nullالمستخدم المنشئ (الحملات الشخصية)
brand_idstring | nullنطاق العلامة التجارية عند تعيينه
created_atstringوقت الإنشاء بصيغة ISO 8601
JSON
{
  "id": "ccamp_abc123",
  "name": "Summer launch",
  "description": "Q2 product push",
  "company_id": "cmxyz_company",
  "user_id": null,
  "brand_id": "cbrand_abc",
  "created_at": "2026-06-22T12:00:00.000Z"
}

post.published

يحدث عند نشر منشور مجدوَل أو فوري بنجاح إلى جميع أهداف المنصات المهيّأة.

الاستخدامات الشائعة: إشعار الأنظمة التابعة بأن المحتوى مباشر، إغلاق حلقة أتمتة الحملات، أو مزامنة حالة النشر مع مستودع بيانات.

ملاحظة: يُصدَر فقط عند نجاح جميع الأهداف. حالات الفشل الجزئي لا تُصدر هذا الحدث حاليًا.

حقول data.object:

الحقلالنوعالوصف
idstringمعرّف المنشور
post_idstringنفس id
statusstringPUBLISHED
company_idstring | nullالشركة المالكة
user_idstring | nullالمستخدم المالك (مساحة عمل شخصية)
brand_idstring | nullنطاق العلامة التجارية عند تعيينه
campaign_idstring | nullالحملة المرتبطة عند تعيينها
published_atstringوقت النشر بصيغة ISO 8601
platform_countnumberعدد أهداف المنصات على المنشور
JSON
{
  "id": "cpost_abc123",
  "post_id": "cpost_abc123",
  "status": "PUBLISHED",
  "company_id": "cmxyz_company",
  "user_id": null,
  "brand_id": "cbrand_abc",
  "campaign_id": "ccamp_abc123",
  "published_at": "2026-06-22T12:00:00.000Z",
  "platform_count": 3
}

webhook.test

نبضة اختبارية تُرسل فقط عند الضغط على إرسال اختبار في لوحة التحكم أو استدعاء POST /v1/webhooks/endpoints/:id/test.

الاستخدامات الشائعة: التحقق من صحة عنوان الاستقبال الخاص بك، طبقة TLS، التحقق من التوقيع، ومعالجة الاستجابة قبل الانتقال إلى الإنتاج.

حقول data.object:

الحقلالنوعالوصف
endpoint_idstringنقطة النهاية التي استلمت الاختبار
messagestringرسالة ثابتة: Styrar webhook test ping
JSON
{
  "endpoint_id": "wh_ep_abc123",
  "message": "Styrar webhook test ping"
}

أمثلة الـ API

عرض نقاط النهاية

RequestGET
Authorization: Bearer sty_live_your_api_key
Response200 OK
[
  {
    "id": "wh_ep_abc123",
    "url": "https://your-app.com/webhooks/styrar",
    "description": "Production CRM sync",
    "enabled": true,
    "eventTypes": ["link.clicked", "link.created"],
    "secretPrefix": "whsec_l",
    "companyId": "cmxyz_company",
    "userId": null,
    "disabledAt": null,
    "createdAt": "2026-06-22T12:00:00.000Z",
    "updatedAt": "2026-06-22T12:00:00.000Z"
  }
]

استقبال حدث على خادمك

عند حدوث حدث مشترَك فيه، تقوم Styrar بإرسال POST إلى عنوان نقطة نهايتك. هذه هي الحمولة التي يستلمها معالجك:

RequestPOST
Content-Type: application/json
Styrar-Event-Id: evt_outbox_abc123
Styrar-Event-Type: link.clicked
Styrar-Signature: t=1719052800,v1=8f4b2c1a9e0d3f7b6a5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3
User-Agent: Styrar-Webhooks/1.0

{
  "id": "evt_outbox_abc123",
  "type": "link.clicked",
  "api_version": "2026-06-22",
  "created_at": "2026-06-22T12:00:00.000Z",
  "workspace": {
    "type": "company",
    "company_id": "cmxyz_company"
  },
  "data": {
    "object": {
      "id": "clink_abc123",
      "link_id": "clink_abc123",
      "short_code": "summer",
      "title": "Summer sale",
      "country": "NL",
      "city": "Amsterdam",
      "device": "mobile",
      "browser": "Chrome",
      "os": "iOS",
      "referrer": "https://instagram.com/",
      "routing_rule_id": null,
      "experiment_variant_id": null,
      "clicked_at": "2026-06-22T12:00:00.000Z"
    }
  }
}
Response200 OK
{
  "received": true
}

يمكن أن يكون جسم استجابتك فارغًا. أعد أي حالة 2xx بعد التحقق من التوقيع وقبول الحدث. تعيد Styrar المحاولة عند الاستجابات غير 2xx.

حمولة نبضة الاختبار

يقوم إجراء إرسال اختبار بتسليم webhook.test بحمولة أصغر:

RequestPOST
Content-Type: application/json
Styrar-Event-Id: evt_test_abc123
Styrar-Event-Type: webhook.test
Styrar-Signature: t=1719052800,v1=...

{
  "id": "evt_test_abc123",
  "type": "webhook.test",
  "api_version": "2026-06-22",
  "created_at": "2026-06-22T12:00:00.000Z",
  "workspace": {
    "type": "company",
    "company_id": "cmxyz_company"
  },
  "data": {
    "object": {
      "endpoint_id": "wh_ep_abc123",
      "message": "Styrar webhook test ping"
    }
  }
}
Response200 OK

عرض عمليات التسليم الأخيرة

RequestGET
Authorization: Bearer sty_live_your_api_key
Response200 OK
[
  {
    "id": "wh_del_abc123",
    "endpointId": "wh_ep_abc123",
    "outboxEventId": "wh_out_abc123",
    "eventType": "link.clicked",
    "status": "delivered",
    "attemptCount": 1,
    "lastStatusCode": 200,
    "lastError": null,
    "durationMs": 142,
    "nextAttemptAt": null,
    "deliveredAt": "2026-06-22T12:00:01.000Z",
    "createdAt": "2026-06-22T12:00:00.500Z"
  }
]

إدارة نقاط النهاية

Plain text
GET    /v1/webhooks/endpoints?companyId={id}
POST   /v1/webhooks/endpoints
GET    /v1/webhooks/endpoints/:id
PATCH  /v1/webhooks/endpoints/:id
DELETE /v1/webhooks/endpoints/:id
POST   /v1/webhooks/endpoints/:id/test
POST   /v1/webhooks/endpoints/:id/rotate-secret
الحقلالوصف
urlعنوان رد اتصال HTTPS (يُسمح بـ HTTP فقط في بيئة التطوير المحلية)
descriptionتسمية اختيارية
eventTypesمصفوفة أنواع الأحداث المشترَك بها؛ الفارغة تعني جميع الأحداث
enabledالافتراضي true

يُعاد سر التوقيع (whsec_live_… / whsec_test_…) مرة واحدة فقط عند الإنشاء وعند rotate-secret. يمكنك تسجيل ما يصل إلى 25 نقطة نهاية لكل نطاق مساحة عمل.

عمليات التسليم

Plain text
GET  /v1/webhooks/deliveries?endpointId={id}
GET  /v1/webhooks/deliveries/:id
POST /v1/webhooks/deliveries/:id/retry

يتتبع كل سجل تسليم status و attemptCount و nextAttemptAt و lastStatusCode و lastError و deliveredAt. افحص حالات الفشل في لوحة التحكم تحت الإعدادات ← الـ Webhooks أو أعد المحاولة عبر الـ API.

صيغة التسليم

كل حدث فعلي هو طلب HTTP POST إلى عنوان رد الاتصال الخاص بك. تظهر الرؤوس والجسم في استقبال حدث على خادمك أعلاه.

الرأسالوصف
Styrar-Event-Idمعرّف الحدث الفريد (استخدمه لإزالة التكرار)
Styrar-Event-Typeمثل link.clicked
Styrar-Signaturet={unix_ts},v1={hmac_sha256_hex}
User-AgentStyrar-Webhooks/1.0

حقول المغلّف:

الحقلالوصف
idمعرّف الحدث (يطابق Styrar-Event-Id)
typeسلسلة نوع الحدث
api_versionإصدار مخطط الحمولة
created_atطابع زمني ISO 8601
workspaceنطاق company أو personal
data.objectالحمولة الخاصة بالحدث

تتضمن حمولات النقرات أبعاد الموقع الجغرافي والجهاز، وليس عناوين IP الخام.

التحقق من التوقيعات

يتبع التوقيع نمطًا على غرار Stripe. يوقّع "{timestamp}.{raw_body}" باستخدام HMAC-SHA256 وسر نقطة النهاية الخاص بك.

  1. حلّل Styrar-Signature إلى t (طابع زمني unix) و v1 (digest سداسي عشري).
  2. ارفض إذا كان t خارج نطاق التسامح الخاص بك (نوصي بـ 5 دقائق).
  3. احسب الـ digest المتوقع وقارنه مع v1 باستخدام فحص بزمن ثابت.
JavaScript
import crypto from 'node:crypto'

function verifyStyrarWebhook(secret, signatureHeader, rawBody, toleranceSeconds = 300) {
  const parts = Object.fromEntries(
    signatureHeader.split(',').map((part) => part.trim().split('=')),
  )

  const timestamp = Number(parts.t)
  const receivedDigest = parts.v1 || ''

  if (!Number.isFinite(timestamp)) return false
  if (Math.abs(Date.now() / 1000 - timestamp) > toleranceSeconds) return false

  const expectedDigest = crypto
    .createHmac('sha256', secret)
    .update(\`${timestamp}.${rawBody}\`)
    .digest('hex')

  try {
    return crypto.timingSafeEqual(
      Buffer.from(expectedDigest, 'utf8'),
      Buffer.from(receivedDigest, 'utf8'),
    )
  } catch {
    return false
  }
}

تحقق دائمًا من جسم الطلب الخام قبل تحليل JSON.

الموثوقية

  • عمليات التسليم تتم مرة واحدة على الأقل. أزل التكرار باستخدام Styrar-Event-Id أو id المغلّف.
  • تُعاد محاولة عمليات التسليم الفاشلة بتأخير تصاعدي حتى النجاح أو الوصول إلى الحد الأقصى من المحاولات.
  • إذا أعاد خادمك HTTP 410، تقوم Styrar بتعطيل نقطة النهاية تلقائيًا.
  • استجب بـ 2xx بمجرد قبولك للحدث؛ عالج الأعمال الثقيلة بشكل غير متزامن.

الحدود

  • يلزم HTTPS في بيئة الإنتاج لعناوين رد الاتصال.
  • 25 نقطة نهاية كحد أقصى لكل نطاق مساحة عمل شخصية أو شركة.
  • تُعرض أسرار التوقيع مرة واحدة عند الإنشاء والتدوير؛ احفظها في مدير الأسرار الخاص بك.

ذو صلة

Join the beta waitlist

By signing up you agree to receive marketing email. See our Privacy Policy.