- What it does
- Submits batches of journal entries into an accounting ledger, having first read what is already in it.
- The control
- It refuses any transaction matching one already posted, or another in the same run, on date, amount, counterparty, direction and account. Refusal is the default state and overriding it is an explicit, deliberate act.
- Failure
- A debt or credit posted twice, a bank reconciliation that will not tie, and three weeks spent finding out why.
- Unit of work
- A batch checked, rather than a posting typed. Fifty transactions per write.
- Authority
- Named systems
- Xero · batch write API · double-entry ledger
- Claims
- Measured: about 1,800 duplicate journal entries a year became none, with 1,740 refused before commit in year one, and year-end clean-up fell from three weeks to under a day. The operation had 18,000 subscriptions; that count is context, not a multiplier. Applying modelled $200 to $400 of debt-or-credit exposure plus $50 to $100 of resolution work to the measured 1,740 refusals gives $435,000 to $870,000 of annual value at risk.
- Non-claims
- That the modelled range is an audited saving or that cash left the bank twice. The assumed debt, credit and resolution values per refused entry are printed below.
- Evidence held
- The ledger history, refusal log and year-end reconciliation: about 1,800 duplicates a year became none, with 1,740 stopped before commit in year one.
- Status
- In production
A ledger that refuses to double-post
About 1,800 duplicate journal entries a year were distorting balances, preventing the bank reconciliation from tying, and leaving a senior bookkeeper with three weeks of year-end clean-up.
The same ten fields, with the arguments behind them.
From a read-only pass to a governed write.
Nothing wrote to the ledger until the refusal check had been proved against real history with no write path attached. That ordering is the whole engagement, and it is the reason the first duplicate the system ever caught was caught in a dry run.
Read the ledger as it stands.
A full read of the existing postings, with no write path attached and no credentials that could create one.
Two weeks
The five-field comparison.
Date, amount, counterparty, direction and account, with the same test run against the batch itself.
The write budget and the exit status.
The run stops at the budget rather than at the end of the batch, and reports whether it finished clean.
The rules and the bounds were built in parallel, because a refusal with no ceiling behind it is a rule you can talk your way past
Dry runs against real history.
Every refusal reviewed by the client’s finance team before a write path existed at all.
Eight weeks of dry runs
The operator gate goes live.
Batches commit only after a person confirms, and the exit status is read on every run.
Fourteen weeks from first workshop to production
Before and after.
| Measure | Before | After |
|---|---|---|
| Duplicate postings reaching the ledger | About 1,800 a year | None; 1,740 refused before commit |
| Write calls for a quarter of a million postings | 250,000 | 5,000 |
| Year-end duplicate clean-up | Three weeks of a senior bookkeeper | Under a day |
The write-call row is a property of the code and needs no measurement: the batch API takes fifty items per call. The other two rows are the client’s own figures.
Six figures of exposure, with the assumptions left in.
This is a sensitivity model, not an audited client saving. The operation had 18,000 subscriptions; that count is context, not an input to the arithmetic. The model is driven by the measured 1,740 first-year refusals. The low case assigns $200 of debt or credit exposure and $50 of resolution work to each refusal. The high case assigns $400 and $100 respectively.
| Value driver | Low case | High case | Method |
|---|---|---|---|
| Operating scale | 18,000 subscriptions | 18,000 subscriptions | Scenario context, not a multiplier |
| Refused entries | 1,740 | 1,740 | Measured in the first year |
| Debt or credit exposure per refusal | $200 | $400 | Replaceable scenario assumption |
| Resolution work per refusal | $50 | $100 | Replaceable scenario assumption |
| Modelled annual value at risk | $435,000 | $870,000 | 1,740 × ($200 + $50) to ($400 + $100) |
| Reconciliation capacity | Three weeks recovered | Three weeks recovered | Measured separately and excluded from the dollar range |
The debt-or-credit and resolution components are explicit scenario assumptions, not client measurements. The separately measured three-week year-end clean-up is excluded from the dollar range, so the same labour is not counted twice.
This is one control inside one finance workflow. When one bounded control puts a modelled six-figure exposure in view before the wider operational benefit is counted, it is no longer an automation line item. It is operating infrastructure.
We did not buy a faster way to post. We bought the only version of this where nobody has to go looking in March for what went in twice in June.
Approved testimonial wording · Financial controller at the client
What this case does not claim.
No claim that every refusal prevented a permanent loss. The debt-or-credit exposure and the resolution work per refusal are replaceable assumptions, printed so a reader can argue with each component rather than being asked to accept the total.
No claim that the subscription count caused the refusal count. The operating scale is context, not a multiplier; the measured refusals are what drive the model.
No claim that the modelled range appeared in the client’s bank account. Duplicate journals can misstate debt or credit without becoming duplicate cash movements. The page therefore publishes the measured reconciliation result and labels the dollar range as a replaceable sensitivity model.