Guide

How to catch duplicate bills before you pay them

Duplicate payments rarely come from fraud. A vendor emails the same invoice twice, someone keys INV-004812 once and 4812 the next week, a bill is re-sent after it was paid. The cheapest place to stop them is the payment run. This is the method behind DuplicateBillCheck.

1. Export the bills to pay

One row per bill in the payment run: vendor, invoice_number, bill_date and amount; currency, due_date, bill_id and memo are used when present. Start from the bills to pay template, or export an unpaid bills report from your accounting system as CSV or XLSX. The header row does not need to be the first line.

2. Export the paid or history bills

Export the bills already entered or paid for the same vendors, for a period long enough to catch re-sent invoices (twelve months is a good default). Use the paid bills template or a vendor report. In QuickBooks, a vendor transaction report exported to Excel or CSV works as it is: the report title lines, the vendor name rows above each block and the Total rows are recognized, Num becomes the invoice number and Date the bill date. Include a status or paid date column if your report offers one; without it, every history bill is “payment status unknown”.

Export paid or earlier bills only. If the history file also contains the open bills you are about to pay, every bill will find itself. Bill IDs in both files avoid this: the same explicit ID is treated as the same record.

3. Vendor, currency and exact amount safeguards

4. Normalize invoice numbers conservatively

Case, spaces and the separators - _ . / # : are ignored. An INV, INVOICE, BILL or NO prefix directly before the digits is dropped, and leading zeros are dropped only from an invoice number that is all digits. So INV-004812, inv 4812, #4812 and 0004812 are all 4812, but A-4812 and 4812-B are not. Every match says whether the invoice numbers were identical or equal after normalization, with both original values.

Paid
A history bill is paid only when its own row says so: a status such as Paid, Closed or Paid in full, or a valid paid date.
Not paid (open)
A status such as Open, Unpaid, Due, Overdue or Partially paid.
Payment status unknown
No status column, a blank status or one that is not recognized. A bill row on its own never proves payment, and payment rows (Bill Payment, Check) are counted and ignored because a report row cannot show which bill they paid.

6. Duplicates inside the batch

The batch is also compared with itself. Two bills with the same vendor, currency, amount and invoice number are a batch group: verify the original bill before paying, and pay it once. The extra copies are totaled separately, so the first bill of each group is not counted as at risk.

7. Reading the results

Every result is a statement about the files, not proof: a bill paid from another system, a vendor under two names or an export with the wrong date range all change what can be seen. Recurring bills with the same amount and different invoice numbers (rent, subscriptions) are deliberately not flagged.

8. Pre-payment checklist

Check your bills Try the demo

DuplicateBillCheck compares the files you give it. It does not connect to your accounting system, cannot see payments made outside the files and never decides whether a bill should be paid.