CommunityPay imports bank statements in three formats, automatically matches transactions against ledger records using an 8-strategy priority engine, and connects the results to the GL integrity scan system. This page describes the full pipeline from file upload through reconciliation.
Supported Formats
The system accepts three bank statement formats. Format is auto-detected from file content — the user does not need to specify which format they are uploading.
| Format | Extensions | Detection | Notes |
|---|---|---|---|
| BAI2 | .bai2, .bai | 01, prefix on first line |
Commercial banking standard. Includes control totals, 100+ transaction type codes, integrity verification. |
| OFX/QFX | .ofx, .qfx | OFXHEADER: or <OFX> in first 500 bytes |
Supports both OFX 1.x (SGML) and 2.x (XML). Credit card statements supported. |
| CSV | .csv, .txt | Default when BAI2/OFX signatures not found | Auto-detects delimiter and encoding. 70+ header patterns for column auto-mapping. |
BAI2 and OFX files are fully structured — they skip column mapping and parse directly into transactions. CSV files require a column mapping step because column layouts vary by bank.
Import Pipeline
The import follows a 3-step wizard. BAI2 and OFX skip Step 2 (column mapping) because their structure is self-describing.
Step 1: Upload
Navigation: Reconciliation tab > Statement Imports > Import Statement
Page title: Import Bank Statement — Step 1 of 3: Select bank account and upload statement file.
The user selects a bank account from a dropdown and uploads the statement file. Accepted extensions: .csv, .txt, .bai2, .bai, .ofx, .qfx. The help text reads: "CSV, BAI2, OFX/QFX — format is auto-detected."
Button: Upload and Continue
The system detects the file format from content signatures. If BAI2 or OFX is detected, the file parses immediately and advances to Step 3 (Match Review). If CSV is detected, the user proceeds to Step 2.
Step 2: Column Mapping (CSV only)
Page title: Map Columns — Step 2 of 3: Map CSV columns to transaction fields.
The page displays a file preview table showing detected headers and sample data rows. Below the preview, the user maps columns using dropdown selectors:
| Field | Required | Description |
|---|---|---|
| Transaction Date | Yes | The date of the bank transaction |
| Post Date | No | Settlement date (if different from transaction date) |
| Description | Yes | Transaction description or memo |
| Amount | Conditional | Single amount column (positive = deposit, negative = withdrawal) |
| Debit Column | Conditional | Separate debit amount column (alternative to single Amount) |
| Credit Column | Conditional | Separate credit amount column |
| Check Number | No | Check number for check transactions |
| Reference | No | Bank reference or confirmation number |
Either Amount or Debit/Credit columns are required — not both.
Additional options:
- Reverse sign convention checkbox: For banks that use positive for withdrawals and negative for deposits.
- Date Format Override: Text input for explicit date format (e.g., %m/%d/%Y). Leave blank for auto-detection.
A sidebar collects optional Statement Balances (begin date, end date, beginning balance, ending balance) which enable integrity verification if provided.
The system auto-suggests column mappings based on 70+ recognized header patterns (e.g., "Transaction Date", "Tran Date", "Date Posted" all map to the date field).
Button: Parse and Continue
Step 3: Match Review
Page title: Review Matches — Step 3 of 3: Accept or reject proposed matches, then apply to reconciliation.
This is the primary review interface. It has four main zones:
Integrity Verification (top): Three status boxes showing pass/fail/not-available for: - Transaction count verification (parsed count matches control total) - Balance verification (computed vs. stated ending balance) - Hash verification (data integrity check)
Each box shows green checkmark text for pass, red X text for fail, or grey dash for not available.
Summary Statistics: Five stat cards showing Total Lines, Matched (green), Unmatched (red), Deposits total, and Withdrawals total.
Proposed Matches section: A stacked card list (not tabs) of matched transactions. Each match shows the bank line, the matched ledger record, the matching strategy that found it, and a confidence badge (Exact, High, Medium, or Low). Each match has Accept and Reject buttons that fire AJAX requests and reload the page.
Above the matches: an Accept All Exact button that bulk-accepts all exact-confidence matches in one action.
Unmatched Lines section: Bank lines with no ledger match. Each unmatched line shows three inline action buttons: - Bank Fee — creates a journal entry recording a bank fee (DR: Bank Fee Expense, CR: Cash) - Interest — creates a journal entry recording bank interest (DR: Cash, CR: Interest Income) - Exclude — marks the line as excluded from matching (e.g., duplicate or irrelevant)
These are inline buttons, not a dropdown menu.
Excluded Lines section: Lines that have been manually excluded.
For large imports (100+ lines), matching runs asynchronously via Celery. The page shows a blue "Matching in Progress" banner with automatic 5-second refresh until matching completes.
Final action: Apply Accepted Matches — converts all accepted matches into BankReconciliationItem records via the ReconciliationBridge service and creates journal entries for any bank fees or interest recorded during the review.
Matching Engine
The TransactionMatchingEngine evaluates each bank statement line against 8 strategies in priority order. The first strategy to produce a match wins. Strategies are direction-aware — deposit-only strategies skip withdrawal lines and vice versa.
Strategy Priority Order
| Priority | Strategy | Direction | What It Matches |
|---|---|---|---|
| 1 | Bank fee/interest | Any | Lines matching bank fee or interest description patterns (e.g., "service charge", "monthly maintenance fee", "interest paid") |
| 2 | Stripe payouts | Deposits | Stripe payout transfers to the HOA bank account |
| 3 | AR payments | Deposits | Resident assessment payments matched against posted invoices |
| 4 | Trust deposits | Deposits | Deposits into trust accounts matched against trust ledger entries |
| 5 | AP payments | Withdrawals | Vendor payments matched against posted bills or vendor payment records |
| 6 | Loan payments | Withdrawals | Loan payment outflows matched against scheduled loan payments |
| 7 | Trust disbursements | Withdrawals | Disbursements from trust accounts matched against trust ledger entries |
| 8 | Journal entry fallback | Any | Matches against any journal entry line by amount and date proximity |
Confidence Levels
Each match receives a confidence score that determines its badge:
| Confidence | Badge | Criteria |
|---|---|---|
| Exact | Green | Amount matches to the penny AND date matches exactly or within 1 day AND reference number or description matches |
| High | Blue | Amount matches AND date within 3 days AND partial description match |
| Medium | Yellow | Amount matches AND date within 7 days |
| Low | Grey | Amount matches but date gap exceeds 7 days, or amount is close but not exact |
The engine performs duplicate detection — if a ledger record has already been matched to a different bank line (in the current import or a previous one), it is not matched again.
Reconciliation Bridge
When the user clicks Apply Accepted Matches, the ReconciliationBridge service converts the accepted matches into formal reconciliation records:
- Each accepted match creates a
BankReconciliationItemlinking the bank statement line to the matched ledger record - Bank fee matches auto-create balanced journal entries via
JournalEngine(DR: Bank Fee Expense, CR: Cash) - Interest matches auto-create balanced journal entries via
JournalEngine(DR: Cash, CR: Interest Income) - All auto-created journal entries flow through the enforcement dispatcher — guard chain evaluation, immutable decision logging, the full enforcement path
The bridge does not bypass any accounting controls. A bank fee journal entry receives the same enforcement decision as a manual journal entry.
BAI2 Parser
The BAI2 parser handles the commercial banking standard with production-grade features:
- Integrity verification: 6 checks — control totals, balance integrity, transaction count, group/file consistency
- 100+ transaction type codes: Full BAI2 type code registry with human-readable descriptions
- Classification: Transactions classified as loan (6xx codes), fee, wire, ACH, or check based on type code
- Value-date extraction: Funds availability type V for value-dated transactions
- Multi-group/multi-account: Handles files with multiple bank groups and accounts
- Bank-specific quirk handling: Accommodates known formatting variations from Wells Fargo, JPMorgan, and Bank of America
OFX/QFX Parser
The OFX parser handles both versions of the Open Financial Exchange standard:
- OFX 1.x (SGML): Automatically closes unclosed tags per the SGML spec
- OFX 2.x (XML): Standard XML parsing
- Credit card support: Handles
CCSTMTRS(credit card statement) response elements - FITID matching: Uses the Financial Institution Transaction ID as the primary deduplication reference
- CURDEF extraction: Reads currency designation from the statement header
- Date range: Extracts
DTSTART/DTENDfor statement period bounds
Connection to Integrity Scanning
Bank statement import feeds directly into the ledger integrity scan system. The scan runs 6 automated checks on the general ledger:
| Check | What It Verifies |
|---|---|
| Balance Check | Every journal entry has equal debits and credits |
| Orphaned Lines | No journal entry lines exist without a parent entry |
| Enforcement Decision | Every journal entry has an associated enforcement decision |
| Fund Assignment | All journal entry lines have fund assignments |
| Closed Period | No entries posted to closed or locked fiscal periods |
| Control Account Reconciliation | GL control accounts (AR, AP, Loans) match subledger totals within $0.02 tolerance |
Viewing Scan Results
Navigation: Insights tab > Audit > Scans
The scan history page shows: - KPI cards: Latest status, total scans, last scan date, checks passed count, findings (critical/warning/info) - Run Scan button: Triggers an on-demand scan - Scan history table: Date, type, status, checks, findings by severity, duration, content hash
Status display: - GREEN: Plain text "Passed" (no badge) - YELLOW: Badge "Warnings" - RED: Badge "Failed"
Each scan creates an immutable IntegritySnapshot with a SHA-256 content hash. Clicking a scan row shows the detail page with findings grouped by severity (CRITICAL > HIGH > MEDIUM > LOW > INFO) and delta comparison against the previous scan.
Bank fee and interest journal entries created during statement import are included in the next integrity scan — they are verified like any other journal entry because they were posted through JournalEngine with full enforcement.
How CommunityPay Enforces This
- Format auto-detection from file content signatures — user never selects format manually
- 8-strategy matching engine with priority ordering and confidence scoring (Exact/High/Medium/Low)
- Duplicate detection prevents matching a ledger record to multiple bank lines across imports
- Bank fee and interest JEs created via JournalEngine with full enforcement dispatcher guard chain
- BAI2 integrity verification: 6 checks including control totals, balance integrity, and transaction count
- Every IntegritySnapshot is immutable with SHA-256 content hash — scan results cannot be altered after creation