Advanced

Webhooks and automation

Subscribe to events, verify signatures, chain distro into your stack.

9 minUpdated 2026-04-19

Webhooks let you react to distro events in your own systems. Common uses: piping shipped posts into an internal dashboard, triggering a CI build when an idea moves to Drafting, posting to a team Slack when a peer review arrives.

Creating a webhook

Settings → API → Webhooks → New. You provide:

  • An endpoint URL (HTTPS required)
  • A subset of events to subscribe to (or "all events")
  • Optionally, specific apps to scope to (default: all your apps)

On save, we generate a signing secret (whsec_...) shown once. Verify incoming requests against it — we never send payloads that aren't signed.

Signature verification

// Node
import crypto from 'crypto';

function verify(rawBody, signatureHeader, secret) {
  const [t, v1] = signatureHeader.split(',').map(p => p.split('=')[1]);
  const signed = `${t}.${rawBody}`;
  const expected = crypto
    .createHmac('sha256', secret)
    .update(signed)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(v1)
  );
}

Header is distro-signature. Reject on mismatch. Reject if the timestamp is more than 5 minutes old (replay protection).

Event payload shape

{
  "id": "evt_01HRXZ...",
  "type": "idea.evaluated",
  "created": 1713456789,
  "livemode": true,
  "data": {
    "idea": { "id": "...", "title": "...", "composite": 78, ... }
  }
}

Retries

We retry non-2xx responses with exponential backoff: 10s, 30s, 2m, 15m, 1h. Give up after 5 attempts. Each attempt has a 10-second timeout.

Test and replay

The webhook detail page shows the last 100 deliveries with status, response body, latency. Click any failed delivery to Resend. Useful when your handler had a bug and you want to re-run after deploying a fix.