The ledger
By the end of this track you can design a system that never loses money.
0/4 finished
Step 1
The idea
Store amounts as integer shillings, keep receipts unique, save the raw events, and never edit money in place.
Step 2
How it works
Integers, not floats
M-Pesa amounts are whole shillings. Store them as integers. Floats round in surprising ways, and money columns must add up exactly.
Never edit money
A ledger is a list of entries that only grows. A refund or reversal is a new entry pointing at the original, so the history always explains the balance.
CREATE TABLE ledger ( id BIGSERIAL PRIMARY KEY, payment_id BIGINT REFERENCES payments(id), kind TEXT NOT NULL, -- charge, refund, reversal, payout amount BIGINT NOT NULL, -- KES, negative for money out receipt TEXT UNIQUE, refers_to BIGINT REFERENCES ledger(id), created_at TIMESTAMPTZ NOT NULL DEFAULT now());Keep the raw events
Save every callback and result body exactly as it arrived, in its own table. When a customer disputes a payment, that is your evidence.
Step 3
Try it
Sketch your payments table with those rules.
Step 4
Common mistakes
- Using FLOAT or DOUBLE for money.
- UPDATE-ing an amount to apply a refund.
- Throwing raw callbacks away once they are processed.
Go deeper
How do you record a refund?
Answer in your own words first.
Show the answerHide the answer
As a new entry that points at the original payment, not by editing the original.