Reconciliation
Match imported bank transactions against your ledger with auto-matching and exception handling.
Overview
The Import & Sync page is the central hub for all external data ingestion — Plaid bank syncs, CSV uploads, and API imports — along with reconciliation of those records against your ledger. It combines connection management, import history, and the reconciliation workflow in a single view.
The reconciliation engine matches imported external records against your internal ledger data. It supports three types of records:
| Record Type | What It Is | Reconciles Against |
|---|---|---|
| Transactions | Bank debits/credits, trades, payments | Events and journal entries |
| Positions | Holdings snapshots at a point in time | Computed ledger balances per account |
| Balances | End-of-period account confirmations | Trial balance and account totals |
Import Sources
Records can be imported through several methods:
| Method | Description |
|---|---|
| Plaid | Automatic sync from connected bank accounts |
| CSV | Upload CSV files from any source |
| On-chain | Blockchain transaction scanning |
| Manual | User-entered records |
| API | External system integration |
Transaction Reconciliation
Import
Import transactions from your bank, broker, exchange, or blockchain wallet. Each transaction includes a date, description, amount, currency, and optional reference numbers.
Duplicate detection runs automatically during import — transactions with matching external IDs, transaction hashes, or identical date/amount/description combinations are skipped.
Automatic Classification
Before auto-matching, the system classifies each imported transaction into an event type. Classification uses a two-layer approach:
- Categorization patterns — user-defined rules that match by counterparty name (e.g. "JPMORGAN CHASE" →
loan_payment). These are checked first and take priority. Patterns can also specify a target account to override the default mapping. See Rules > Categorization for details. - Built-in heuristics — if no pattern matches, the system uses the transaction's account type (CREDIT_CARD, LOAN, DEPOSITORY), Plaid category/subcategory, and amount direction to infer the event type.
Auto-Matching
After import, run the auto-match engine to find corresponding ledger events. The engine scores potential matches using multiple signals:
| Signal | What It Checks |
|---|---|
| Amount | Exact match, close match (within 5%), or normalized match (handling tax/tip variations) |
| Date | Same date, within 3 days, or within 7 days |
| Counterparty | Exact name match or fuzzy match (handles variations like "AMZN*1A2B3C" matching "Amazon") |
| Reference | Invoice or check number matches |
| Historical patterns | Known counterparty-to-account mappings learned from previous matches |
Transactions scoring above the auto-match threshold (default: 90/100) are automatically matched. Lower-scoring matches are flagged for manual review.
Manual Matching
For unmatched transactions, you can:
- Match to an existing event — link the transaction to a ledger event
- Create a new event — generate a ledger event directly from the transaction, which flows through the posting engine
- Exclude — mark the transaction as not relevant (e.g. internal transfers)
The system learns from your manual matches — counterparty patterns are saved and applied to future auto-matching and auto-classification.
Status Lifecycle
Each transaction progresses through these statuses:
- Unmatched — no corresponding ledger event found
- Matched — linked to a ledger event (auto or manual)
- Confirmed — match verified and locked
- Excluded — marked as not relevant
You can unmatch a previously matched transaction to send it back to the unmatched queue.
Position Reconciliation
Import holdings snapshots from brokers, custodians, or blockchain wallets to verify that your ledger balances match external records.
The engine matches imported positions to ledger accounts by currency and name, then computes the variance between the imported quantity and the ledger balance as of the snapshot date.
Balance Reconciliation
Import end-of-period balance confirmations to verify that your ledger account totals match external statements.
The engine matches imported balances to ledger accounts by account code, name, or role mapping, then computes the variance between the reported balance and the computed ledger balance.
Import & Sync Hub
The Import & Sync page uses a tabbed layout:
Overview Tab
Displays real-time sync status and recent import activity:
- Connection cards — each connected source (Plaid, CSV, API) shows its status, last sync time, and a sync-now button. Active syncs display a live progress indicator powered by Pusher.
- Recent import batches — the latest batches with per-batch stats (total transactions, unmatched/matched/confirmed counts). Click a batch to drill down and see individual transactions.
- Dashboard banner — the main dashboard shows a sync status indicator with connection health and a quick link to Import & Sync.
Bulk Import Tab
Upload CSV files or manually enter records. Supports drag-and-drop with automatic column mapping.
History Tab
Full import batch history with status breakdowns, date ranges, and drill-down to individual transactions.
Real-Time Sync Updates
When a bank sync runs, the UI receives live updates via Pusher WebSocket events:
| Event | Description |
|---|---|
sync:started | Sync initiated for a connection |
sync:progress | Incremental count of transactions created and accounts synced |
sync:completed | Final stats: transactions created, duplicates skipped, quarantined, errors |
sync:failed | Error details when a sync fails |
Events are broadcast on the entity-{entityId} Pusher channel. The Import & Sync page subscribes automatically and updates connection cards and batch lists in real time.
Reconciliation Workflow
- Import — upload CSV or sync from a connected source
- Auto-match — run the matching engine to find correspondences
- Review — examine matched and unmatched items in the dashboard
- Resolve exceptions — handle unmatched items (match, create event, or exclude)
- Confirm — lock reconciled items
Use Confirm All to bulk-confirm all matched items in a batch.
API Reference
Reading Data
GET /api/reconciliation?entityId=...&type=transactions&status=UNMATCHED| Param | Description |
|---|---|
entityId | Required |
type | transactions (default), positions, balances, or lot_positions |
status | Filter by status (UNMATCHED, MATCHED, CONFIRMED, EXCLUDED) |
batchId | Filter by import batch |
summary | Set to true for aggregate counts only |
limit / offset | Pagination |
Transaction Actions
| Action | Description |
|---|---|
import | Import transaction records |
auto_match | Run auto-matching engine |
find_candidates | Get ranked match candidates for a transaction |
manual_match | Link a transaction to an event |
unmatch | Unlink a previously matched transaction |
confirm | Confirm and lock a matched transaction |
confirm_all | Bulk confirm all matched transactions |
exclude | Mark a transaction as not relevant |
create_event | Create a ledger event from an unmatched transaction |
Position Actions
import_positions, auto_match_positions, confirm_position, unmatch_position, exclude_position
Balance Actions
import_balances, auto_match_balances, confirm_balance, unmatch_balance, exclude_balance
Lot Position Actions
auto_match_lots — compares imported broker positions against the internal tax lot inventory on a per-asset basis. Returns quantity and cost basis variances.
You can also access lot reconciliation via GET /api/reconciliation?type=lot_positions&entityId=....
All write operations use POST /api/reconciliation with an action field.
Import Batches API
Query import batch history and drill down into per-batch transactions:
GET /api/import-batches?entityId=...&limit=30&offset=0Returns aggregated batch data grouped by importBatchId, including transaction counts by status (unmatched, matched, confirmed, excluded), date range, import method, and linked treasury account name.
To fetch individual transactions within a batch:
GET /api/import-batches?entityId=...&batchId=batch-uuidConnections API
Manage integration connections and view sync status:
GET /api/connections?entityId=...| Action | Description |
|---|---|
| (default) | List all connections for the entity |
action=summary | Lightweight sync overview: total, active, syncing, lastSyncAt, nextSyncAt, errorCount |
action=logs&connectionId=... | Sync log history for a connection |
action=health&connectionId=... | Connection health check |
action=providers | List available integration providers |
Write operations use POST /api/connections:
| Action | Description |
|---|---|
create | Create a new connection (provider, displayName, credentials, config, syncFrequency) |
sync | Trigger a manual sync for a connection |
update | Update connection settings |
delete | Remove a connection |