Skip to content
← All articles
Stop shipping `isPaid: true`
Insight· 2 min read

Stop shipping `isPaid: true`

Most payment bugs are vocabulary bugs. Accepted is not confirmed. Confirmed is not settled. The three-state model this blog starts from — and why your boolean is lying to finance.

Support closed the ticket. The app showed green. Finance opened Monday's settlement file and three rows were missing.

Nobody lied. Your schema did.

isPaid: true collapses three different moments into one bit. That bit is enough for a demo. It is not enough for a ledger, a dispute, or an auditor.

Three states, not one boolean

StateWhat actually happenedWhat you may show the user
AcceptedProvider took the request; debit may still fail"Processing…"
ConfirmedWallet / card hold succeeded; float moved"Paid" — with an asterisk ops owns
SettledBatch / bank file closed the loopRevenue finance will recognize

Card rails call these auth → capture → settlement. Mobile money often hides them behind one callback named SUCCESS. Same money. Same trap. Different names.

If your domain model has a single boolean, you will eventually lie to at least one audience: the customer, support, or finance.

Why this is the entry point

This blog exists for teams that move money in markets where callbacks are late, providers are slow-not-down, and "it worked in staging" means nothing across eleven subsidiaries.

The rest of the catalog is the same thesis, applied:

The rule that survives every rail

UI copy  ≠  provider status  ≠  ledger truth  ≠  bank settlement

Map each of those to an explicit state. Persist transitions. Reconcile on a schedule. Never let a spinner invent certainty.

Ship states finance can defend. Booleans are for feature flags — not for money.

The sequel is what happens when you ship the three states and still copy the provider's word: The callback that said SUCCESS.

Want to apply this on your platform?

Describe your tech landscape and constraints — I'll offer straightforward advice if there's a technical match.