Bank statement reconciliation

Bank statement reconciliation,
back to its source.

banktrail turns bank statement exports into a record you can check, with each bank transaction linked to its source. Keep named accounting ledgers alongside it, with searchable entries, notes and tags. Link accounting entries to bank transactions and follow each match in either direction. Missing statements and unread rows stay visible for review.

  • Every bank transaction points back to its source file and position.
  • Missing statements and unread rows stay visible in the chain.
  • Accounting entries link to bank transactions in both directions.
Watch banktrail in action 39-second walkthrough
banktrail Northwind Traders, Jan–Apr 2025 — 21 rows, 2 breaks in the balance chain, 1 row the bank printed that banktrail could not read
northwind
Date Description Reference Amount Balance Account
1 2025-01-03 INVOICE SETTLEMENT ACME LOGISTICS INV-2201 188,400.00 670,590.55 0132-4477810-03
2 2025-01-07 RENT UNIT 4 HARBOUR ESTATE rent SO-1180 -96,250.00 574,340.55 0132-4477810-03
3 2025-01-09 SUPPLIER PAYMENT KHALID BROS CHQ 100442 -41,875.20 532,465.35 0132-4477810-03
4 2025-01-14 SALARY BATCH JANUARY payroll PR-2025-01 -238,914.00 293,551.35 0132-4477810-03
5 2025-01-14 SALARY BATCH JANUARY payroll PR-2025-01 -238,914.00 54,637.35 0132-4477810-03
6 2025-01-21 INVOICE SETTLEMENT ACME LOGISTICS INV-2214 215,600.00 270,237.35 0132-4477810-03
7 2025-01-28 UTILITIES K-ELECTRIC DD-0093 -18,442.10 251,795.25 0132-4477810-03
8 2025-01-31 BANK CHARGES -1,250.00 250,545.25 0132-4477810-03
9 2025-02-03 INVOICE SETTLEMENT NORTHWIND RETAIL INV-2219 142,300.00 392,845.25 0132-4477810-03
10 2025-02-06 RENT UNIT 4 HARBOUR ESTATE rent SO-1180 -96,250.00 296,595.25 0132-4477810-03
Chain break · account 0132447781003 · 2025-02-06 → 2025-02-14 · expected 55,295.25, found 119,795.25 · 64,500.00 unaccounted for · 1 unread row(s) in northwind-2025-02.csv may hold this
11 2025-02-14 SALARY BATCH FEBRUARY payroll PR-2025-02 -241,300.00 119,795.25 0132-4477810-03
12 2025-02-19 INVOICE SETTLEMENT ACME LOGISTICS INV-2223 198,750.00 318,545.25 0132-4477810-03
13 2025-02-25 SUPPLIER PAYMENT KHALID BROS CHQ 100467 -52,300.00 266,245.25 0132-4477810-03
14 2025-02-28 BANK CHARGES -1,250.00 264,995.25 0132-4477810-03
Chain break · account 0132447781003 · 2025-02-28 → 2025-04-04 · expected 441,895.25, found 554,675.75 · 112,780.50 unaccounted for · no statement covers this window
15 2025-04-04 INVOICE SETTLEMENT NORTHWIND RETAIL INV-2241 176,900.00 554,675.75 0132-4477810-03
16 2025-04-08 RENT UNIT 4 HARBOUR ESTATE rent SO-1180 -96,250.00 458,425.75 0132-4477810-03
17 2025-04-14 SALARY BATCH APRIL payroll PR-2025-04 -243,050.00 215,375.75 0132-4477810-03
18 2025-04-17 SUPPLIER PAYMENT KHALID BROS CHQ 100501 -38,120.00 177,255.75 0132-4477810-03
19 2025-04-22 INVOICE SETTLEMENT ACME LOGISTICS INV-2247 205,300.00 382,555.75 0132-4477810-03
20 2025-04-29 UTILITIES K-ELECTRIC DD-0101 -19,105.40 363,450.35 0132-4477810-03
21 2025-04-30 BANK CHARGES -1,250.00 362,200.35 0132-4477810-03
21 rows Filter net -297,270.70 ⚠ 2 chain breaks all accounts
Chain break 2025-02-06 → 2025-02-14 expected 55,295.25, found 119,795.25 64,500.00 unaccounted for what the workbook below calls “diff 64,500??” — now with a date and a cause
The file this replaces

