Skip to content

Build1 publisher3 min readPublished

Two records of one capture make an order look overpaid by its own value

A dev.to post sorts order-versus-payment disagreements into four classes. All four surface as a total that does not match, the money is already right in three of them, and only the fourth is a broken integration.

The Engineer · Build desk

Illustration accompanying Two records of one capture make an order look overpaid by its own value

What happened

  • A dev.to post opens on the numbers operations keeps finding: an order recorded at 120.00 euro against a capture of 119.40, an order with no payment at all, and a refund larger than anything ever collected.
  • It sorts those disagreements into four classes that look identical from a distance: two versions of one basket, split captures, one capture recorded by two sources, and a record that is simply absent.
  • The post describes the usual week: operations blames the payment system, engineering blames the order system, both get exported into a spreadsheet, and the spreadsheet becomes the thing everyone argues about.
  • Three of the four are legitimate, and adjusting a figure fixes none of them. That leaves the absent record as the only class the post treats as a real problem.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • exposure The double-counted capture hands an operator a plausible number and a plausible action, and issuing that refund sends money out of the business on an order that was collected once.
  • decision Someone has to name an authoritative source for each kind of record and publish it, because nothing in the data resolves which of two systems to believe.
  • constraint A totals-based report will fail on legitimate split captures every time it runs, and the post's observation is that this is how teams learn to ignore the report.
  • capability Versioned basket identifiers in the export make the most common class of disagreement disappear without anyone touching a payment.

Classification runs on identifiers. Two versions of one basket show up as a single order identifier carrying two totals, or as a total that moved between one export and the next [8]. Split captures reconcile one by one: a 150 euro order captured as 100 and then 50 [9], which is 150 exactly [22]. Double counting shows up as two records pointing at the same operation identifier from two different sources [13]. The fourth class has nothing to point at, because the record is simply absent [16].

The size of the gap tells you nothing about which one you have. The post's opening example is an order at 120.00 euro against a capture of 119.40 [2], a shortfall of 60 cents [23]. Its basket example is 30 euro apart, and both exports are telling the truth [7]. A spreadsheet compares totals, and all four classes produce a total that does not match [19].

The dangerous one is the double count. The provider reports a capture, the ledger reports the same capture, and adding them makes the order look overpaid by exactly its own value, so somebody starts preparing a refund [11]. "This one is dangerous because it doesn't look like a duplicate, it looks like a finding," the author wrote [12].

The repair for that class is a decision. Decide once which source is authoritative for each kind of record, and write it down somewhere people can find it [13]. No comparison can settle it, because the data cannot say which system to believe [14].

For the absent record, the first step is finding out why it is absent [16]. The causes the post lists are a webhook that failed and was never retried, a nightly export that ran while a transaction was still in flight, and a refund issued from the provider's dashboard that the order system never heard about [15]. "A missing record isn't a discrepancy to reconcile, it's a hole in how two systems talk to each other," the author wrote [17].

What the post asks of a comparison tool is refusal. Two basket versions and no rule for choosing between them: say so, do not pick the bigger one. If two sources claim one payment, report that both are claiming it, do not add them up. And when a record is missing, say it is missing, do not treat it as a zero [20]. A green result then means one narrow thing, that the records supplied are consistent with each other; it says nothing about whether the money arrived or whether the provider's history is complete [21].

The taxonomy is one practitioner's account across banking, healthcare, gaming and public administration, where every team was sure its situation was unusual [5]. The post does not count incidents beyond the twice-a-month figure [1]. Whether the four classes appear in your ledger in anything like these proportions depends on preconditions you can check: class two needs a provider that does partial captures and retries after a decline [9], class three needs provider events and your own writes landing in the same comparison [11], and class one needs an export that snapshots a mutable basket without saying which version it is [8]. A shop that captures once per order, and lets one system write payment records, should expect the fourth class and little of the other three [25].

What to watch

  • Whether the author publishes the comparison tool, so the refusal behaviour can be tested against real provider exports.
  • A cart or provider export that ships a basket version identifier by default would remove class one before any comparison runs.
  • Whether teams actually write down an authoritative source per record type, the only one of the four repairs that code cannot do.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories