Idempotent usage events with transaction_id
A short engineering note on sending usage from queues and retries without ever double-billing a customer.

If you emit usage from a job queue, a worker will eventually crash after sending an event but before marking it done. The queue redelivers; the event is sent again. Without idempotency, that customer is billed twice.
The contract
POST /api/v1/events accepts customer_id, event_name, transaction_id and properties. The first call with a given transaction_id returns 202 { status: processed }. Any later call with the same ID returns 202 { status: duplicate } and changes nothing.
Choosing the ID
Use something that is stable across retries and unique per real-world occurrence: the job ID, the request ID, or a hash of (customer, meter, timestamp bucket). Do not generate a fresh UUID at send time — that defeats the purpose.
What to do with duplicate
Treat it as success. Log it if you want visibility into retry rates, but never alert on it; it is the system working.
Payments · 26 Oct 2026
Usage billing · 11 Oct 2026
Usage billing · 8 Oct 2026