Refunds, disputes, and reconciliation
A refund a merchant initiates and a dispute a cardholder initiates look similar from a distance — money moves back — but they're different processes with different triggers, different costs, and different things a system needs to track.
3 min read
Refunds: merchant-initiated, straightforward
A refund is the merchant choosing to return some or all of a payment — a customer request, a service issue, an order cancellation. As covered in the payment-states lesson, this is a new transaction, not an edit of the original charge: money that was captured gets sent back, and the original payment record still shows it was, in fact, originally paid.
Full refund - the entire captured amount is returned
Partial refund - some amount less than the full captured amount is
returned (a partial cancellation, a discount
applied after the fact, a damaged-item credit)
Partial refunds matter for the ledger design covered later in this domain: a partially refunded payment needs to show both the original captured amount and the refunded amount as separate, visible facts — not a single field silently decremented, which would erase the record of what was actually charged in the first place.
Disputes (chargebacks): cardholder-initiated, adversarial by default
A dispute is fundamentally different: the cardholder (or their issuing bank, on the cardholder's behalf) formally contests a charge directly with their bank — "I didn't authorize this" or "I didn't receive what I paid for" — bypassing the merchant entirely as the first step. The bank typically pulls the funds back immediately, before the merchant has any chance to respond, and the merchant is then given a window to submit evidence (proof of delivery, terms agreed to, communication history) contesting the dispute.
This asymmetry — money already gone before the merchant even knows there's a problem — is why disputes are treated as a materially more serious event than a refund in most systems: they usually need their own tracked status, their own evidence-submission workflow, and are frequently a strong signal (at volume) of either a real fulfillment problem or fraudulent card use.
Reconciliation: the ongoing discipline underneath both
Reconciliation is the practice of comparing a merchant's own database against the payment gateway's own records and finding where they disagree. Even a system built with every idempotency and signature-verification lesson so far applied correctly can still drift from the gateway's records over time — a webhook lost outright, a manual database edit, a bug in a rarely-hit code path — which is exactly why "the code should be correct" isn't treated as a substitute for actually checking.
Why reconciliation catches things testing and code review can't
Reconciliation isn't a substitute for correct code — it's a check for the class of problem correct code can't prevent: a gateway-side event that genuinely never arrived, a partial outage, a race no test happened to exercise, a person editing a database record by hand outside of any application code path at all. This is why real payment systems treat reconciliation as an ongoing operational practice, not a one-time reliability feature that, once built, can be forgotten.
Further reading
Check your understanding
A quick comprehension check — not tracked, not graded, just for you.
1. A cardholder contacts their bank directly to contest a charge, and the bank pulls the funds back before the merchant is even notified. Is this a refund or a dispute?
2. A payment of $100 is partially refunded $30. How should this be represented in the data model?
3. A team has thoroughly tested their payment webhook handler and code review found no bugs. Is a reconciliation job still worth running periodically?
4. Why are disputes generally treated as a more serious event than refunds in payment systems?