Our settlement was off by ₹410 and it took three days to find why
Partner bank sends us a settlement file every morning. We compare it with our ledger and the totals should match to the paisa. One Monday it was off by ₹410.37. Not a lot of money. But a mismatch is a mismatch and finance will not close the day with it.
First day we checked the obvious things. Missing transactions, duplicates, refunds settled on a different day. Everything matched row by row on the transaction amount. The difference was only in the fee column.
Second day I put both fee calculations side by side for all 41,000 rows. Ours: for each transaction, fee = 1% of amount, then 18% GST on the fee, round each one to 2 decimals, then sum. Bank: sum all fees for the batch, then GST on the total, round once. Per row rounding vs rounding once at the end. Each row was off by at most half a paisa and with 41k rows it adds up to hundreds of rupees. The contract actually says GST is computed on the aggregate fee per settlement. Nobody on engineering side had read that page.
Third day found a second problem, which is why the number still did not match after fixing the GST logic. A legacy service still calculated fees in rupees as JavaScript numbers. Something like Math.round(1.005 * 100) / 100 gives 1 and not 1.01, because 1.005 cannot be represented exactly in floating point. Rare, but in 41k rows it happens enough to matter.
What we changed:
- All amounts in integer paise, everywhere, including that legacy service.
- Fee per transaction computed in paise with an explicit rounding mode, in one shared function.
- GST computed at batch level exactly like the contract says.
- Reconciliation report now shows the difference broken down by component (principal, fee, tax), so next time we know in 10 minutes which column is wrong.
Lesson for me: rounding rule is a business rule, not an implementation detail. Find it in the contract, write it down, and test with real files, not with 3 rows of test data.
Written by
Arjun Mehta
Backend engineer at a lending startup in Bengaluru. Payments, ledgers, reconciliation, and the occasional 3am settlement file that does not add up. Postgres fan. Will talk about idempotency keys until you leave.
Get the best of #ledger_lines weekly
One email each Monday with the most useful posts. No spam; unsubscribe in one click.
Comments
Sign in to join the conversation.
Sign in to comment