Taking a payment is the easy half. Knowing, a month later, exactly what happened to a particular payment — and being able to show it to a bank, an auditor or an annoyed customer — is the half that earns trust. In fintech work most of our engineering effort goes into the parts nobody demos.
One ledger, append only
State machines that update a row in place lose the one thing you need during an investigation: the order in which things happened. We write immutable entries and derive the current state from them. Reversals are new entries, never edits. It costs a little storage and saves entire afternoons.
- Entries are written once and never edited
- A reversal is a new entry that points at the original
- The current balance is derived, so it can always be recomputed
Never invent a result the provider has not confirmed. A timeout is an unknown, not a failure.
Reconciliation is a feature, not a script
Provider statements and internal records drift apart for ordinary reasons: timing windows, fees booked separately, a retry that landed after a timeout. We build reconciliation as a first-class part of the system, with a screen that shows what matched, what did not, and why — rather than a cron job that emails a CSV to one person.
Design the retry before the first transaction
Timeouts are not failures; they are unknowns. Idempotency keys, bounded retries with backoff, and an explicit "we do not know yet" status keep an unknown from quietly becoming a double charge. The rule we hold to: never invent a result the provider has not confirmed.
Make compliance work visible early
Audit trails, data retention and access control are far cheaper to design in than to retrofit under deadline. We prefer to agree with the compliance side in week one what must be logged, for how long, and who may read it — so the first external review is a formality rather than a project.