Webhooks · v1

Webhooks — يدفعها CD4CD، يستقبلها سيرفرك.

سجّل endpoint مرة واحدة، واستقبل تدفّق أحداث منظّم. توقيع HMAC على كل payload، إعادة محاولة ذكية، JSON بسيط.

التسجيل

سجّل عبر /dashboard/api → New webhook أو عبر REST API:

POST /v1/webhooks
Authorization: Bearer cd_live_xxx

{
  "endpoint": "https://hooks.aljazera.sa/cd4cd",
  "events":   ["link.clicked", "link.created"],
  "secret":   "auto"
}

→ 201 Created
{ "id": "wh_8f3c", "endpoint": "...", "secret": "whsec_xyz" }

الأحداث المتاحة

الحدثالوصف
link.createdعند إنشاء رابط جديد.
link.updatedعند تعديل الوجهة أو الـ alias.
link.deletedعند حذف رابط.
link.clickedفي كل نقرة (مع breakdown).
qr.createdعند إنشاء QR جديد.
qr.scannedكل فحص QR.
bio.visitedكل زيارة لصفحة Bio.
security.flaggedعند تعليم رابط بطل بالطبقات الأمنية.

مثال: link.clicked

POST https://hooks.aljazera.sa/cd4cd
CD4CD-Signature: t=1715583720,v1=8f3c…a91
Content-Type: application/json

{
  "id":   "evt_18f3c_a91",
  "type": "link.clicked",
  "createdAt": "2026-05-13T05:42:00.123Z",
  "data": {
    "linkId":   "lnk_8f3c_a91",
    "shortCode": "promo-2026",
    "longUrl":   "https://example.com/long/path",
    "country":   "SA",
    "device":    "mobile",
    "os":        "iOS",
    "referrer":  "https://t.co/abc"
  }
}

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

كل webhook يحمل header CD4CD-Signature. احسب HMAC_SHA256(secret, t + "." + body) وقارن مع v1.

// Node.js
import crypto from 'node:crypto';

const sig = req.headers['cd4cd-signature']; // t=..,v1=..
const [tPart, vPart] = sig.split(',');
const t = tPart.slice(2);
const v1 = vPart.slice(3);

const expected = crypto
  .createHmac('sha256', WEBHOOK_SECRET)
  .update(`${t}.${req.rawBody}`)
  .digest('hex');

if (expected !== v1) return res.status(401).end();

إعادة المحاولة

إذا لم نستلم 2xx خلال ١٠ ثوانٍ، نُعيد المحاولة بـ exponential backoff:

  • 1m → 5m → 15m → 1h → 6h → 24h
  • بعد ٦ محاولات فاشلة، نُعطّل الـ webhook ونرسل بريداً.

الـ Idempotency

كل حدث له id. احفظ آخر ٧ أيام منها لتجاهل التكرار.