Designing Idempotent Webhook Consumers in Node.js
Webhook providers retry aggressively. Without idempotency, one payment or event can be processed multiple times. The consumer must be repeat-safe by design.
Step 1: Build an idempotency key from provider event ID
function idemKey(provider: string, eventId: string) {
return `${provider}:${eventId}`;
}
Step 2: Use atomic insert-or-ignore before processing
INSERT INTO processed_events (idem_key, received_at)
VALUES ($1, NOW())
ON CONFLICT (idem_key) DO NOTHING;
Step 3: Return success for duplicates after dedupe
if (!inserted) {
return res.status(200).json({ ok: true, duplicate: true });
}
Common pitfall
Checking duplicates in memory only. Process restarts and horizontal scale will break it.
What to check
- Retries do not create duplicate side effects.
- Dedupe table survives restarts and deployments.
- Metrics show duplicate ratio per provider.