Every self-managed HOA board eventually asks the same question at month-end: does the bank statement actually match what's in the books? Most answer it the hard way — someone opens the bank's PDF statement in one window, the accounting software in another, and manually checks off each transaction by hand, hunting for the ones that don't line up. It's tedious, easy to get wrong at 11pm after a full-time job, and when a treasurer rotates off the board, whatever mental model they had for "which weird transactions are normal" rotates off with them.
Getting bank data into an HOA's books in the first place is a solved problem for most modern platforms — connect a bank account, transactions flow in, an AI categorizer sorts them into expense accounts. LotWize does that too. But categorized transactions sitting in a list aren't the same thing as a reconciled set of books. Reconciliation is the separate, harder step of proving that the cash movements the bank actually processed are the same cash movements the general ledger says happened. That's the job LotWize's reconciliation agent is built to do, and the mechanics are worth walking through, because they're more interesting than "AI checks your bank account."
Reconciliation is a matching problem, not a categorization problem
Bank sync and categorization answer "what is this transaction and which expense account does it belong to?" Reconciliation asks a different question: for every dollar that moved through the bank account, is there a corresponding entry in the ledger — and for every ledger entry that touched cash, did the bank actually process it?
Those two things drift apart constantly, for reasons that have nothing to do with anyone making a mistake. A vendor payment posts to the ledger on the 28th but doesn't clear the bank until the 2nd of next month. A bank charges a $12 monthly service fee nobody entered because nobody knew about it until the statement arrived. An HOA earns $4.16 in interest on its operating account — real income that technically needs its own journal entry. None of these are errors. They're the normal seams between what the board recorded and what the bank actually did, and a board has to reconcile them every period or the books quietly stop being trustworthy.
How the matching engine actually works
The core matching logic lives in a pure, deterministic function — autoMatch() in lib/accounting/reconciliation.ts. It's intentionally strict: a bank transaction's effect on the cash balance (bankTxnCashDeltaCents, the negative of a debit amount) and a ledger entry's cashDeltaCents are candidates for a match only if they're exactly equal — no fuzzy matching on amount. Among equal-amount candidates, only ones dated within a four-day window qualify, and ties go to whichever is closest in date. Bank transactions process oldest-first, so the same input always produces the same output.
Whatever doesn't pair off — a bank transaction with no same-amount ledger entry nearby, or a ledger entry with no corresponding bank activity — falls out as unmatched. No machine learning model, no confidence score: exact-amount, close-date, greedy matching, deliberately simple because reconciliation is a place where "probably right" isn't good enough. A second function, computeReconciliation(), then does the arithmetic a treasurer would do by hand: beginning balance plus every cleared cash movement should equal the bank statement's ending balance. If the difference isn't zero, the reconciliation isn't done.
Where AI actually enters: classifying and proposing entries for the leftovers
The matching itself is pure math. Judgment shows up specifically for unmatched bank transactions — activity the bank processed that nobody recorded, usually because nobody knew it was coming. classifyBankTxn() in lib/agents/reconciliation-agent.ts reads the bank's own transaction description against three patterns: "fee," "service charge," or "maintenance charge" on an outflow becomes a bank_fee; "NSF," "overdraft," or "returned item" becomes an nsf_fee; "interest" on an inflow becomes interest. Anything else comes back unknown and waits for a human — the agent doesn't guess.
For what it can classify, proposeEntryForBankTxn() drafts a fully balanced journal entry referencing LotWize's real chart-of-accounts codes, so a board member approves it rather than building it. A bank fee debits Administrative and credits Operating Cash; interest income debits Operating Cash and credits Interest Income.
The guardrail that matters more than the matching
The most important design decision isn't the matching algorithm — it's what happens with the results. LotWize's agents share a single autonomy ladder (lib/agents/autonomy.ts): L0 only suggests, L1 drafts and queues for approval, and L2/L3 auto-execute work that's within board-set rules, with L3 differing only in notification cadence.
A clean one-to-one match is treated as "within rules," so at L2+ it can auto-clear without a click. But every unmatched bank transaction or ledger entry is, by definition, an exception, and decideDisposition() always routes exceptions to the approval queue — even at the highest autonomy level. That's hard-coded into planReconciliationRun(), not a setting a board can loosen, because posting to the ledger and clearing cash are fiduciary actions: authorizing "auto-clear my clean matches" is not the same as authorizing "auto-post whatever the agent guesses about a fee I never approved."
What a board actually sees
The feature lives at /board/finances/bank/reconcile, titled "Bank Reconciliation" with the subtitle "Operating Cash · match imported bank activity to the general ledger." Three stat cards summarize the period — Auto-matched, Bank items to review, Ledger items to review — and a "Complete reconciliation" card states the close condition plainly: confirm the statement balance, the auto-matched transactions clear, and it ties out when the difference is zero.
Two panels handle the leftovers, "Bank items not in the ledger" and "Ledger entries not on the statement," each reading simply "All cleared." when there's nothing to review — no manufactured urgency once a community has a few clean months behind it. The feature sits behind a hasBankSync plan flag; without it, a community is redirected to the subscribe page.
A concrete walkthrough
Say a 40-unit community's operating account shows a beginning balance of $18,400 for the month. The bank processes twenty-two transactions: dues deposits, vendor payments, and two the board never manually recorded — a $9.50 monthly maintenance fee and $3.12 in interest.
autoMatch() pairs twenty of the twenty-two bank transactions cleanly against the posted ledger entries for expected dues and vendor payments — those clear automatically once the board has L2 autonomy turned on for reconciliation. The $9.50 fee and $3.12 interest deposit have no ledger counterpart, so they fall out as unmatched.
classifyBankTxn() reads "MONTHLY MAINTENANCE FEE" on the outflow and returns bank_fee; it reads "INTEREST PAYMENT" on the inflow and returns interest. proposeEntryForBankTxn() drafts two balanced entries — Administrative debited and Operating Cash credited for $9.50, Operating Cash debited and Interest Income credited for $3.12 — and both land in the approval queue rather than posting themselves. A board member approves both in a couple of clicks, and the reconciliation ties out to zero. Nobody spent an evening cross-referencing twenty-two line items against a PDF statement to find the two that didn't belong.
Why this is worth building carefully
Reconciliation is the step where a lot of HOA software quietly gives up and leaves the board to sort it out manually, because getting the matching logic right — and getting the guardrails right — is more work than syncing a bank feed. A matching engine that's too permissive creates false confidence: transactions get marked "cleared" that don't actually correspond to anything, and a board stops trusting the number at the bottom of the page. LotWize's approach is narrower on purpose: match only on exact amount within a tight date window, auto-clear only what's unambiguous, and treat every exception — no matter how small the dollar amount — as something a human signs off on before it touches the books.
2026 Update: The AI Reconciliation Agent is live for LotWize communities on plans with bank sync enabled, matching cleared bank activity against the general ledger and proposing ready-to-approve entries for fees and interest the board never had to hunt for manually. See how it compares to manual reconciliation workflows in our guide to HOA software alternatives, or start a free LotWize trial to reconcile your own operating account.
Key Takeaways
Reconciliation is a distinct step from bank sync and categorization — it proves the bank statement and the general ledger actually agree, not just that transactions were imported and sorted.
Matching is exact and deterministic: a bank transaction pairs with a ledger entry only when their cash effect is identical and their dates fall within a four-day window, with ties broken by closest date.
AI is used narrowly, only on the leftovers — reading a bank transaction's own description to classify unmatched items as a bank fee, an NSF charge, or interest income, and drafting a balanced journal entry a board approves in one click.
Clean, one-to-one matches can auto-clear once a board turns on higher autonomy, but every exception — an unmatched bank transaction or ledger entry — always queues for human approval, at every autonomy level, with no override.
The reconciliation page shows exactly what doesn't tie out — which bank items have no ledger entry and which ledger entries have no bank activity — so a board resolves specific line items instead of re-checking an entire month by hand.
Frequently Asked Questions
What does LotWize's AI Reconciliation Agent actually do?
It matches every imported bank transaction to the posted journal entry it should correspond to, using a signed cash-delta comparison within a four-day window. Clean matches clear automatically once a board authorizes it; anything that doesn't match is always routed to a human approval queue, regardless of autonomy level.
Is this the same thing as LotWize's bank sync and transaction categorization?
No, it's the next step after it. Bank sync pulls transactions in and an earlier AI step categorizes them into expense accounts. Reconciliation is the later process that proves the statement and the ledger actually agree, the same way a treasurer would tie out a checkbook by hand.
Can the reconciliation agent post transactions without a human approving them?
Only clean, one-to-one matches — same amount, within four days — can auto-clear, and only once a board turns that autonomy level on. Every exception, including proposed entries for fees or interest, is always queued for a human to approve.
How does the agent know a transaction is a bank fee or interest, not something else?
It reads the bank's own transaction description. Wording like "fee" or "service charge" on an outflow is classified as a bank fee; "NSF" or "overdraft" as an NSF charge; "interest" on an inflow as interest income. Anything else is left unclassified and queued as a plain exception.
What happens to a reconciliation that doesn't balance?
The board sees exactly where the gap is. The worksheet compares the reconciled ending balance to the bank statement's ending balance and reports the difference, and the review panels show precisely which bank items and ledger entries are unmatched — so the board resolves specific line items instead of re-checking the whole month.