Fintech & Finance Operations// diagnostic

The same invoice got paid twice: finding the near-duplicate your check missed

In short

A duplicate that reaches payment is almost never an exact duplicate: the check on supplier plus invoice number plus amount passed because the second document differed in one of those three. Regroup candidates on supplier group, net-of-tax amount and a date window instead, and the pairs surface immediately.

Key takeaways

  • Exact-match duplicate checks fail on the 3 fields they compare: number, amount and supplier identity.
  • Group on supplier group, net-of-tax amount and a 45-day window. The pairs appear in the first query.
  • 5 causes account for nearly all of them, and each needs a different fuzzy key to catch.
  • A stalled first invoice is the commonest cause of a resubmission, so fixing approvals removes the source.
  • No rule set is complete. The last defence is a sweep over the payment proposal, including invoices paid recently.

The usual way this arrives is not from a control. A supplier writes to say their account is in credit, a statement reconciliation refuses to balance, or a recovery review finds a pair months later. By then the money has gone, and the question everyone asks first is why the duplicate check did not fire.

It did fire. It compared supplier, invoice number and amount, found the three did not all agree, and correctly concluded the two documents were different. They were different. They were also the same bill, and the gap between those two statements is where every duplicate payment lives.

Regroup the register before anyone forms a theory

Before working out how the second document was created, confirm the scale. One pair found by a supplier is rarely the only one, and the same query that confirms this case finds the others.

  1. Resolve each supplier to a supplier group rather than a row id. Join on normalised legal name, on tax registration where held, and on bank account, because a document entered under two vendor rows is invisible to any check scoped to one row.
  2. Compute a comparison amount that is net of tax and rounded to 2 decimals. Tax-inclusive comparison fails whenever a portal copy and an emailed PDF round tax differently, which they routinely do on multi-line invoices.
  3. Group by supplier group, comparison amount and a 45-day window on the invoice date. The window matters more than it looks: a resubmission usually arrives 30 to 60 days after the original, once the supplier's credit control notices nothing has been paid.
  4. Subtract the legitimate repeats. Rent, retainers, standing charges and licence instalments are identical by design, so exclude groups where the amounts recur on a regular cadence and carry the same account code and description.
  5. Rank what remains by amount and by whether both documents reached a payment run. Anything paid twice becomes a recovery item today; anything where one is still open becomes a block.

Run the same query with the amount rounded to the nearest whole unit as a second pass. It is noisier, and it catches the pairs that differ by a rounding difference or a small freight line — the ones that are hardest to find and easiest to argue about later.

Five ways one bill becomes two documents

Ranked roughly by how often each turns out to be the cause. The third column is the detection key that would have caught it, and they are deliberately different keys — a single fuzzy rule that catches all five does not exist.

CauseWhat the second document looks likeDetection key
Resubmission under a new numberSame amount, same or similar date, a new invoice number, often marked as a copy or a statement chaserSupplier group, net amount, invoice date within a few days
Two channels for one invoiceSame invoice number arriving as a portal record and as an emailed PDF, sometimes with different tax roundingSupplier group plus invoice number normalised: strip leading zeros, prefixes, spaces and punctuation
Credit note issued, then re-billedA corrected invoice with a new number, where the credit against the original was never postedNet position per PO line, or per contract period, across the whole window rather than per document
Split shipment billed twiceA second invoice repeating lines already billed on the first, against the same purchase order lineCumulative billed quantity against cumulative received quantity, per PO line
One document, two supplier rowsAn identical invoice keyed under a second vendor record created for the same supplierBank account plus amount plus date, ignoring supplier id entirely
Cause, what the second document looks like, and the key that catches it

The fourth cause deserves a note because it is the one that looks like a matching problem rather than a duplicate. When a purchase order line is billed in a different unit on the second invoice, the amounts do not agree and neither the duplicate check nor the match catches it — the arithmetic is genuinely different on the two documents. That is unit-of-measure drift producing a duplicate rather than an exception, and only the cumulative quantity test finds it.

The fifth is worth checking early because it is cheap. If the two payments left for the same bank account under two different supplier ids, the vendor master has duplicate rows, and there will be more pairs waiting.

Why the exact check passed

The standard check compares three fields, and each of the three has a normal, blameless way of differing between two copies of the same bill.

  • The invoice number. Suppliers add prefixes for a re-issue, drop leading zeros, change series after a system migration, or append a suffix to a copy. A string comparison sees two different numbers; a human sees one invoice with a letter on the end.
  • The amount. Tax-inclusive against tax-exclusive, a freight line added on the second copy, a rounding difference from a per-unit price derived by division. A comparison to the penny fails on all three.
  • The supplier identity. Two vendor rows, or one row on the original and a one-off payee record on the copy, and the check never gets as far as comparing anything else.
  • The date. Which date the check uses is rarely stated. The invoice date, the received date and the posting date can be weeks apart on the same document, and a window measured from the wrong one puts the two copies outside each other's range.

There is a fifth reason that has nothing to do with fields. If the original invoice is sitting unpaid in an approval queue, the supplier's credit control will chase it, and the chase arrives as a fresh document. Duplicate risk is downstream of approval latency, which makes invoices that stall in approval a duplicate-payment control as much as a cycle-time one. Fixing the stall removes the cause rather than catching the effect.

