DEV Community

Payload
Payload

Posted on

How do you check that a payout matches what was actually owed?

When a paid API call settles, the payment side is easy to prove. There is a transaction, an amount, a sender and a receiver.

The harder part starts after that. If that call was supposed to be split between a few parties, or counted toward a recoupment balance, or paid out at a different rate because of where it came from, the settlement alone does not tell you whether the right people ended up with the right amounts. You need something on the other side to check against: a record of what was owed, computed from the agreement, that the actual payout can be compared to line by line.

We have been going back and forth on how strict that check should be. Exact match on amount and recipient per line, with any difference flagged? Or is a periodic reconciliation that catches drift in aggregate good enough for most teams?

If you run paid APIs or a marketplace with splits, how do you verify payouts against what was owed, and where has that check caught something the payment logs missed?

Top comments (3)

Collapse
 
mickyarun profile image
arun rajkumar •

Exact per line, but I would argue the strictness is not what makes the check work, and that is the part worth settling first.

If the owed record and the payout are both computed from the same inputs by the same code path, an exact match proves nothing. You get a number divided by itself, and it will agree forever, including while it is wrong. The check only has content when the two sides have different authors: owed derived from the agreement, payout derived from what the rail actually did. Then a difference means one of two independent things moved, which is a finding. Same-source agreement only means nothing changed in your code since the last run.

Against periodic aggregate reconciliation there is one specific failure it cannot see, and it is common once splits are involved: offsetting errors. Two lines wrong in opposite directions net to zero in the aggregate and stay wrong indefinitely. Per-line is what catches that, and it is why payments does per-transaction matching rather than daily totals, even though totals are cheaper and catch most things.

Where has yours caught something? The cases I find most useful are the ones where the rail succeeded and the split was wrong, because the payment log is green, the money moved, and nothing alerts. Those are also the ones that are hardest to find later, since the only record that disagrees is the one you have to compute on purpose.

Collapse
 
payload-tools profile image
Payload •

The different authors point is the whole game. If one code path writes both sides, matching is just the same assumption compared with itself. On ours the two sides at least start apart: the owed record is written when the event happens, from the agreement rules, and the payout side is read back from the chain afterwards. Straight answer to your question though: the only record run through it end to end so far is a validation payout we made ourselves, not a customer error it caught, so there is no war story yet. Offsetting errors are exactly why we matched per line anyway. An aggregate check would have called that payout correct and moved on.

Collapse
 
fintechrailsdigest profile image
Fintech Rails Digest •

The shape of the answer matters more than the tool: the owed side has to be computed from the agreement, not assembled from history. Once you derive it, the payout comparison becomes an ordinary data check instead of an investigation, and the interesting failures stop being arithmetic and start being interpretation. The two that bite hardest in practice are refunds and clawbacks landing after the split was recorded, and rate changes that apply mid-period with no clear boundary date, so the owed record needs effective dates the way a ledger needs a currency.