Skip to content
tolapayBeta
Engineering · Usage billing · 5 Oct 2026 · 4 min read

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.

Related