Without banktrail, completeness is checked by hand.

Whether the population is complete is answered today in a workbook like this one: the same three statements typed into a single sheet, with manual per bank and diff columns bolted on the side.

By hand — not banktrail Northwind Traders, Jan–Apr 2025. Three statements typed into one sheet.
recon_FY25_v3_FINAL(2).xls — last saved 11:48 PM
=F19-G19  …doesn’t tie. diff 64,500?? see note

Every figure in the workbook is defensible on its own. The person who maintains it is not careless. What the workbook cannot show is whether a statement is missing: the difference gets a note, a colour and a colleague’s name, where the viewer above gives the same 64,500 a date window and a cause.

What the import returned

The same rows now show a chain break.

Consecutive statements have to chain: each expected closing balance must appear among the balances the bank printed. Where they fail to join, banktrail reports the break rather than the total.

  • A break is drawn between the two rows it separates, with the date window and the amount nobody can account for. The workbook’s “diff 64,500??” becomes 64,500.00 unaccounted for between 2025-02-06 and 2025-02-14.
  • A break has one of two causes. Either an unread row — a row the bank printed that banktrail could not read — or a statement nobody sent. The first break here is an unread row: the cell printed as #####, which stays in the unread list with its file, its line, and the reason it was refused. The second is a missing statement, and no document on hand covers 2025-02-28 to 2025-04-04.
  • The row struck out in the workbook is still here. Two payments with the same amount and payee on the same day are two payments, not one. The statement printed both at different positions, and banktrail treats each position as a separate transaction. A parser that discards rows produces a ledger that looks complete but is short. That is the most expensive failure mode, because the output carries the authority of every row that parsed.

A matching balance is only one check. Read the guide to checking for missing bank statements for the full source inventory and coverage steps.

The viewer

One import, four ways to read it

Select a tab in the viewer above to see the same three statements as transactions, accounts, documents, or the integrity report.

  • Transactions is a virtualised grid. It draws the rows in view instead of rendering the entire ledger at once, so long ledgers remain practical to browse. A chain break appears in the grid between the two rows it separates, not on a separate report page. Tags sit on their rows and keep the same colour across sessions. Any selection copies as TSV straight into a spreadsheet.
  • Accounts shows the state of each balance chain — the sequence of closing balances across statements. Each account is listed with its currency, transaction count, date span, money in and money out, and a state: intact, has breaks, or unverifiable. Unverifiable means the statements print no running balance, so no continuity check is possible. It is a state of its own, never reported as passed.
  • Documents lists every imported file: the format it was read as, rows produced, rows unread, whether the statement arithmetic balances, and the SHA-256 of the file as uploaded. Each transaction records the document and byte range it came from.
  • Integrity is the report in full: uid integrity, provenance, the amount mirror, statement arithmetic and balance continuity, each with pass or fail and the count behind it. The sample company fails balance continuity, because two chain breaks and one unread row mean the ledger is incomplete.

Tags, comments and supporting evidence stay with the records they explain. Corrections keep an attributed edit history. Evidence can attach to many rows at once, and a SQLite snapshot preserves accounting entries, bank matches and statement sources together.

Accounting ledgers

Link your accounting entries to the bank record

Create named ledgers for purchases, sales or other accounting records. Add entries by hand or import CSV, then compare them with bank statement transactions.

  • Use the same review tools on every entry. Keep tags, comments, supporting images and edit history with accounting entries. Search descriptions, references, tags and notes within one ledger or across all your accounting ledgers.
  • Find and confirm a match. Narrow candidates by text, currency, amount and date range, then record the relationship with a note. You can start from an accounting entry or a bank transaction.
  • Follow the link in either direction. Open the bank transaction from its accounting entry, or the accounting entry from the bank transaction. An entry can link to several bank transactions, and a bank transaction can link to several entries. Each reviewer can withdraw their own match.

