الـ 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. إنشاء نقطة نهاية من لوحة التحكم
- سجّل الدخول وافتح الإعدادات ← الـ Webhooks (
/settings/webhooks). - تحت نقاط النهاية، أدخل عنوان نقطة النهاية (عنوان رد الاتصال HTTPS العام).
- أضف وصفًا اختياريًا (مثل "مزامنة CRM للإنتاج").
- اختر الأحداث التي تريدها (يجب اختيار حدث واحد على الأقل). من الاختيارات الشائعة:
link.clickedلتتبع النقراتlink.created/link.updated/link.deletedلدورة حياة الروابطpost.publishedوcampaign.createdلأحداث مسار التحويل
- اضغط إضافة نقطة نهاية.
بعد الإنشاء، تعرض Styrar السر الخاص بالتوقيع (whsec_live_… أو whsec_test_…). انسخه فورًا واحفظه في مدير الأسرار الخاص بك. يظهر مرة واحدة فقط. إذا فقدته، استخدم تدوير السر على نقطة النهاية وحدّث خادمك.
4. إنشاء نقطة نهاية عبر الـ API
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"
]
}{
"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:
Authorization: Bearer sty_live_your_api_key{
"ok": true,
"statusCode": 200
}عند نجاح الاختبار، يجب أن يكون خادمك قد استلم حدث webhook.test (انظر استقبال حدث على خادمك أدناه).
تحقق من عمليات التسليم الأخيرة في لوحة التحكم (أو GET /v1/webhooks/deliveries) إذا فشل الاختبار. المشاكل الشائعة:
| المشكلة | ما يجب فحصه |
|---|---|
| رفض الاتصال / انتهاء المهلة | تأكد أن العنوان HTTPS عام، والجدار الناري يسمح بـ Styrar، والنفق (tunnel) يعمل |
| HTTP 4xx/5xx من تطبيقك | يجب أن يُرجع المعالج 2xx بعد التحقق؛ سجّل الجسم الخام والرؤوس |
| فشل التحقق من التوقيع | استخدم الجسم الخام، السر الصحيح، ومقارنة بزمن ثابت |
| نقطة النهاية معطّلة | أعد التفعيل من لوحة التحكم أو أصلح السبب الذي أدى إلى HTTP 410 |
6. التحقق من عمليات التسليم ومعالجتها
عند كل POST إلى عنوانك:
- حلّل
Styrar-Signatureإلى الطابع الزمنيtوالـ digestv1. - ارفض إذا كان
tأقدم من نطاق التسامح الخاص بك (يُنصح بـ 5 دقائق). - احسب HMAC-SHA256 لـ
"{t}.{raw_body}"باستخدام السر الخاص بنقطة النهاية. - قارن مع
v1باستخدام فحص بزمن ثابت. - حلّل JSON فقط بعد نجاح التحقق.
- احذف التكرارات بالاعتماد على
Styrar-Event-Id(التسليم يحدث مرة واحدة على الأقل).
انظر قسم التحقق من التوقيعات أدناه لمثال بلغة Node.js.
7. الانتقال إلى الإنتاج
- حافظ على نقطة النهاية مفعّلة في لوحة التحكم.
- اشترك فقط في الأحداث التي تحتاجها (يقلل من الضجيج والتكلفة).
- راقب عمليات التسليم الأخيرة بحثًا عن الفشل واستخدم إعادة المحاولة عند الحاجة.
- دوّر السر إذا كان من المحتمل أنه تسرّب (تدوير السر في لوحة التحكم أو
POST …/rotate-secret).
بداية سريعة
- احصل على صلاحية الوصول للـ API بصلاحيتي
webhooks:readوwebhooks:write(مفتاح API أو OAuth). - اكشف نقطة استقبال HTTPS عامة وأنشئ نقطة نهاية في الإعدادات ← الـ Webhooks أو عبر
POST /v1/webhooks/endpoints. - انسخ سر التوقيع عند ظهوره واحفظه بأمان.
- أرسل حدثًا اختباريًا وتأكد من أن خادمك يحقق
Styrar-Signatureويُرجع 2xx. - عالج الأحداث الفعلية مع إزالة التكرار بالاعتماد على
Styrar-Event-Id.
المصادقة
تتطلب إدارة الـ webhooks رمز Bearer يحمل الصلاحيات المذكورة في الخطوة 2 أعلاه. تعمل مفاتيح API ذات الصلاحيات المطابقة بنفس طريقة رموز وصول OAuth.
أنواع الأحداث
استدعِ GET /v1/webhooks/event-types للحصول على الكتالوج الفعلي في بيئتك. اشترك في أنواع محددة لكل نقطة نهاية، أو مرّر مصفوفة eventTypes فارغة لاستقبال جميع الأحداث.
webhook.test يُرسل فقط عند الضغط على إرسال اختبار؛ لا يُصدر من النشاط الطبيعي لمساحة العمل.
مغلّف الحدث (Event envelope)
تستخدم كل عملية تسليم نفس الشكل الأعلى مستوى. تعيش الحقول الخاصة بكل حدث تحت data.object:
| الحقل | النوع | الوصف |
|---|---|---|
id | string | معرّف الحدث الفريد. نفس القيمة الموجودة في رأس Styrar-Event-Id. |
type | string | اسم الحدث (مثل link.clicked). |
api_version | string | إصدار مخطط الحمولة (2026-06-22). |
created_at | string | طابع زمني ISO 8601 عند إنشاء الحدث. |
workspace.type | string | company أو personal. |
workspace.company_id | string | null | معرّف الشركة عندما يكون workspace.type هو company. |
data.object | object | حمولة الحدث (موثّقة لكل حدث أدناه). |
مثال كامل على التسليم (المغلّف + حمولة link.created):
{
"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:
| الحقل | النوع | الوصف |
|---|---|---|
id | string | معرّف الرابط |
short_code | string | الرمز المختصر العام |
title | string | null | عنوان الرابط |
original_url | string | null | عنوان الوجهة |
is_active | boolean | ما إذا كان الرابط نشطًا |
company_id | string | null | الشركة المالكة (مساحة عمل الشركة) |
campaign_id | string | null | الحملة المرتبطة، إن وجدت |
link_group_id | string | null | معرّف المجلد/المجموعة، إن وجد |
created_at | string | وقت الإنشاء بصيغة ISO 8601 |
{
"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 (انظر أعلاه).
{
"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.
| الحقل | النوع | الوصف |
|---|---|---|
id | string | معرّف الرابط |
short_code | string | الرمز المختصر وقت الحذف |
title | string | null | عنوان الرابط |
original_url | string | null | عنوان الوجهة |
is_active | boolean | false بعد الحذف الناعم |
company_id | string | null | الشركة المالكة |
campaign_id | string | null | الحملة المرتبطة، إن وجدت |
link_group_id | string | null | معرّف المجلد/المجموعة، إن وجد |
created_at | string | وقت الإنشاء الأصلي |
{
"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:
| الحقل | النوع | الوصف |
|---|---|---|
id | string | معرّف الرابط |
link_id | string | نفس id |
short_code | string | الرمز المختصر الذي تم النقر عليه |
title | string | null | عنوان الرابط |
country | string | null | رمز الدولة بصيغة ISO (بحث جغرافي) |
city | string | null | المدينة من البحث الجغرافي |
device | string | null | فئة الجهاز (مثل mobile، desktop) |
browser | string | null | اسم المتصفح |
os | string | null | نظام التشغيل |
platform | string | null | إشارة المنصة من تحليل وكيل المستخدم |
referrer | string | null | عنوان المُحيل عند توفره |
routing_rule_id | string | null | قاعدة التوجيه الجغرافي/الجهاز المطابقة، إن وجدت |
experiment_variant_id | string | null | معرّف نسخة A/B عندما تكون النقرة قد مرّت عبر تجربة |
clicked_at | string | وقت النقرة بصيغة ISO 8601 |
{
"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:
| الحقل | النوع | الوصف |
|---|---|---|
id | string | معرّف التجربة |
link_id | string | معرّف الرابط الأب |
short_code | string | null | الرمز المختصر للرابط الأب |
status | string | completed |
assignment_mode | string | null | كيفية تقسيم حركة البيانات (مثل التوزيع الموزون) |
winning_variant_id | string | null | معرّف النسخة الفائزة |
ended_at | string | null | وقت الاكتمال بصيغة ISO 8601 |
variants | array | نتائج كل نسخة (انظر أدناه) |
كل عنصر في variants:
| الحقل | النوع | الوصف |
|---|---|---|
id | string | معرّف النسخة |
label | string | تسمية مقروءة للبشر |
weight | number | وزن حركة البيانات المستخدم في الاختبار |
destination_url | string | عنوان URL الذي وجّهت هذه النسخة الزوار إليه |
clicks | number | إجمالي النقرات المسجلة لهذه النسخة |
{
"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:
| الحقل | النوع | الوصف |
|---|---|---|
id | string | معرّف الحملة |
name | string | اسم الحملة |
description | string | null | وصف الحملة |
company_id | string | null | الشركة المالكة |
user_id | string | null | المستخدم المنشئ (الحملات الشخصية) |
brand_id | string | null | نطاق العلامة التجارية عند تعيينه |
created_at | string | وقت الإنشاء بصيغة ISO 8601 |
{
"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:
| الحقل | النوع | الوصف |
|---|---|---|
id | string | معرّف المنشور |
post_id | string | نفس id |
status | string | PUBLISHED |
company_id | string | null | الشركة المالكة |
user_id | string | null | المستخدم المالك (مساحة عمل شخصية) |
brand_id | string | null | نطاق العلامة التجارية عند تعيينه |
campaign_id | string | null | الحملة المرتبطة عند تعيينها |
published_at | string | وقت النشر بصيغة ISO 8601 |
platform_count | number | عدد أهداف المنصات على المنشور |
{
"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_id | string | نقطة النهاية التي استلمت الاختبار |
message | string | رسالة ثابتة: Styrar webhook test ping |
{
"endpoint_id": "wh_ep_abc123",
"message": "Styrar webhook test ping"
}
أمثلة الـ API
عرض نقاط النهاية
Authorization: Bearer sty_live_your_api_key[
{
"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 إلى عنوان نقطة نهايتك. هذه هي الحمولة التي يستلمها معالجك:
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"
}
}
}{
"received": true
}يمكن أن يكون جسم استجابتك فارغًا. أعد أي حالة 2xx بعد التحقق من التوقيع وقبول الحدث. تعيد Styrar المحاولة عند الاستجابات غير 2xx.
حمولة نبضة الاختبار
يقوم إجراء إرسال اختبار بتسليم webhook.test بحمولة أصغر:
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"
}
}
}عرض عمليات التسليم الأخيرة
Authorization: Bearer sty_live_your_api_key[
{
"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"
}
]إدارة نقاط النهاية
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 نقطة نهاية لكل نطاق مساحة عمل.
عمليات التسليم
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-Signature | t={unix_ts},v1={hmac_sha256_hex} |
User-Agent | Styrar-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 وسر نقطة النهاية الخاص بك.
- حلّل
Styrar-Signatureإلىt(طابع زمني unix) وv1(digest سداسي عشري). - ارفض إذا كان
tخارج نطاق التسامح الخاص بك (نوصي بـ 5 دقائق). - احسب الـ digest المتوقع وقارنه مع
v1باستخدام فحص بزمن ثابت.
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 نقطة نهاية كحد أقصى لكل نطاق مساحة عمل شخصية أو شركة.
- تُعرض أسرار التوقيع مرة واحدة عند الإنشاء والتدوير؛ احفظها في مدير الأسرار الخاص بك.
ذو صلة
- نبضة التحويل — تتبع التحويلات على صفحات الوجهة التي لا تتحكم بها
- الروابط المختصرة وأكواد QR في مركز المساعدة
- مفاتيح API والتطبيقات المتصلة