How to Catch Duplicate and Double Payments
A customer messages you, upset: they were charged twice. You check your dashboard and, sure enough, there are two successful payments for one order. Or worse - you do not check, because you never noticed, and the customer only found out from their own statement. Double payments are one of the most common and most reputation-damaging reconciliation problems for Nepali wallet merchants, and almost all of them are catchable before the customer complains.
This article explains how duplicates happen on eSewa, Khalti, and Fonepay, how to detect them systematically, and how to resolve them cleanly.
How a single order becomes two payments
Duplicates are rarely fraud. They are almost always the ordinary friction of mobile payments on imperfect networks. The usual paths:
- The impatient retry. The customer taps pay, the app hangs on a slow connection, they assume it failed, and they tap again. Both attempts succeed. One order, two captures.
- The double-submit. A checkout button with no guard fires twice on a double tap or a laggy page, sending two payment requests before the first responds.
- The stale callback. A gateway sends a success callback, your server is slow to respond, the gateway retries the callback, and your system records the payment twice - even though only one capture happened at the gateway.
- The refund-and-repay loop. A payment is refunded, the customer is told to try again, they pay a second time, and then the original refund does not go through - leaving two live payments and no refund.
Each path produces a slightly different fingerprint, which matters because the fix depends on the cause. A genuine double capture at the gateway is a real duplicate charge. A single capture recorded twice in your own system is a bookkeeping duplicate. They look identical on a naive report and require opposite responses.
There are two kinds of duplicate: a real one, where the customer was actually charged twice at the gateway, and a phantom one, where a single gateway capture got recorded twice in your books. Always confirm which you have before acting - refunding a phantom duplicate gives money back that you never received.
Detecting duplicates systematically
Waiting for customers to report double charges is not a control - it is luck. A systematic detector looks for the signatures duplicates leave:
- Same amount, same customer, close in time. Two captures for an identical amount from the same payer within a short window are the classic duplicate. The tighter the time gap, the more likely it is a retry.
- Two captures against one order reference. If your checkout passes an order ID to the gateway, two successful payments carrying the same order reference are an unambiguous duplicate. This is why passing a stable reference on every payment is worth the effort.
- A capture with no matching order. A payment in the gateway that maps to no open order is often the second leg of a duplicate whose first leg already closed the order.
- Gateway transaction ID repetition. If the same gateway transaction ID appears twice in your records, that is a phantom duplicate - one real capture recorded twice - not a real double charge. The Khalti docs and eSewa developer reference both key transactions by a unique identifier precisely so you can deduplicate on it.
The most reliable detector combines these: match on amount and payer and time window, then confirm against the order reference, then check whether the gateway transaction IDs are distinct. Distinct IDs mean two real captures. A repeated ID means one capture double-recorded.
Do not deduplicate on amount alone. Two customers legitimately buying the same 500-rupee item within a minute are not a duplicate. Amount is a signal, never a verdict - always confirm with payer identity and the gateway transaction ID before you flag or refund.
Resolving each type cleanly
Once you know which kind of duplicate you have, resolution is straightforward:
- Real double charge (two distinct gateway captures, one order). Refund one of the two captures. On Khalti this can be done through the refund API, and remember the refund will typically net out of a future payout rather than appear as a standalone debit - so track it to the settlement that absorbs it.
- Phantom duplicate (one capture, recorded twice). Do not refund anything. Correct your own records to collapse the two rows into the one real capture. The money was never double-taken; only your books were double-counting.
- Refund-and-repay tangle. Confirm whether the original refund actually completed. If both the original and the repayment are live, refund one. If the refund failed and only the repayment stands, you are fine - just reconcile the failed refund so it does not haunt a later settlement.
The through-line: never issue a refund until you have confirmed a real second capture exists at the gateway. Refunding a phantom duplicate hands back money you never collected.
Why duplicates hide in reconciliation
Duplicates are dangerous precisely because they can balance. A double charge that gets refunded the same day nets to zero and vanishes from a casual month-end glance - even though the customer experienced a charge, a scare, and a refund. And a phantom duplicate inflates your recorded revenue against a bank that only ever received one payment, leaving a residual that a tired bookkeeper might round away.
This is why duplicate detection belongs inside your daily reconciliation, not in a separate "check for double charges" task nobody does. When every capture is matched to an order and every payout is decomposed to the rupee, a duplicate cannot hide - it shows up as either an extra unmatched capture or a residual that will not close. The broader practice is covered in what is payment reconciliation.
Automating the catch
RakamHQ treats duplicate detection as part of reconciliation rather than an afterthought. As it ingests your gateway reports, it flags captures that share a payer, amount, and window, distinguishes real double captures from single captures recorded twice by comparing transaction IDs, and follows any resulting refund through to the settlement that nets it. The result is that a customer's double charge surfaces on your morning close - not in an angry message a week later. Prove where every rupee went, and duplicates have nowhere to hide.
Frequently asked
How do double payments happen on wallets?
Usually through ordinary friction: an impatient retry on a slow network, a double-submit checkout button, a stale gateway callback recorded twice, or a refund-and-repay loop where the original refund never completes.
What is the difference between a real and a phantom duplicate?
A real duplicate is two distinct gateway captures for one order - the customer was genuinely charged twice. A phantom duplicate is a single capture recorded twice in your own books. Refunding a phantom hands back money you never received.
How do I detect duplicate payments reliably?
Match on same amount, same payer, close in time, then confirm against the order reference and check whether the gateway transaction IDs are distinct. Distinct IDs mean two real captures; a repeated ID means one capture double-recorded.
Should I deduplicate on amount alone?
No. Two customers buying the same-priced item within a minute are not a duplicate. Amount is a signal, never a verdict - always confirm with payer identity and the gateway transaction ID before flagging or refunding.
Keep reading
Get your free reconciliation.
Send us last month's eSewa report, Khalti export, bank statement and orders sheet. Within 48 hours we send back a one-page close - every payment matched, every fee computed, every settlement decomposed.
Files only · private upload link · nothing to install