Reimporting an identical accounting entry with the same external ID keeps the existing entry. A conflicting entry is flagged before the batch is imported.

Where this came from

Every row parsed. The population was still short.

Getting rows out of statement files is the easy part. banktrail came out of a reconciliation across 284 bank statements from 6 banks. Asked how many transfers of one kind had been made, the first answer was eleven. Eleven was right — for one account, out of a population of three, over a date range everyone had assumed was continuous and was not. Every row that had been read had been read correctly, which is exactly what made the number so convincing. No statement parser we could find would have caught it. Accountants, auditors and controllers meet this constantly: every row parses, and the population is still short.

  • money

    Money is always handled as Decimal.

    A ledger must foot to the minor unit. It cannot rest on a data type where 0.1 + 0.2 is not 0.3. Every amount is a Decimal from the reader to the ledger, and a string everywhere in between.

  • dates

    Adapters declare the date order.

    An adapter is the component that reads one bank's statement format, and it declares that bank's date order. 03/01/2023 is 3 January in Karachi and 1 March in Chicago. Where a date is ambiguous and no order is declared, banktrail warns rather than picks.

  • files

    File type is detected from the content.

    Banks send .xls files that are HTML documents and .xls files that are genuine BIFF. The extension does not tell them apart. banktrail reads the bytes and decides from those, which is the only safe way to identify a format.

  • footing

    A statement must balance before it imports.

    The import is refused unless opening plus net movement equals closing. That one check catches a misread column and a defective adapter. Neither is imported.

  • scans

    A scan is rejected until every token is accounted for.

    banktrail refuses an image-only PDF rather than parsing it to nothing. Reading one is a separate, deliberate step: OCR turns the pages back into positioned words, and a capture report then accounts for every token on the page that looks like money before the import is allowed. A partial read shows up in the report instead of disappearing into the total.

  • identity

    Identical payments on the same day are two payments.

    Two payments with the same amount, payee and date are two transactions. banktrail identifies each by its position in the statement rather than by its contents, so both salary payments on the 14th survive an export that shuffles the rows.

  • annotations

    Annotations record where they came from.

    Tags, comments and supporting images stay with bank transactions and accounting entries. Each match records who made it and how it was selected, with an optional confidence and note. Reviewers can follow the recorded relationship from either entry.

  • audit

    The ledger downloads as a standalone file.

    A SQLite snapshot preserves accounting entries, annotations and bank matches alongside the statement evidence. An auditor can inspect the file with tools they already use, without relying on banktrail being online.

Accounts whose statements carry no balance column are reported as unverifiable, never as passed. Reporting an unchecked account as intact would claim a proof that was never run.

How you run it

In your browser. Or on your desktop.

Create a hosted workspace to review statements in your browser, with nothing to install. Or use the new desktop app to work with a ledger on your own computer, with the same statement checks, accounting ledgers and review tools. The desktop app targets Mac and Windows and is currently in preview; public installers are not available yet. Command-line and self-hosted tools remain available for custom workflows.

Desktop features and download status →

  • It reads XLSX, XLS, CSV, HTML, PDF (text layer), text e-statements. The type is detected from the content, not the file extension: an .xls file that is really an HTML document is read as HTML. See supported formats and their limits.
  • Adding a bank does not require a software release. For most banks the statement layout is described by naming the header fragments the bank prints, so a layout nobody has seen before is a configuration change. banktrail can add a new bank from a single statement.
  • Agents and integrations use an HTTP API authenticated with a key, with reader, annotator, importer and editor roles. They can create accounting ledgers, import entries, search, annotate and link accounting entries to bank transactions. Matches and edits retain their attribution.