New — webhooks your AI agents can wait on. Hook & Sense opening to early access.

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

Test idempotency the way agents experience it: HookSense's `replay_callback` re-fires a captured callback 10× at your handler so you can confirm the side effects only happen once — even when an agent retries a `wait_for_callback`.

Get a free webhook URL

Related terms