Launch special — let's split the check with SPLITCHECK for 50% off

Glossary

Idempotency

The property that processing the same webhook twice has the same effect as processing it once. Critical because providers retry deliveries.

Webhook providers retry failed deliveries — typically with exponential backoff over hours or days. They also occasionally double-deliver successful webhooks (network races, ack loss). If your handler isn't idempotent, retries cause double charges, duplicate emails, duplicate inventory deductions.

The standard pattern: every event has a unique ID (e.g., Stripe's evt_*, GitHub's X-GitHub-Delivery). Store processed IDs in a database with a unique constraint. On every incoming event: try to insert the ID — if it conflicts, return 200 immediately without re-running side effects.

Idempotency goes beyond dedup: if your handler partially fails and the provider retries, the second attempt should reconcile state, not re-do completed work. Design handlers as state machines, not scripts.

Idempotent handler using event ID as dedup key

async function handle(event: WebhookEvent) {
  const { rowCount } = await db.query(
    "INSERT INTO processed_events (id) VALUES ($1) ON CONFLICT DO NOTHING",
    [event.id],
  );
  if (rowCount === 0) return; // already processed
  await applyBusinessLogic(event);
}

How HookSense helps

HookSense's Replay feature is a great way to test idempotency: capture an event, replay it 10× against your handler, and confirm the side effects only happen once.

Get a free webhook URL

Related terms