Most duplicate payment checks start in the wrong place. They compare the vendor ID on an invoice with the invoice number, and they pass cleanly when both match a single record. The failure that taught the harder lesson started months earlier, at setup, when the same supplier entered the vendor master twice.
One record read Acme Industrial Ltd, the other Acme Industrial Limited. One carried a head office address, the other a depot address. The tax number matched. The bank account matched. The vendor numbers did not, so every downstream check that keyed on vendor ID treated the two records as two different suppliers, and both got paid.
What the duplicate actually breaks
The double payment is only the visible part. Spend reporting splits across two records, so the business understates what it really buys from that supplier. Volume rebates get calculated on half the true volume. Credit notes posted against one record sit unused while the other record keeps paying invoices in full. By the time a supplier statement gets reconciled, the overlap has usually been running for months.
That pattern is why the vendor master check in ERPSav treats this as an entity resolution problem first and a payments problem second. Fixing an invoice does not fix the record that produced it.
What worked
Match on strong identifiers first. Name spelling is the weakest signal in the file. Bank account and tax ID are far stronger, because suppliers rarely change either one when a clerk creates a second record. The matching pass ranks candidate pairs by those fields first, then uses name and address similarity only to order the review queue.
Review pairs, not singles. The useful output is a side by side pair: both names, both addresses, tax numbers, bank details, open items, and payment history on one screen. A reviewer can confirm a duplicate in seconds from that view, while a flat list of suspicious vendors takes much longer to work through.
Freeze, do not delete. When a pair is confirmed, the newer record gets frozen and its open items move to the surviving record, with a cross reference left behind. Deleting the duplicate would break the audit trail for historical invoices. Freezing stops new payments while keeping every old transaction traceable.
Sweep backwards after the merge. Once two records become one, the payment history needs a second pass: same invoice numbers, same delivery notes, and amounts within a few days of each other across both old records. That sweep is where the actual duplicate payments surface.
What broke
The first version leaned too hard on fuzzy name matching. It flagged legitimate separate entities, such as a parent company and a trading subsidiary that share part of a name, and reviewers stopped trusting the queue. Precision mattered more than recall here. A shorter queue that is almost always right gets worked. A long queue full of false pairs gets ignored.
Address matching also misled early on. A supplier can legitimately have several sites, so two records at different addresses are not automatically duplicates, and two records at the same address are not automatically the same supplier. Address became a supporting signal only, never a deciding one.
The other lesson was timing. Running the check after payments have gone out turns it into recovery work. Running it when a new vendor record is created turns it into prevention, which is cheaper in every way. The check now belongs at setup time as well as in the periodic review.
The takeaway
Duplicate payments are often described as an accounts payable mistake. In practice they are frequently a data modelling mistake that AP inherits. If the identity of a supplier is spread across two records, no invoice level check downstream can reliably catch what the master data already allowed.
The original feature on this, with the full cleanup sequence, sits on the fleet blog. The product side lives at https://erpsav.com , where the vendor master check runs alongside checks for duplicate supplier payments, lease overcharges, utility and telecom billing errors, card processing fees, warranty claims, and the other leak categories finance teams deal with.
For teams maintaining their own vendor files: which fields do you trust most when you suspect two records are really one supplier?

