Webhook Idempotency
Sangho guarantees at-least-once delivery: an event may be delivered more than once in the event of a network failure, timeout, or server restart. Your endpoint must be idempotent — processing the same event twice must not produce additional side effects.
Deduplication strategy
- 1. Extract the
Sangho-Event-IDfrom the header (orevent.idfrom the body). - 2. Check in your database whether this ID has already been processed.
- 3. If yes → return
200immediately without reprocessing. - 4. If no → process the event, then record the ID.
Do not use an in-memory Set in production — it resets on
server restart. Use a SQL table with a PRIMARY KEY constraint
on event_id, or Redis with SET NX
(SET if Not eXists).
In PostgreSQL and SQLite, use INSERT … ON CONFLICT (event_id) DO NOTHING for atomic
deduplication with no race condition, even under concurrent load.
Deduplication (Node.js)
SQL deduplication model
Create a dedicated table to store already-processed event IDs. The PRIMARY KEY constraint on event_id
guarantees uniqueness at the database level, even under concurrent requests.
Add an index on processed_at to facilitate periodic cleanup
of old records (after 30 days, for example).
Sangho will never redeliver an event after 48 hours. You can safely delete deduplication records older than 72 hours. Schedule a cleanup job via Celery Beat, cron, or a scheduled task.