# How to Use the Match and Reconcile Feature for ERPNext Bank Reconciliation

> Streamline your ERPNext bank reconciliation process. Learn how to use the Match and Reconcile feature to automate matching bank statements with vouchers and payment entries, ensuring accurate financial records.

- Repository: [Frappe/erpnext](https://github.com/frappe/erpnext)
- Tags: how-to-guide
- Published: 2026-05-20

---

**The Match and Reconcile feature in ERPNext automates bank reconciliation by matching imported bank statement lines against existing vouchers or new payment entries, updating the `Bank Transaction` document status to "Reconciled" upon confirmation.**

The ERPNext Match and Reconcile functionality provides a centralized interface within the Frappe framework for aligning bank transactions with accounting vouchers. This feature combines a React-based split-pane UI with Python server-side logic to handle everything from transaction filtering to ledger updates.

## Understanding the Match and Reconcile Architecture

The reconciliation workflow operates through a coordinated system of client-side state management and server-side document processing. The interface uses **Jotai atoms** to track selection states. When you interact with the `BankPicker` component in [`BankReconciliation.tsx`](https://github.com/frappe/erpnext/blob/main/BankReconciliation.tsx) (lines 44-48), it updates the `selectedBankAccountAtom`, which triggers the `useGetUnreconciledTransactions` hook to fetch data via the Frappe RPC endpoint `erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_bank_transactions`.

## Step-by-Step Bank Reconciliation Process

### 1. Select a Bank Account and Load Transactions

Begin by selecting a bank account from the dropdown picker. The system immediately queries the server using `get_bank_transactions` to pull all unreconciled items for that account. The `UnreconciledTransactions` component (starting at line 73 of [`MatchAndReconcile.tsx`](https://github.com/frappe/erpnext/blob/main/MatchAndReconcile.tsx)) renders these results in the left pane, invoking `useGetUnreconciledTransactions` (line 84) which ultimately calls `erpnext.accounts.doctype.bank_transaction.bank_transaction.get_unreconciled_transactions` on the backend.

### 2. Filter and Search Transaction Lists

Narrow down large transaction lists using the search interface defined around lines 45-110 of [`MatchAndReconcile.tsx`](https://github.com/frappe/erpnext/blob/main/MatchAndReconcile.tsx). The implementation uses **Fuse.js** (lines 97-101) for fuzzy searching against transaction descriptions and references, while the `getSearchResults` helper (imported from `utils`) applies client-side filtering. Filter states are stored in dedicated atoms: `bankRecTransactionTypeFilter` for debit/credit filtering and `bankRecAmountFilter` for amount ranges.

### 3. Select Transactions for Matching

Click any row in the unreconciled list to select it. The click handler resides in `UnreconciledTransactionItem` (lines 84-92) and updates the `bankRecSelectedTransactionAtom` (line 76). For bulk operations, **Shift-click** enables multi-selection across the transaction list, storing multiple selections in the atom keyed by bank account name.

### 4. View Matching Vouchers

Once you select a transaction, the right pane populated by `VouchersForTransaction` (starting at line 220) displays potential matches. The component calls `useGetVouchersForTransaction`, which executes the server method `get_linked_payments`. This function runs `check_matching` (around line 1110 in [`bank_reconciliation_tool.py`](https://github.com/frappe/erpnext/blob/main/bank_reconciliation_tool.py)), which builds ranked queries using specific builders like `get_pe_matching_query` (line 1319) for Payment Entries, `get_je_matching_query` for Journal Entries, and `get_bt_matching_query` for opposite bank transactions. The results render via `VoucherItem` (lines 71-82), with the highest-ranked matches displaying a green "Suggested" badge.

### 5. Execute Reconciliation or Create Entries

You have two resolution paths:

- **Reconcile against existing voucher**: Click the **Reconcile** button on any listed voucher. This invokes `useReconcileTransaction` (line 99), which POSTs to the `reconcile_vouchers` method (line 610 in [`bank_reconciliation_tool.py`](https://github.com/frappe/erpnext/blob/main/bank_reconciliation_tool.py)). The server loads the `Bank Transaction` document, calls `add_payment_entries` (lines 65-72) to link the voucher, runs validation and allocation logic, and sets the status to "Reconciled".

- **Create new voucher**: If no match exists, use the action buttons in `OptionsForSingleTransaction` or `OptionsForMultipleTransactions` (lines 456-527) to create a **Payment Entry**, **Bank Entry**, or **Internal Transfer**. These call APIs like `create_payment_entry_bts` (line 308), which builds and submits the document before automatically calling `reconcile_vouchers` with `is_new_voucher=True`.

### 6. Handle Date Range Gaps

If unreconciled transactions exist before your selected date range, the `OlderUnreconciledTransactionsBanner` (lines 997-1045) appears. This component queries `get_older_unreconciled_transactions` (defined at line 889 in [`bank_reconciliation_tool.py`](https://github.com/frappe/erpnext/blob/main/bank_reconciliation_tool.py)) to count items before the `from_date` and retrieve the oldest date, allowing you to expand the filter range to include historical items.

## Core Server-Side Implementation

The reconciliation engine resides in [`erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py`](https://github.com/frappe/erpnext/blob/main/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py).

### Fetching Unreconciled Bank Transactions

```python

# erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py

@frappe.whitelist()
def get_bank_transactions(
    bank_account: str,
    from_date: str | date | None = None,
    to_date: str | date | None = None,
    all_transactions: bool = False,
):
    # Filters and retrieves Bank Transaction documents

    # Implementation at lines 49-88

```

### Matching Logic and Query Builders

```python

# erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py

def get_linked_payments(
    bank_transaction_name: str,
    document_types: str | list[str] | None = None,
):
    transaction = frappe.get_doc("Bank Transaction", bank_transaction_name)
    # Retrieves GL account and company, then executes matching

    matching = check_matching(gl_account, company, transaction, document_types)
    return subtract_allocations(gl_account, matching)

```

The `check_matching` function orchestrates ranked queries for each document type, utilizing specific query builders such as `get_pe_matching_query` (line 1319) for Payment Entries.

### Reconciliation API

```python

# erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py

@frappe.whitelist()
def reconcile_vouchers(
    bank_transaction_name: str | int,
    vouchers: str,
    is_new_voucher: bool = False
):
    vouchers = json.loads(vouchers)
    transaction = frappe.get_doc("Bank Transaction", bank_transaction_name)
    transaction.add_payment_entries(vouchers, is_new_voucher)
    transaction.validate_duplicate_references()
    transaction.allocate_payment_entries()
    transaction.update_allocated_amount()
    transaction.set_status()
    transaction.save()
    return transaction  # Status now "Reconciled"

```

### Creating Payment Entries

```python

# erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py

def create_payment_entry_bts(
    bank_transaction_name: str,
    reference_number: str | None = None,
    # ... additional parameters

):
    # Constructs Payment Entry document (lines 308-374)

    pe.insert()
    pe.submit()
    # Links and reconciles automatically

    return reconcile_vouchers(
        bank_transaction_name,
        json.dumps([{"payment_entry": pe.name}]),
        is_new_voucher=True
    )

```

## Summary

- The **Match and Reconcile** interface in ERPNext provides a split-pane workflow for matching bank transactions to vouchers.
- Selection logic utilizes **Jotai atoms** (`selectedBankAccountAtom`, `bankRecSelectedTransactionAtom`) to manage UI state.
- Server-side logic in [`bank_reconciliation_tool.py`](https://github.com/frappe/erpnext/blob/main/bank_reconciliation_tool.py) handles transaction retrieval, fuzzy matching via `check_matching`, and final reconciliation through `reconcile_vouchers`.
- The system supports both matching against existing documents and creating new Payment Entries, Journal Entries, or Bank Entries on the fly.
- Date range management includes warnings for older unreconciled items via `get_older_unreconciled_transactions`.

## Frequently Asked Questions

### What document types does the Match and Reconcile feature support?

According to the ERPNext source code, the matching engine queries **Payment Entry**, **Journal Entry**, **Sales Invoice**, **Purchase Invoice**, and opposite **Bank Transaction** documents. The `check_matching` function in [`bank_reconciliation_tool.py`](https://github.com/frappe/erpnext/blob/main/bank_reconciliation_tool.py) builds specific SQL queries for each type, such as `get_pe_matching_query` for payments and `get_je_matching_query` for journal entries.

### How does ERPNext determine which vouchers match a bank transaction?

The system retrieves the bank account's GL account and company, then passes these to `check_matching` (around line 1110). This function executes ranked queries comparing amounts, dates, and references. Results are scored and returned to the UI, where the top match receives a "Suggested" indicator.

### Can I reconcile multiple bank transactions simultaneously?

Yes. The UI supports **Shift-click** multi-selection in the `UnreconciledTransactionItem` component (lines 84-92), storing multiple selections in `bankRecSelectedTransactionAtom`. When multiple transactions are selected, the `OptionsForMultipleTransactions` component (lines 456-527) provides actions to create consolidated entries or reconcile against matching vouchers.

### What happens to the Bank Transaction document after reconciliation?

When you confirm reconciliation, the `reconcile_vouchers` method (line 610) loads the `Bank Transaction` document, invokes `add_payment_entries` (lines 65-72) to link the voucher allocations, validates for duplicates, updates the allocated amount, and calls `set_status()`. The document status changes to **"Reconciled"**, the unallocated amount drops to zero, and the ledger reflects the matched entries.