DEV Community

Cover image for Why your order system and your payment provider disagree
Enrico Lorenzo De Vito
Enrico Lorenzo De Vito

Posted on Originally published at trustedpai.com

Why your order system and your payment provider disagree

Twice a month somebody in operations finds a number that doesn't match. An order recorded at €120.00 against a capture of €119.40. Or an order with no payment at all. Or, the one that ruins the afternoon, a refund larger than anything that was ever collected. Then a week goes by. Operations says the payment system is wrong, engineering says the order system is wrong, somebody exports both into a spreadsheet, and the spreadsheet becomes the thing everyone argues about instead of the systems. A decision gets made in the end because the week ran out, not because anyone worked out what happened.

I've watched this in banking, in healthcare, in gaming and in public administration. Every team was sure their situation was unusual. It never was. There are four ways this goes wrong, they look the same from a distance, and each one needs a different answer. That's why the week disappears.

The basket changed and nobody wrote it down

A customer starts a checkout at €120, adds something, pays €150. Your order system has both numbers in it somewhere. Your provider only ever saw one. Pull the two exports on different days and they're €30 apart, and neither of them is lying. This is the common one, and there's nothing broken: the records describe two versions of the same purchase, and nothing in the export tells you which version you're holding.

You'll spot it because the same order identifier carries two totals, or because a total moved between one export and the next. There's nothing to do to the money — fix the export so each version of a basket carries its own identifier, and the disagreement stops existing.

One payment, taken in two goes

A €150 order captured as €100 and then €50. A partial capture, a retry after a decline, two cards. Look at the totals and it reads as €50 missing; look at the transactions one by one and it reads as a payment nobody asked for. Both readings are wrong, and both are what you get from a spreadsheet left to itself.

The giveaway is that the captures add up to the order total. Again there's nothing to do to the money, but notice that any comparison working on totals will flag this every single time. That's how teams learn to stop reading the report.

The same payment counted twice

Your provider reports a capture, your ledger reports the same capture, and if you add them the order looks overpaid by exactly its own value — so somebody starts preparing a refund. This one is dangerous because it doesn't look like a duplicate, it looks like a finding. It hands you a plausible number and a plausible thing to do about it, and the thing to do is wrong.

You'll see two records pointing at the same operation identifier from two different sources. The fix isn't technical: decide once which source is authoritative for each kind of record, and write it down somewhere people can find it. No comparison can work this out on its own, because there's no fact in the data that says which system to believe.

A record that never turned up

A webhook that failed and never got retried. A nightly export that ran while a transaction was still in flight. A refund somebody in support issued from the provider's dashboard, which your order system never heard about. This is the only one of the four that's a real problem, and it's the one that looks most like the other three.

The difference is that the record isn't different, it's absent. Before anything else, find out why. A missing record isn't a discrepancy to reconcile, it's a hole in how two systems talk to each other.

Why the week disappears

Three of those four aren't errors. The records are incomplete, or duplicated, or describing different moments, and not one of them is fixed by adjusting a figure. So the team spends the week arguing about which system is wrong, when the question was which of the four they were looking at. That question takes minutes if the comparison is built to tell them apart, and it's unanswerable in a spreadsheet, because a spreadsheet compares totals and all four produce a total that doesn't match.

What a comparison has to do before it's worth anything

It has to refuse to guess. Two versions of a basket and no rule for choosing between them: say so, don't pick the bigger one. The same payment from two sources: say two systems are claiming this, don't add them up. A record that isn't there: say it isn't there, don't treat it as a zero. And when it does say everything agrees, that has to mean something narrow and stated out loud — the records you gave it are consistent with each other. Not that the money arrived. Not that your provider's history is complete. The moment a green result means more than the evidence behind it, somebody has to check it by hand, and you're back where you started.

The last one is the one everybody skips. You have to be able to reproduce the answer without the thing that produced it. If I tell you order 4,412 is €40 short, you should be able to take the same inputs, run the comparison yourself, and either get my number or prove me wrong. A finding you can't check is a finding you have to trust — and trust is exactly what nobody had during the week they spent arguing.


I build software that does this and I take engagements on it. You send anonymised order, capture and refund records; you get the findings back with evidence your engineers can recompute on their own machines. trustedpai.com

ELDV - 0xENX

Top comments (0)