Skip to main content

Use cases

Webhook reliability patterns (retry, idempotence, replay)

Exponential retry, event_id dedup, manual replay

Scell.io retries each webhook with exponential backoff (5 attempts over 24h: 1min, 5min, 30min, 2h, 12h). On the receiver side you must implement three patterns: (1) verify the HMAC-SHA256 signature in `X-Scell-Signature`, (2) deduplicate on `event_id` to handle legitimate duplicates (network retries, manual replay), (3) respond 2xx within 5s or delivery is considered failed and a retry is scheduled. To replay a webhook use `POST /api/v1/webhooks/{id}/replay` or inspect logs via `GET /api/v1/webhooks/{id}/logs`.

Key facts

  • 5 retries over 24h, backoff 1min → 12h
  • `X-Scell-Signature` HMAC-SHA256 header
  • `X-Scell-Timestamp` anti-replay header (5min tolerance)
  • Stable `event_id` UUID, idempotent on receiver side
  • `POST /api/v1/webhooks/{id}/replay` endpoint for manual replay
  • 30-day persistent logs via `GET /api/v1/webhooks/{id}/logs`

Code example

import { createHmac, timingSafeEqual } from 'node:crypto';
import type { Request, Response } from 'express';

const processed = new Set<string>(); // En prod : Redis SET avec TTL 7j

export async function webhookHandler(req: Request, res: Response) {
  const sig = req.header('X-Scell-Signature') ?? '';
  const ts = Number(req.header('X-Scell-Timestamp') ?? 0);
  const raw = (req as any).rawBody as string;

  // 1. Anti-replay
  if (Math.abs(Date.now() / 1000 - ts) > 300) return res.sendStatus(401);

  // 2. Verify HMAC
  const expected = createHmac('sha256', process.env.WEBHOOK_SECRET!).update(`${ts}.${raw}`).digest('hex');
  if (!timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) return res.sendStatus(401);

  // 3. Idempotency
  const event = JSON.parse(raw);
  if (processed.has(event.event_id)) return res.sendStatus(200);
  processed.add(event.event_id);

  await handleEvent(event);
  res.sendStatus(200); // < 5s
}

See also

Your cookie preferences

We use cookies to improve your experience. Essential cookies are always active. Cookie policy.