Webhooks · v1

Webhooks — CD4CD pushes, your server receives.

Register one endpoint, receive a structured event stream. HMAC-signed payloads, smart retries, clean JSON.

Registration

Register via /dashboard/api → New webhook or via the 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" }

Available events

EventDescription
link.createdA new short link was created.
link.updatedLink destination or alias updated.
link.deletedLink deleted.
link.clickedEvery click (with breakdown).
qr.createdA new QR was created.
qr.scannedEvery QR scan.
bio.visitedEvery Bio page visit.
security.flaggedA link flagged by safety layers.

Example: 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"
  }
}

Verify the signature

Every webhook carries a CD4CD-Signature. Compute HMAC_SHA256(secret, t + "." + body) and compare against 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();

Retries

If we don't get a 2xx within 10s, we retry with exponential backoff:

  • 1m → 5m → 15m → 1h → 6h → 24h
  • After 6 failed attempts we pause the webhook and email you.

Idempotency

Each event has a unique id. Store the last 7 days to dedupe replays.