← Field notes

Webhook idempotency without guesswork

Published March 2025 · Naledi Khumalo

Network cables plugged into a switch

Vendors retry webhooks when your endpoint times out or returns 5xx. Some also assign a new delivery ID on each attempt while the business payload stays identical. If you key idempotency only on the delivery ID, you will double-charge, double-ship, or double-email.

Prefer vendor business keys

Look for payment intent IDs, order references, or shipment tracking numbers in the body. Store processed keys in a table with a TTL longer than the vendor’s documented retry window—often 72 hours, but verify in their docs.

When no stable key exists

Hash a canonical JSON representation of fields that define the business event, excluding timestamps and delivery metadata. Document the canonicalisation rules in your handler so the next engineer does not “fix” whitespace and break deduplication.

Respond quickly

Acknowledge with 2xx after the event is persisted to your queue, not after all downstream work finishes. Process asynchronously so retries do not stack during slow database migrations.

Need a second pair of eyes on your handlers? Book an integration review.