Your accounting system has a duplicate invoice check, and it works. It reliably catches the duplicates that look like duplicates: same vendor record, same invoice number character for character, same amount. Those are the ones a person would have caught anyway.
The duplicates that get paid look different. The number was typed INV-0042 the first time and 42 the second. The vendor is "Smith & Sons Ltd" in one record and "Smith and Sons Limited" in another. The second copy was a payment reminder with the same PDF attached, and whoever entered it had no way to know the first one was already approved. By the time the check runs, the information that would have made it obvious is gone — because it lived in the inbox, and the check lives in the ledger.
TL;DR
- QuickBooks, Xero and SAP all check for duplicates by exact match on a handful of fields, and all of them warn rather than block by default.
- Real duplicates arrive in six recognisable ways — two channels, reminders, reformatted numbers, statements, re-issues, and split vendor records. Exact matching misses most of them.
- The strongest duplicate signals — same PDF, same email thread, "reminder" in the subject — exist only at intake and are thrown away when someone downloads and re-uploads.
- Normalizing references and vendor names catches the majority. Try two invoices in the checker below.
- Nobody has a trustworthy public duplicate rate. You can estimate yours from twelve months of exports in an afternoon.
What your accounting system actually checks
Every mainstream system has some version of the same control. The details matter, because every field in the match is a field where a real duplicate can differ.
| System | Fields compared | What happens on a match |
|---|---|---|
| QuickBooks Online | Bill number, for the same vendor record | A warning — and only if the option is switched on in Advanced settings |
| Xero | Contact, reference, and amount — all three | Flags a possible duplicate; the bill still posts unless someone stops it |
| SAP (FI / MM invoice verification) | Vendor, currency, gross amount, plus company code, reference and invoice date depending on configuration | A warning by default; can be configured as a hard error |
Two things are true of all three. First, the comparison is exact: the reference is a string, and INV-0042 is not INV 0042. Second, the default is a warning — which is the right design for a system that can't be certain, and which means the control is exactly as strong as the attention of the person clicking past it at the end of the month.
Check your own configuration. This reflects how these checks are documented as of September 2026. SAP in particular is configured per company code and per vendor, so two entities in the same group can behave differently.
The six ways the same invoice arrives twice
Watch where duplicates come from in a real accounts payable inbox and they sort into a short list. Almost none of them are the vendor double-billing. They're the same invoice travelling two routes and changing shape on the way.
1. Two channels
The vendor emails ap@ and also the person who ordered the service. The first copy is processed. Three weeks later the requester clears their inbox and forwards "the invoice from Smith, not sure if you have this". Nobody on the AP side can tell from the forward that it's the same document, because the forward is a new email with a new date.
2. The reminder is the invoice
"Friendly reminder: INV-0042 is now overdue" — with the original PDF attached. If the first copy is still waiting for approval, the reminder looks like a new bill that needs paying urgently. It gets fast-tracked, precisely because it's overdue, and then the approval on the original comes through.
3. The number, reformatted
The same reference keyed by two people, or read by OCR once and typed once: INV-2026-0042, INV 2026 42, 2026/0042, #42, INV-2026-OO42 with letter O's. To an exact-match check these are five different invoices.
4. The statement
A vendor sends a monthly account statement listing open invoices and a total due. It looks like a bill, it has an amount and a due date, and it gets entered as one. Every invoice on it is now in the system twice — once individually and once inside the statement total.
5. The re-issue
The first invoice was missing a PO number, or had the wrong billing address, so the vendor sends a corrected one: INV-0042-R1, or a brand new number. The correction is paid. The original, which nobody formally rejected, is paid too — because a credit note for it was never requested or never arrived.
6. The vendor, twice
"Smith & Sons Ltd" and "Smith and Sons Limited" are two records in the vendor master, created a year apart by two people. Every duplicate check scoped to "the same vendor" is now blind across them. This one is the quietest and the most expensive, because it affects every invoice from that supplier, not one.
There's a seventh pattern that isn't technically a duplicate but fails the same control: paying after cancellation. The contract ended, the notice went out, and the subscription invoice keeps arriving on schedule — correct number, correct amount, for a service you no longer have. The check has nothing to say about it, because nothing is duplicated. What's missing is the link between the invoice and the state of the contract it bills against.
Is it the same invoice? Try it
Enter two invoices the way they'd appear in your system. The checker shows what an exact-match duplicate check sees, and what it sees once the vendor name and reference are normalized. It runs in your browser; nothing is sent anywhere.
Invoice A — already in the system
Invoice B — just arrived
Exact-match check (what most systems run)
Normalized check
Two things to notice. The "reformatted number" example is the most common real duplicate, and it sails through an exact-match check. The "monthly subscription" example is the most common false alarm — same vendor, same amount, a month apart — and it's why any rule looser than exact match needs the service period on the invoice to settle it. An invoice with no service period is one an agent can't clear, for exactly this reason.
Why the check sits in the wrong place
A duplicate check at posting runs after a person has already decided the document in front of them is a new invoice. It compares a handful of typed fields against other typed fields. Everything else that was known about the document when it arrived has been discarded.
And what was discarded is most of the useful evidence:
- The file itself. A re-attached PDF in a reminder is byte-for-byte the original. A file hash matches it instantly, regardless of how anyone typed the number.
- The thread. A forward carries the original message in the chain. "Fwd: Invoice INV-0042" is not a new event.
- The subject line. "Reminder", "overdue", "statement", "copy", "resend", "corrected" — each one changes what the attachment probably is.
- The sender. An invoice forwarded by an employee rather than sent by the vendor is a second route by definition.
- The line items. A statement lists invoices you already have. Comparing its lines against open bills tells you it's a statement, not a bill.
Every one of these exists at intake and nowhere else. The moment someone downloads the attachment and uploads it to the accounting system, they're gone — and the check downstream is left comparing strings. That's why the most effective duplicate control is not a stricter matching rule in the ledger. It's one intake route, and something on that route that remembers what it has already seen.
Duplicate payments are an intake problem that surfaces as a payment problem. By the time an invoice reaches the ledger, the question "have we seen this before?" is much harder to answer than it was when the email arrived.
What you can do this week, without new software
- Turn the check on and make it harder to ignore. In QuickBooks Online, enable the duplicate bill number warning. In SAP, review whether the duplicate message should be an error for vendors where it matters. The default settings are the weakest settings.
- Collapse the routes. Tell vendors, in writing, that invoices go to one address. Tell employees that an invoice forwarded from their own inbox goes to the same address with "FWD from requester" in the subject, so the second-route case is visible.
- Normalize before you compare. Store a normalized reference alongside the typed one: uppercase, no separators, no alphabetic prefix, no leading zeros. Most exports and most spreadsheets can do this with one formula.
- Clean the vendor master once. Sort vendors by a normalized name — lowercase, "&" to "and", legal suffixes removed — and merge the pairs that collide. Every duplicate check you have is scoped to a vendor record, so a split vendor makes all of them blind.
- Never key a statement. Statements are for reconciliation. Reconcile them monthly against open bills; unapplied cash on a vendor statement is the most reliable way duplicates you've already paid show up.
- Reject re-issued originals explicitly. When a corrected invoice arrives, ask for a credit note against the original the same day, and hold the correction until you have it.
How much is this costing you?
You'll see figures from 0.1% to 2% of accounts payable spend quoted as the industry duplicate rate. Treat all of them carefully. They come almost entirely from recovery-audit firms, which are paid a share of what they find, and from AP software vendors, which sell the fix. Neither is lying, exactly — the range is genuinely wide, because it depends on how many routes invoices arrive through and how clean the vendor master is — but there is no neutral public dataset behind any single number.
The good news is that your own rate is easy to estimate. Export twelve months of bills with vendor, reference, amount, date, and payment status. Add the normalized reference and normalized vendor columns described above. Then produce two lists:
- Same normalized vendor and reference. These are near-certain duplicates. Check whether both were paid.
- Same normalized vendor and amount, within 45 days, different reference. These include legitimate recurring charges. The service period on each invoice settles it — and where there is no service period, you've found a template problem worth raising with the vendor.
For most small and mid-sized finance teams this takes an afternoon, and it answers the question with your own data instead of someone else's marketing.
If you've already paid twice
Write to the vendor with both payments referenced by date and amount, and ask for either a refund or a credit against the next invoice — whichever they can process faster, but in writing either way. In your books, record the second payment as a vendor credit or prepayment rather than voiding or deleting anything, so the trail survives an audit. Vendors are usually cooperative; the difficult cases are the ones discovered a year later, when the account manager has changed and nobody on either side remembers the invoice.
Then trace which route the second copy came through. That route is where the next one will come from.
Where an intake agent changes this
An AI agent reading a shared AP mailbox has every piece of evidence the ledger check lacks: the file hash, the thread, the subject, the sender, and the line items, alongside the fields it extracts. It can recognise a reminder as a reminder and a statement as a statement before either becomes a bill, match a re-issue to its original and ask for the credit note, and link each invoice to the contract and service period it bills against — which is also how it catches the seventh pattern, the invoice for a contract that has already ended.
That's what SynapticRelay does on invoices@ and contracts@: one intake route that remembers what it has seen. Until then, the six checks above, a normalized reference column, and one afternoon with your exports will catch most of what the default duplicate check lets through.