What makes payment requirements different from a typical CRUD feature: correctness over speed, the impossibility of a true 'undo,' regulatory constraints, and the functional/non-functional list a real payment feature needs before any code.
Published September 23, 2026
Payment features get requirements wrong more often than most other features, specifically because the failure cost is asymmetric: a bug in a typical feature is annoying; a bug in payment is either lost revenue or a customer charged incorrectly — both expensive, both hard to walk back cleanly. This lesson establishes the requirements list before any implementation.
Most features optimize for responsiveness first, correctness second (a slightly stale product recommendation is a non-event). Payment inverts this: a slow-but-correct charge is vastly preferable to a fast-but-possibly-duplicated or possibly-lost one. Every subsequent design decision in this cluster (Idempotency Implementation, Failure Handling & Reconciliation) exists specifically to protect correctness, even where it costs latency or implementation complexity.
A failed database write: roll back the transaction, nothing happened, clean.
A failed payment charge: the charge may have ALREADY reached the payment processor
and succeeded on their end, even if YOUR service never received the success response
(e.g. the response was lost to a network failure after the charge itself succeeded).
"Rolling back" now means ISSUING A REFUND, a separate, visible, sometimes-delayed operation
— not a clean, instantaneous undo.
This single fact — that a payment failure mode can leave you not knowing whether money actually moved — is what makes idempotency (Payment — Idempotency Implementation) and reconciliation (Payment — Failure Handling & Reconciliation) non-optional, not nice-to-haves. A design that assumes payment failures behave like database failures (clean, atomic, fully reversible) is a design with a real correctness gap.
PCI-DSS (the Payment Card Industry Data Security Standard) isn't a suggestion — it's a mandatory compliance requirement for any system that stores, processes, or transmits card data, with real audit and liability consequences for non-compliance (covered fully in Payment — Security). This changes the requirements list itself: "we will never store raw card numbers" isn't an implementation detail decided later, it's a functional requirement stated up front, because it changes which components even need to exist (a tokenization step becomes mandatory, not optional).
Q: Why not just always retry a failed payment request automatically until it succeeds? A: Because without idempotency guarantees (Payment — Idempotency Implementation), a naive automatic retry risks charging the customer multiple times for what the client believes is one request — retries are safe only once idempotency is actually implemented, not before.
Q: Is 'no true undo' unique to payments, or does it apply to other systems too? A: It applies to any operation with an external, real-world side effect outside your own database's transaction boundary (sending an email, calling a third-party shipping API) — payment is simply the highest-stakes, most commonly-discussed example, and the same idempotency/reconciliation thinking applies to those other external-side-effect operations too.
Q: Should refunds share the same code path as charges, given they're both 'move money'? A: They should share infrastructure (the same processor integration, similar idempotency handling) but not the same code path — a refund has different business rules (partial refunds, refund windows, reason codes) and different failure semantics, and conflating the two typically produces harder-to-reason-about code than treating them as related-but-distinct operations.
Q: How do these requirements change for a system that only ever charges a FIXED subscription amount, vs one with arbitrary variable amounts? A: The core requirements (idempotency, auditability, no-true-undo) apply identically either way; a fixed-amount subscription system can additionally simplify around predictable retry/dunning schedules (see typical subscription-billing patterns), while variable-amount, one-off charges need more flexible amount validation and fraud-check integration at charge time.