Skip to content

Idempotency

While Transyt deduplicates events at the ingestion level, your application may still receive the same event more than once — for example, if a delivery times out but your app actually processed it, or during a replay.

  • Delivery timeout — Your app processed the event but didn’t respond within 30 seconds, so Transyt retried
  • Manual replay — Someone replayed the event from the dashboard or API
  • Network issues — The response was lost in transit

Every delivery includes a unique event_id (UUID). Store processed event IDs and skip any you’ve already seen:

# Rails example
def process_webhook(payload)
event_id = payload["event_id"]
# Skip if already processed
return if ProcessedEvent.exists?(event_id: event_id)
ActiveRecord::Base.transaction do
ProcessedEvent.create!(event_id: event_id)
# Process the event...
end
end

The external_id field contains the provider’s own deduplication key (e.g., Stripe’s evt_xxx). This can be useful for cross-referencing with the provider’s records:

return if Payment.exists?(stripe_event_id: payload["external_id"])

Design your processing logic so that applying the same event twice produces the same result:

  • Use upsert instead of insert for database operations
  • Check the current state before making changes
  • Use unique constraints at the database level

After processing, you can explicitly acknowledge events via the API:

Terminal window
# Mark as processed
curl -X POST https://ingest.transyt.com/admin/events/{event_id}/ack \
-H "X-Admin-Token: YOUR_ADMIN_TOKEN"
# Mark as failed
curl -X POST https://ingest.transyt.com/admin/events/{event_id}/fail \
-H "X-Admin-Token: YOUR_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"error": "Insufficient inventory"}'