How we verify AI-extracted bank statements — deterministically
AI is good at reading bank statements and terrible at knowing when it's wrong. Our answer is to never let the model be the last word: every number an AI extracts is checked by deterministic arithmetic against the statement's own printed balances, statements that don't prove out are flagged rather than shipped, and every automatic correction must re-prove the statement end to end before it's accepted. This is a plain-language tour of that verification layer — what it catches, what the checkmarks actually assert, and why 'needs review' is a feature.
Why isn't AI extraction alone trustworthy?
Modern models read statements impressively well — most rows, most layouts, most banks. The problem is the failure mode. When a model misreads, it doesn't produce something that looks broken; it produces something plausible. A 57.20 becomes 75.20. A payment's credit marker gets dropped and the amount lands as a debit. A row quietly disappears from a dense page. Each of these survives a visual skim, because nothing about the output looks wrong.
With financial data, plausible-but-wrong is the worst possible failure mode. A spreadsheet that is obviously mangled gets fixed; a spreadsheet that is subtly wrong gets imported, reconciled against, and discovered weeks later as a mystery discrepancy in the books.
So the design question isn't 'how do we make the model read better?' — it reads well, and it will keep improving. The question is: what in the pipeline is allowed to say 'this is correct'? Our answer: never the model. Arithmetic.
What is balance-chain verification?
A bank statement carries its own proof system. Most statements print a running balance beside each transaction, and every statement states its opening and closing balances. Those numbers aren't decoration — they're an arithmetic chain: opening balance, plus each credit, minus each debit, must land exactly on the printed balance at every step, and finally on the closing balance.
That chain is what we check, to the cent, with exact decimal arithmetic — no floating point. Every extracted row is tested against the printed balance that follows it: previous balance plus this amount must equal this row's balance. A row that passes is marked verified. If a digit were transposed, an amount attributed to the wrong side, or a row dropped entirely, the chain breaks at that exact point — the error can't stay hidden, because the bank's own printed numbers contradict it.
The same arithmetic settles direction. Whether a row is money in or money out isn't taken from the model's guess — it follows from which sign makes the chain hold. A dropped 'CR' marker can't silently flip a payment into a charge.
This is why the approach needs no per-bank templates. Layouts differ; arithmetic doesn't. Any statement that prints balances brings its own answer key, in any language, from any bank.
What does the checkmark actually assert?
Precision matters here, because the marks are a contract.
- A solid check on a row means that specific row was proven against the printed running balance that follows it. Not 'looks right' — proven.
- 'Reconciled' on a statement means the whole chain ties: opening balance plus every transaction lands exactly on the closing balance.
- Some statements — most credit cards — print no running balance beside rows, so no individual row can carry its own proof. When the account totals still tie exactly from opening to closing, rows wear a softer mark: covered by the statement-level proof rather than individually witnessed. The strong mark is never diluted to make a page look greener.
The distinction is deliberate. A verification mark that can be earned two different ways stops meaning anything; ours are earned exactly one way each, and the interface says which.
Why is 'needs review' a feature, not a failure?
When the arithmetic doesn't tie, the honest output isn't a best guess — it's a flag. A statement that's off by 405.20 says so, with the difference stated, instead of shipping a spreadsheet that silently absorbs the discrepancy. A row the system can't prove is marked for review instead of blending in with the proven ones.
This runs against the grain of most converters, which are built to always produce output and let you discover the quality later. We think the opposite contract is worth more: when the result is green, you can build on it without re-checking; when it isn't, your review time is pointed at exactly the rows that need eyes, not spread across thousands that don't.
The flags are also load-bearing for scans. A photographed or scanned statement has no text layer, and optical misreads — a 0 read as an 8, a dropped decimal — are precisely the plausible-looking errors a skim misses. Because a misread breaks the balance chain, scanned statements get their errors caught by the same arithmetic, and rough scans simply surface more flagged rows: the system telling you where to look.
How do automatic repairs avoid making things worse?
Sometimes the pipeline can fix an extraction problem on its own — a statement whose opening balance is printed only as the first ledger line, an amount whose digits got fused with a balance, a whole section a model skipped. Every one of these repairs follows the same rule: propose the correction, then re-run the verification, and accept the repair only if the statement now ties end to end, exactly, with zero unexplained rows.
If the repaired statement doesn't fully prove out, the repair is discarded and the honest 'needs review' verdict survives. A correction that can't demonstrate it made the statement arithmetically consistent is treated as a guess — and guesses don't ship.
The same discipline applies at the boundaries people rarely think about: currencies with three-decimal minor units are checked at their own precision, statements printed newest-first are re-ordered so the arithmetic chains correctly, and a document that ends mid-statement keeps its flag rather than being 'balanced' against totals that live on pages that aren't there.
What should you take away from this?
If you're evaluating any statement converter — ours or anyone's — the useful question isn't 'does it use AI?' Everything does now. The question is: what checks the AI, and what happens when the check fails?
Look for output that's verified against the statement's own balances rather than merely formatted; for uncertainty that's flagged rather than hidden; and for the difference stated when something doesn't tie. Those properties, not the model, are what make an extracted spreadsheet safe to build on.
You can see the whole system work in about half a minute: convert a statement — no signup for the first pages — and watch each statement reconcile against its own printed balances before you export.
Frequently asked questions
- Does 'reconciled' mean the AI made no mistakes?
- It means every extracted number is arithmetically consistent with the statement's own printed balances, from opening to closing, to the cent. A misread amount, a flipped direction, or a missing row would break that chain — which is precisely why the tie is meaningful.
- What if my statement has no running balance column?
- Then no individual row can carry its own proof, and the interface says so honestly: when the account totals still tie exactly, rows show a softer 'covered by totals' mark instead of the solid per-row check. The statement-level reconciliation is still exact.
- Why do I see more flagged rows on scanned statements?
- Scans have no text layer, so digits are read optically, and optical misreads look plausible. Because every misread breaks the balance arithmetic, those errors get flagged instead of absorbed — more flags on a rough scan means the verification is catching more, not failing more.
- Can I trust an automatic correction the system made?
- Every automatic repair is accepted only if the statement re-verifies end to end afterwards — the complete chain, zero unexplained rows. A correction that can't prove it restored consistency is discarded and the honest 'needs review' flag remains.
Upload a bank statement PDF and get reconciled spreadsheet data back. Free to try, no sign-up.
Convert a statement — free