Extracted statement: closing balance does not equal opening plus movements
In short
Foot the statement page by page rather than end to end: opening plus credits minus debits must equal the stated closing balance on every page. The first page that fails locates the fault, and the residual names it — one row's amount is a dropped line, twice a row's amount is an inverted sign, the previous page's closing balance is a brought-forward subtotal read as a movement.
Key takeaways
- A statement carries its own proof of completeness; nothing else in the client's paperwork does.
- Foot each page separately — a whole-statement check tells you only that something is wrong, never where.
- A residual equal to exactly twice a printed amount is a sign fault, not a missing row.
- A residual equal to the previous page's closing balance means a carried-forward line was emitted as a transaction.
- Where a running balance column exists, check row to row; that narrows the fault to a line rather than a page.
When the extracted bank statement balance does not match the closing figure printed on the page, the size and sign of the difference tell you which fault you have before you open the document. A statement is the rare source record that proves its own completeness: opening balance, plus every credit, minus every debit, equals the stated closing balance. If your rows fail that identity, rows are missing, duplicated, inverted or invented, and the residual separates those four in seconds.
The mistake is running the check once, over the whole statement. A 14-page statement failing by 4,318.20 tells you only that something happened somewhere. The same check run per page tells you it happened between page 6 and page 7 — a page boundary, which is a specific and very common failure with a specific fix.
Foot each page separately, then walk the running balance
- Capture the printed balances as their own fields: opening and closing for the statement, brought-forward and carried-forward at the top and foot of every page. These are labels, not transactions, and belong in a different part of the record from the rows.
- Run the identity per page. Page opening plus page credits minus page debits equals page closing. Store the residual rather than a pass or fail, because the residual is the diagnostic and a boolean throws it away.
- Find the first page that fails. Everything after it inherits the error, so only the first failure is informative. If page 7 fails and pages 8 to 14 fail by the same amount, you have 1 fault, not 8.
- Walk the running balance inside that page, where the bank prints one. Each row's balance minus the previous row's should equal that row's signed amount, and the first row where it does not is the exact line at fault.
- Count dates, amounts and description lines separately. A page with 22 dates, 22 amounts and 31 description lines has wrapped descriptions, which is formatting. A page with 22 dates and 21 amounts has lost a value.
- Use the statement's own totals block. Many banks print total credits and total debits for the period — an independent check that parsers reading only the transaction table never use.
Six residuals, and what each one means
| Residual signature | Most likely cause | What confirms it |
|---|---|---|
| Equals one printed amount exactly | A row dropped, or the same row emitted twice | Count that amount in the raw text layer against the rows you emitted |
| Equals exactly twice a printed amount | One row's sign inverted: a debit read into the credit column | The row exists with the right value and the wrong direction; the running balance breaks there and never recovers |
| Equals the previous page's closing balance | A brought-forward line emitted as a transaction | A row with a balance-like description, no counterparty and no reference |
| Equals a contiguous block of rows | A page, or one column of a page, was never read | File page count against the page-of-n marker in the footer |
| Small, and grows with row count | Amounts truncated, or a separator misread on a subset of rows | Recompute from the raw strings; locale faults cluster by document source, not by page |
| Equals a page's own subtotal line | A subtotal such as total this page ingested as a movement | The offending row's amount equals the sum of the rows above it |
The last two rows cost teams the most time, because both look like arithmetic and neither is. A residual growing with row count is a parsing convention fault, damaging a population defined by who produced the document rather than by which page it sits on — the asymmetry that makes dates and amounts wrong for only one client's suppliers so durable.
Rows that fall into the gap between two pages
Page boundaries are the largest source of missing transactions, by three mechanisms. A row printed across the break has its date and description on one page and its amount on the next. A table detector working page by page ends the table at the last complete row and discards the partial one. And a page repeating its column titles can push the first data row into the header band, where a row detector reads it as furniture.
The tell is a residual at a page transition equal to one row's amount, or to 2 adjacent rows. The fix is to stitch pages before detecting rows rather than after: concatenate the text layer with page markers retained, detect the table once across the document, then attribute each row back to its page for provenance. Statements arriving inside a larger bundle have an earlier failure than this one, because a boundary error at intake means page 7 may not be in the same file at all — that is a batch scan splitting into the wrong number of documents, and it has to be ruled out first.
The lines that look like transactions and are not
Every statement carries rows with an amount that move no money: balance brought forward, balance carried forward, total credits, total debits, interest summary blocks, and on card statements the previous and new balance lines. Each has a date-shaped field and a number in the amount column, which is all a naive row detector needs to promote it to a transaction.
Detect them by role rather than by wording. Bank phrasing varies — b/f, b/fwd, opening balance, balance from previous statement — and a keyword list built from 3 banks fails on the fourth. Two structural signals hold: the row's amount equals the running balance at that point rather than a delta, and the row has no counterparty, no reference and no transaction code. Emit these to a separate labels collection, where the continuity check can use them as anchors.
One bank's columns run the other way round
Layout conventions are not universal. Some statements print debit then credit, some the reverse, some use a single amount column with a Dr or Cr suffix, a trailing minus, or parentheses for negatives. Indian statements commonly head the columns withdrawal and deposit, and card statements often invert the convention outright, because a payment reduces what is owed.
A column-order fault produces a residual of exactly twice the affected amount, the cleanest signature in the set. Store the detected column mapping on the statement record with the layout fingerprint that produced it, so the next statement from that bank resolves without re-detection — and so a corrected mapping replays over the statements already processed, not only the next one.
The residual is not an error message. It is a measurement, and its value points at a specific row, a specific page or a specific column.
The page that never arrived, and the file that never opened
Where the residual is large, unremarkable and matches no row, the document is usually incomplete rather than misread. Clients photograph statements, print them one-sided, or forward a truncated download. Three checks settle it: the page-of-n marker against the file's actual page count, the date gap between the last row of one page and the first of the next, and whether the final page carries a closing balance at all. A statement missing its last page normally ends with no closing figure, so the check has no anchor and should report a missing anchor rather than a residual.
Settle that before re-parsing: a re-parse of an incomplete document returns the same incomplete answer with more confidence attached. A statement that never opened is a different queue — see half the client statements that will not open for the failure classes upstream of everything here.
Re-parse, ask for a better copy, or put it in front of a person
- Row-level signature, digital PDF with a text layer. Re-parse with the corrected mapping or the stitched-page pass. This is the only branch automation finishes on its own.
- Row-level signature, photograph or scan. Re-parse once, then treat a second failure as a capture problem. Rescanning at a higher resolution changes the answer; re-running the same model over the same pixels cannot.
- Anchors missing — no opening balance, no closing balance, no page-of-n. Request the document again, and be specific: ask for the bank's own portal download rather than another photograph.
- Unexplained after a corrected re-parse. Route it to a reviewer with the page-level residuals, the first failing page and that page's raw text attached. A reviewer given a residual and a page number resolves it in a minute; one given a red flag opens the whole document.
- Same bank, same signature, repeatedly. A recurring layout fault is not an incident but a mapping — authored once, tested against held-out statements from that bank, versioned, and then replayed over history.
That last branch is why continuity belongs in the pipeline as a gate rather than on a dashboard as a metric. A pipeline that refuses to emit an unbalanced result turns a silent data error into a visible queue, which is the design argued in a statement-to-transactions pipeline that gates itself. The same discipline — never treat a step as done until something outside your own process confirms it — is what stops a filing with no acknowledgement being discovered at a deadline.
What a statement that foots still does not prove
Continuity proves arithmetic completeness and nothing else. A statement can foot perfectly while every description is garbled, every counterparty is unresolvable and the dates sit a month out because a day-first layout was read month-first. Nor does it see a missing statement: 11 months that each foot are still 11 months, and only a period-coverage check finds the gap.
So run it as the first of several gates. Period coverage, uniqueness across overlapping statements and counterparty resolvability are separate checks with separate queues. Building that as an explicit sequence, each gate with its own reason string, is ordinary product build work, and it is what the rest of extraction and classification of source documents is about inside the accounting and tax systems we build.
Frequently asked questions
Short answers to the follow-ups this page tends to raise.
Why does an extracted bank statement not balance to its closing figure?
Because rows were dropped, duplicated, inverted or invented, and the residual tells you which. One printed amount means a row is missing or doubled; exactly twice an amount means a debit was read as a credit; the previous page's closing balance means a brought-forward line was emitted as a transaction. Run the check per page: only the first failing page carries information.
How do you find which transaction was dropped from a parsed statement?
Walk the running balance column row by row. Each row's printed balance minus the previous row's should equal that row's signed amount, and the first row where it does not is the line at fault. Where no running balance is printed, fall back to per-page footing, then compare the counts of dates and amounts on the failing page — unequal counts mean a value was lost rather than a whole row.
Should a statement that fails the balance check be released to the bookkeeper anyway?
No. Release the pages that pass and the recipient cannot tell the period is short, so the shortfall reappears weeks later as an unexplained reconciliation difference. The statement is the unit that passes or fails, and the correct output for a failure is no transactions plus a reason, a page number and the residual.
What tolerance should a balance continuity check allow?
None on a bank statement. Unlike an invoice, where per-line rounding can leave a small legitimate difference, a statement's movements and balances are written by one system in one currency at one precision, so the identity holds exactly. Any non-zero residual is an extraction defect or an incomplete document, and a tolerance band mainly hides the smallest and most misleading faults.
- document extraction
- bank statements
- reconciliation
- data quality
The work behind this page
Builds from our portfolio that this page draws on.
AP Copilot
An AI accounts-payable copilot that reads invoices, matches them to POs, and routes clean approvals
FintechAskVault
An AI internal knowledge-search platform that answers employee questions from your own docs — grounded in citations, with knowledge gaps surfaced and deflection tracked.
Productivity AINotewell
An AI meeting assistant that records and transcribes every meeting, extracts the decisions and action items, assigns owners and due dates, and tracks follow-through until it's done.
Productivity AIRead next
- Half the client bank statements will not open in the pipeline at allA pile of failed jobs at the first step is four different problems wearing one error message. Classify by failure class before anyone retries, re-requests or asks a client for a password.diagnostic
- Line items extract cleanly but they do not sum to the invoice totalThe lines are right, the total is right, and the two disagree. Divide the difference by the subtotal before opening the document — the ratio usually identifies the fault on its own.diagnostic
- Dates and amounts come out wrong, but only for one client's suppliersA locale fault cannot corrupt every document, which is exactly why it survives. Sample the ambiguous cases only, sliced by supplier, and the fault appears at once.diagnostic
- The end-of-day bank statement message, and the fields a PDF never hadAn XML statement the bank sends the account owner, reporting booked entries and balances. For a bookkeeping pipeline it turns extraction into validation.definition
- A credit note is not a negative invoice: where the sign really livesModel it as an invoice with a minus in front and three things break: allocation, tax reporting, and every aging report that reads the ledger afterwards.definition
- A two-hundred-page client scan splits into the wrong number of documentsBoundary errors are wildly uneven across document types, so an overall accuracy figure hides them. Count documents in against documents out, per type, and fix the cause where the pages are produced.diagnostic
Working on something in this space?
Tell us where you are in a sentence or two. We'll tell you honestly whether we're the right team, and what a sensible first slice of the work looks like.
Start the conversation