← All work

At work

Transket · Jul 2025 – Present

Credit ledger & billing

An append-only credit ledger where the stored balance is a cache, the ledger sum is source of truth, and retries cannot double-charge.

See in graph

The problem

Webhook redelivery and worker retries are normal. If a charge is applied by “update the balance,” a second delivery silently spends the customer twice. Vendor cost and customer price also move independently, so a single currency field cannot be both an audit trail and a live price list.

What it is

Messaging products that sell prepaid credits cannot treat a number in a column as money. I designed the billing core so every debit and credit is an immutable ledger entry, pricing can vary by region without rewriting history, and payment webhooks are safe to replay.

What I built

The ledger is append-only and immutable. A running balance exists for reads, but it is a cache. The sum of ledger entries is what the system believes. Every write carries an idempotency key, so a retried webhook or a restarted worker cannot insert a second charge for the same event.

Credits are a currency-neutral unit. A versioned regional price book maps those units to what a vendor pays and what a customer is billed. Cost and price can change without rewriting historical debits, which stay auditable in the units that were actually spent.

Two payment gateways sit behind one adapter interface. Inbound webhooks are signature-verified before they ever reach the ledger, so a forged or replayed payload does not become a credit.

How it fails

Failure is supposed to be loud. A write that cannot prove it is unique does not guess; it no-ops or errors. A balance that disagrees with the ledger is a cache bug, not a new source of truth. Migrations that touch money are designed to be reversible without silent correction of history.

Focus

  • Append-only double-entry ledger as source of truth
  • Idempotent writes for webhooks and workers
  • Currency-neutral credits with a versioned regional price book
  • Two payment gateways behind one adapter

What changed

  • Charges survive webhook redelivery and worker retries without double-spend.
  • Regional pricing and vendor cost can move independently of historical ledgers.
  • Payment providers can be added without teaching the rest of the product about each gateway.

Built with

DjangoPostgreSQLRedisCeleryAWS