How to find duplicate journal entries across multiple Xero entities
29 August 2026Draft — noindex, not in sitemap
You find them by matching on account, amount and normalised description within a bounded time window, run across every entity at once rather than one ledger at a time. The reason this needs saying at all is that a duplicate spanning two entities is structurally invisible to normal review: no single Xero organisation contains both halves, so no amount of care inside one ledger will surface it.
Why does reviewing each entity separately not find these?
Because the evidence is split across two ledgers that nobody looks at together. A reviewer working through one entity’s account transactions sees one entry, correctly coded, for a plausible amount, with a sensible description. There is nothing wrong with it. The identical entry sitting in a sister entity is in a different Xero organisation, behind a different login, reviewed by a different person on a different day.
This happens in ordinary ways. A shared cost — group insurance, a software subscription, a professional fee — gets coded in full to two entities instead of split between them. A supplier invoice arrives addressed to the parent and is entered by the parent’s bookkeeper and again by the subsidiary’s, because both believed it was theirs. A recurring journal template is copied to a new entity and left running in the old one.
None of these look like errors from inside either ledger. They only look like errors when both entities are in view at the same time, which is exactly the condition group reporting creates and per-entity review does not.
What makes two entries a duplicate?
Three attributes have to match, within a limited window of time.
The account has to be the same. Matching across different accounts would flood you with false positives, since many unrelated entries share an amount.
The net amount has to be the same. Absolute equality, not approximate — near-matching sounds cleverer and produces far more noise than signal at the volumes a mid-sized group generates.
The description has to match once normalised — case folded, punctuation and extra whitespace removed — so that “Insurance renewal 2026” and “insurance renewal 2026” are recognised as the same text.
And the entries have to fall within a short window of each other, in the order of a couple of weeks. A window that is too wide starts matching genuinely recurring monthly charges; too narrow and it misses the common case where the second entry is made days after the first, once someone notices the invoice has not been paid.
Which entries should be excluded from matching?
Three categories of entry are excluded because they repeat legitimately and would otherwise dominate the results.
Cash receipt and cash payment journals are excluded. Repetition is the normal condition of a cash ledger — the same customer paying the same retainer, the same direct debit going out — and treating that as suspicious produces a report nobody reads.
Zero-value lines are excluded, since an amount of nothing matching another amount of nothing carries no information.
Blank descriptions are excluded, because with no text to compare, the match rests on account and amount alone, which is far too weak a signal.
There should also be sanity bounds on dates, so that entries with implausible dates do not distort the comparison. A useful check on any implementation is whether it has a defensible lower bound on how far back it looks — an unbounded lookback gets slower every year and starts surfacing ancient matches nobody will act on.
What will this approach miss?
It will miss any duplicate coded to different accounts, and that is a deliberate trade.
If the parent’s bookkeeper codes a shared insurance invoice to Insurance and the subsidiary’s codes it to General Expenses, the amounts and descriptions match but the accounts do not, and no alert is raised. Relaxing the account condition to catch it would raise the false positive rate to the point where the report stops being useful, and a control nobody reads catches nothing at all.
It will also miss duplicates where the amounts differ — a shared cost split unevenly rather than duplicated in full, or one entry including GST and the other excluding it.
And it says nothing about whether a genuine match is actually an error. Two identical entries in two entities can be entirely correct: an intercompany recharge legitimately appears on both sides, and some groups deliberately post mirrored entries. The detection tells you to look; it does not tell you what you will find.
Stating these limits matters more than it might seem. A control whose blind spots are documented can be relied on within them. A control that implies total coverage will be trusted past the point where it is doing anything.
What false positives should you expect?
Expect a small number of legitimate matches, concentrated in a few recognisable patterns.
Accruals that are reversed and re-posted within the window can match themselves. Standing charges billed twice in a fortnight — some suppliers invoice twice monthly — will match. Deliberate mirrored entries across entities will match. And a genuine correction, where an entry was deleted and re-entered identically, looks exactly like a duplicate because in every observable respect it is one.
This is normal for a detective control and is not a reason to tighten the rule until the report is empty. The useful measure is whether a reviewer can clear the list in a few minutes each month. If they can, the false positives are paying for themselves by keeping the true positives visible.
Is this the same as duplicate invoice detection in accounts payable?
No, and the distinction matters when comparing tools. Duplicate invoice detection in AP is a preventive control that runs before payment, matching incoming invoices against purchase orders, vendor records and prior payments to stop the same invoice being paid twice. It protects cash.
Duplicate journal detection runs after the fact, across the general ledger, and protects the accuracy of your reported numbers. A duplicated journal may never involve a payment at all — a doubled accrual overstates a cost and misstates the period without a dollar leaving the bank.
Groups generally need both, and they sit in different parts of the stack. If you are evaluating tools, be clear which problem you are solving, because a product that does one well may not attempt the other.
Does this replace review or audit?
No. This is a detective control: it shortens the distance between an error being made and someone noticing it. It does not test whether your controls are well designed, whether entries were properly authorised, or whether the numbers are right in any broader sense.
What it does is remove a specific blind spot that group structure creates and that no reviewer working inside a single entity can close, however careful they are. That is a narrow claim, and it is the honest one. The related problem of entries arriving long after a period was considered closed is covered in close controls, and the mapping gaps that let entity balances disappear from group totals are covered in the chart of accounts mapping guide.