A related timing case is the invoice that arrives before its goods receipt, sits unmatched while somebody chases the warehouse, and is re-sent in the meantime. Both copies then match on the same day once the receipt posts. The mechanics of that gap are in matching fails because the goods receipt has not been posted yet, and the duplicate is a side effect of it.

Block, hold, or claim it back

Every candidate pair ends in one of three places. The decision is mechanical once two facts are known: whether both documents have been paid, and whether the second is a genuine second liability.

  1. Neither paid, and the pair is confirmed as one bill. Block the later document, link it to the earlier one, and record the reason on both so the link survives the person who found it.
  2. Neither paid, and the second is genuinely a second liability — a real split shipment, a legitimately re-issued invoice after a credit. Release both, and post the credit if it exists but was never entered. This is the case that makes an automatic block dangerous.
  3. One paid, one open. Cancel the open document rather than paying and reclaiming. Obvious, and routinely missed when the two sit in different queues owned by different people.
  4. Both paid, supplier still active. Raise it with the supplier and request the credit be applied against the next invoice rather than refunded. Faster to collect, and it keeps the account reconcilable.
  5. Both paid, supplier dormant or the relationship ended. Treat it as a recovery item with an owner and an age, and set a review date. Recoveries without an owner become write-offs by default.
  6. In every branch, record the cause code from the table above. Without it, the same five causes recur and nobody can say which rule to build next.

A duplicate check that compares three fields exactly is not a control against duplicates. It is a control against clerical re-entry, which is the one cause that has largely stopped happening.

The sweep before the payment run, and the honest limit of it

No rule set is complete. Each of the five keys above is a heuristic tuned to a pattern, and suppliers keep inventing new ones — a merged entity re-billing an old ledger, a portal migration re-uploading a quarter of history, a factoring company presenting invoices already paid to the original supplier. The last defence has to be positional rather than clever: a sweep that runs against the payment proposal, immediately before money moves.

The deeper design point is where the check lives. A duplicate report that runs nightly and lands in an inbox is a report; a check that runs inside the write path and refuses to create a second payment against the same external reference is a control. That is the same structural argument as a wallet that went negative and nothing stopped it: if the invariant is only ever evaluated after the fact, it is not an invariant. Give the payment record a uniqueness constraint on supplier group plus normalised invoice number, and the duplicate that survives every heuristic still fails to write.

Building that generally means owning the layer between the ERP and the payment file rather than replacing either, which is the shape most of our internal tools and operations work takes in finance. The surrounding controls — matching, tolerance, approval routing and the exception queue that receives whatever they reject — are covered across invoice to pay: capture, matching and approvals, and the wider posture behind all of it sits in our finance operations work.

Frequently asked questions

Short answers to the follow-ups this page tends to raise.

Why did our duplicate invoice check not catch this?

Because it compared supplier, invoice number and amount exactly, and the second document differed in at least one of them. Suppliers re-issue under new numbers, portals and emailed PDFs round tax differently, and the same bill entered under two vendor rows never reaches the comparison at all. The check worked as designed; the design assumed duplicates are identical, and the ones that reach payment are the ones that are not.

How do you detect a duplicate invoice with a different invoice number?

Group on supplier group, net-of-tax amount and a date window rather than on the invoice number. Resubmissions after a chase usually carry the same amount and a date within a few days of the original, so a window of 45 days on the invoice date catches most of them. Normalising the invoice number separately — stripping prefixes, leading zeros and punctuation — catches the second family, where the number is really the same one wearing a different format.

Should a duplicate check block payment or just flag it?

Block only where the pair is confirmed as one bill, and flag everywhere else. Split shipments, staged billing and legitimately re-issued invoices after a credit note all look like duplicates to a fuzzy key, and blocking them automatically creates late payments and supplier disputes that cost more than the duplicates prevented. The workable split is a hard block on an exact key inside the write path, and a ranked review list from the fuzzy keys attached to the payment proposal.

Can a duplicate payment be recovered after it has gone out?

Usually, and the fastest route is to have the credit applied against the supplier's next invoice rather than requesting a refund. That keeps the account reconcilable and avoids a separate inbound payment nobody expects. Recovery gets substantially harder where the supplier is dormant, the entity has been sold, or the payment went to a factoring company, which is why every open recovery needs a named owner and a review date rather than sitting on a list.

Where should the duplicate check sit in the invoice process?

In two places, doing two different jobs. An exact-key uniqueness constraint belongs in the write path, so a second payment against the same external reference cannot be created at all. The fuzzy sweep belongs against the payment proposal, comparing each line to invoices already paid in a trailing window — that is the point at which supplier, amount and bank details are final, and the point at which somebody is already reviewing the run.

  • duplicate payments
  • accounts payable
  • controls
  • debugging
// shipped work

The work behind this page

Builds from our portfolio that this page draws on.

Working on something in this space?

Tell us where you are in a sentence or two. We'll tell you honestly whether we're the right team, and what a sensible first slice of the work looks like.

Start the conversation