TL;DR

Bank of America’s CSV exports start with a 6–7 row metadata block — strip it before parsing. Their Description field mixes sender info with internal BofA codes (DES:, INDN:, CO ID:); regex out the noise before matching. Xero’s AmountDue is your source-of-truth for what’s still open.

What breaks when reconciling Bank of America with Xero

Three things that bite repeatedly:

The metadata header block. BofA’s CSV starts with several rows that aren’t transactions:

Description,,Summary Amt.
Beginning balance as of 04/01/2026,,52432.18
Total credits,,28940.00
Total debits,,-19873.45
Ending balance as of 04/30/2026,,61498.73

Date,Description,Amount,Running Bal.
04/01/2026,...

If your parser doesn’t skip these rows, you’ll get garbage cells. Look for the empty line followed by the Date,Description,... header — that’s the real data start.

The Description code soup. A typical BofA ACH credit shows up as:

DES:PAYMENT     ID:1234567890 INDN:ACME CONSULTING CO ID:1234567890 CCD

DES: = transaction description, ID: = sender’s bank-assigned ID, INDN: = individual or company name (the actual payer), CO ID: = company ID, CCD = SEC code. You want the INDN: value for counterparty matching, but it’s buried mid-string.

Running Balance is end-of-business. BofA computes Running Bal. once at end of day, so two transactions posted the same day will both show the EOD balance regardless of intraday order. Useless for intra-day sequence reconstruction.

Export the Bank of America statement

  1. BofA Business → Accounts → pick the account → Download (top-right of activity list).
  2. File type: Microsoft Excel (.csv). The Quicken / QuickBooks / Money options work too but are not standard CSV.
  3. Date range: pick a calendar month. BofA caps at 18 months historical.
  4. File saves as stmt.csv — yes, that’s the actual default filename, no date suffix. Rename immediately to avoid overwriting on the next export.

After stripping the metadata block, columns are: Date, Description, Amount, Running Bal.. Note the period in Bal.. Amount is signed: positive = credit, negative = debit.

Export the Xero invoice list

Same as the Wise + Xero guide: Business → Invoices → filter → Export → CSV.

Key columns for this combo: ContactName, InvoiceNumber, Reference, InvoiceDate, DueDate, Total, AmountDue, AmountPaid, Status, Currency.

AmountDue is what’s still open. AmountPaid is what Xero has already recorded against the invoice. If Status = PAID, AmountDue = 0. If Status = AUTHORISED and AmountPaid > 0, it’s a partial. Filter to AUTHORISED for “needs to be reconciled to bank” + PAID for “should already match a bank inflow”.

Match algorithm cheats for this combo

  1. Pre-process the BofA CSV. Drop rows where Date is empty or doesn’t parse as MM/DD/YYYY. The first 6–7 rows are metadata; skip until you hit the real header.
  2. Extract INDN: from description. Regex INDN:([^|]+?)(?=\s+CO ID:|\s+ID:|$). This gives you the payer name in uppercase. Lowercase + strip suffixes (INC, LLC, CORP) before fuzzy-matching.
  3. Amount + date window. Match BofA Amount against Xero Total exactly. ACH typically settles within 1 business day; wires same-day. Use a ±2 business day window from InvoiceDate to Date (allowing prepayment) and a ±90 day window from DueDate (catching late payments).
  4. Reference field shortcut. If the BofA description contains a substring matching INV-\d+, #\d+, or a 4–6 digit number, try it against Xero InvoiceNumber and Reference (both fields — clients use either).
  5. Status-based filtering. Drop Xero rows with Status in (DRAFT, VOIDED, DELETED) before matching. They’re not real receivables.

Real example

BofA inflow:

04/15/2026,"DES:RETAINER     ID:0001234567 INDN:DELTA STUDIOS LLC                CO ID:0001234567 CCD",7500.00,68932.50

Xero invoice line:

"Delta Studios","studios@delta.com",,"INV-2026-0421",,"04/01/2026","04/30/2026","7500.00","0.00","7500.00","PAID","USD"

Extract INDN:"DELTA STUDIOS LLC". Normalize → "delta studios". Fuzzy-match against "Delta Studios" → 1.0 (after normalization). Amount exact match. Date within range. Status = PAID confirms Xero already recorded this — our match validates the bank-side cash event. Confidence: Exact (with Xero-side already-matched signal).

Edge cases this combo hits

Check deposits. BofA’s mobile/branch check deposits show in the description as "MOBILE CHECK DEPOSIT - REF #12345" or "BRANCH DEPOSIT - REF #12345". No payer name. Match on amount only and confirm visually in the result view. The check image is accessible via BofA’s web view but not in the CSV.

Zelle inbound. Zelle deposits show as "ZELLE PAYMENT FROM <NAME> ON <DATE> CONF# <ID>". The <NAME> is the Zelle account holder, usually a personal name even for business payers (“John Smith” for “Acme Inc” payments). Cross-reference Xero contacts by both company name and known contact person.

Wire transfers. Inbound wires show "WIRE TYPE:INTL IN DATE:042126 TIME:1432 ET TRN:..." or domestic equivalents. The originator name is buried deeper; sometimes it’s the next field after OBI: (Originator-to-Beneficiary Information). Manual extraction often required.

Fees and reversals. BofA charges occasional fees as separate same-day debit rows. If you reconcile by daily aggregate, fees will reduce your net inflow. Categorize them separately before matching against Xero.

Partial payments. If a customer wires partial payment (e.g., $5,000 against a $10,000 invoice), Xero will show Status = AUTHORISED, AmountPaid = 5000.00, AmountDue = 5000.00. Your BofA row shows $5,000. Match should mark the invoice as “Partially paid”, not “Paid”.

When this combo breaks our tool

If the BofA CSV has more than 90 days of transactions in one file, our matcher’s date-window optimization becomes less efficient. Performance is OK up to ~5,000 rows; past that, expect noticeable lag.

The INDN: extraction regex assumes English/Latin-character names. If you have international payers with non-Latin characters in their BofA registration, the regex may fail. We fall back to whole-description fuzzy match, which is less precise.

If you’ve enabled Xero’s bank feed for the BofA account, Xero may have auto-matched some inflows to invoices already. Our reconciliation will partially overlap; review the “Already matched” summary in Xero before comparing.

Faster way

Drop the BofA stmt CSV + Xero invoice export into the reconciler on the homepage — header skip, INDN: extraction, and ACH-prefix stripping all happen automatically. Run takes ~10 seconds for a typical month.

For the underlying AR concepts behind these invoices, the accounts receivable glossary entry covers the foundation.

If you handle a lot of overdue invoices coming out of these reconciliations, the how-to-recover-unpaid-invoices guide covers the chase scripts.