How the balance check works, and what it misses

Every converter in this category says it is accurate. None of them say how, or what would have to be true for them to be wrong. This page does both, because a claim you cannot check is worth nothing when the numbers are going into someone’s books.

The idea

A bank statement carries its own proof. It prints an opening balance, a closing balance, and often a running balance beside each row. Those numbers were produced by the bank's ledger, not by our parser — so they are an independent check on everything the parser read. If our transactions and the bank's balances disagree, the parser is wrong, and we can know that without ever seeing the original.

Two checks, picked automatically

Running balance, row by row

When at least 60% of rows carry a balance, every row must satisfy previous balance + amount = this row's balance. Rows with no printed balance carry the running total forward, so a gap does not throw off the rows after it. Each row is checked independently and a mismatch resyncs to the printed balance, so one bad row cannot cascade into a page of false alarms.

Opening to closing

With no balance column — Chase-style statements are organised by section and print none — the check is opening balance + Σ(all amounts) = closing balance. Weaker, because it is one equation instead of many, but it still catches a dropped, duplicated or misread row, since any of those move the total.

Source: src/parse/reconcile.ts.

Signs are solved, not guessed

Many statements print amounts unsigned and leave the direction to a column header or a section heading. Guessing is how converters silently turn a deposit into a withdrawal. Instead, when a row fails its check but would pass with the sign flipped, the sign is flipped — because the balance column proves the direction — and every flip is reported in the output. A correction you are not told about is indistinguishable from an error.

What the check cannot catch

This is the part other pages leave out. The check verifies totals, so any error that preserves the total survives it:

None of these are hypothetical; they are the reason the page says the math checks out rather than this file is correct. The check raises the floor. It does not replace a human who knows what was on the statement.

When it does not agree

Nothing is guessed and nothing is hidden. The row where the chain breaks is shown with the amount we read and the amount the balance column implies, and you decide: take the balance column's figure, or keep what the statement printed and carry the gap into the export. Until the chain agrees end to end, the file is not called verified.

Scanned statements are refused

A PDF with fewer than 100 extractable characters per page has no text layer — it is a photograph of a statement. There is no OCR here yet, so such files are rejected with a plain error instead of returning a half-empty spreadsheet that looks plausible. You can check yours in ten seconds: open the PDF and try to select a line of text. If nothing highlights, no text-based converter can read it honestly.

Check it yourself

Everything above is arithmetic you can redo in a spreadsheet: sum the Amount column, add the opening balance, compare with the closing balance the bank printed. If they match, the conversion preserved the money. That is the whole claim — and it is deliberately small enough to audit.