LedgerLou Docs is optimized for desktop.

Please open this page on a device with a wider screen.

LedgerLou Bank

LedgerLou Bank

The Bank module connects raw account movements with the general ledger. Bank statements are imported, matched against suggestions, and systematically reconciled via REST or agents.

API Reference
CSV / CAMT importMulti-format parser for all common bank-statement formats
Matching suggestionsSuggestions based on amount, date, and reference text
Manual reconciliationAssign transactions individually or create a new posting
Batch and group matching1
, 1
, and n
matches with explicit clearing lines for residual differences
GoBD-compliantUnmatch as a counter-posting, no silent overwriting
API & MCPREST complete, MCP available for the core flow and being extended

Workflow

1
Import a bank statementCSV, CAMT.053, or XML via dashboard upload or POST /v1/bank-accounts/
/upload
. Duplicates are automatically skipped based on a content hash.
2
Review open transactionsAll unreconciled transactions are immediately visible via API or agent. Status unmatched shows where action is still required.
3
Apply matching suggestionsGET /v1/bank-transactions/suggestions returns prioritized suggestions based on amount, date, and reference text. Confirmation happens via REST or via an agent with write clearance.
4
Assign remaining cases manuallyTransactions without a suggestion are assigned via REST to an existing posting, reconciled against open items via allocations plus clearing lines, or processed with a supplementary posting.
5
Check reconciliation statusGET /v1/bank-accounts/
/reconciliation
shows open vs. reconciled transactions and the account’s current posting status.

Access methods

Dashboard (UI)In the MVP used for bank-account setup, statement import, and reconciliation work.
REST APIImport bank statements automatically and drive full reconciliation via scripts or backend workflows.
MCPMCP agents can already read, import, and reconcile the core flow. Extended parity with the REST API is currently being built out.

Foreign-currency reconciliation

LedgerLou continues to keep the general ledger in EUR. For open items in a foreign currency, the system therefore always stores two levels:

  • Document currency: e.g. 41.63 USD
  • EUR posting value at initial posting: e.g. 38.27 EUR

During bank reconciliation:

  • Matching suggestions for foreign-currency invoices compare the bank movement with the EUR posting value, not with the raw foreign-currency figure.
  • The open item is reduced or closed in document currency during reconciliation.
  • The difference between the actual bank inflow/outflow and the cleared EUR posting value is booked as realized FX gain/loss.
  • The REST API offers an explicit FX settlement with document amount, EUR clearing, and FX effect.

Group reconciliation and residual differences

In addition to the existing 1:1 assignment, LedgerLou now supports a raw match-group flow for open items: one or more bank transactions against one or more OIs, optionally supplemented by explicit clearing lines.

  • Endpoint: POST /v1/bank-match-groups
  • Goal: consolidate open items in a single Settlement-Intent, including 1:1 cases in the dashboard
  • All selected bank transactions must originate from the same bank account and have the same direction.
  • The group may be cleared via three building blocks: allocations to OIs, automatic FX gain/loss posting, and manual clearing lines.
  • The result is a single settlement posting in the general ledger; all associated bank transactions are set to the same intent_id.
  • POST /v1/bank-match-groups/:id/unmatch fully reverses this group posting and reopens all linked bank transactions.

For foreign-currency open items, each allocation is still reconciled against the EUR posting value. The difference between the bank amount and the EUR clearing flows automatically via 4840/6880. Other residual differences such as bank fees, cash discount, write-offs, or manual counter-postings are captured as explicit clearing lines with a freely chosen account and debit/credit side.

Duplicate detection

When importing a bank statement, LedgerLou checks each transaction in three stages before it is written to the database.

Stage 1 — Bank reference (highest priority)

If the transaction contains a bank_reference (e.g. an order or transaction ID from the bank), the system first searches for a row with an identical normalized bank reference and the same amount. Hit → duplicate, row is skipped.

Stage 2 — Content fingerprint

Candidates with the same amount and a matching date (posting or value date ±0) are checked:

  • IBAN of the counterparty + reference text match → duplicate
  • Name of the counterparty + reference text match → duplicate

All fields are normalized before comparison: Unicode composition resolved, umlauts simplified (ü → u), special characters replaced with spaces, lowercased. This way, e.g. "Müller & Söhne" and "Muller und Sohne" are recognized as identical.

Stage 3 — Content hash (database constraint)

In parallel, the parser computes a SHA-256 hash over the fields:

tenant_id | bank_account_id | tx_date | amount | counterparty_name | reference

The hash is enforced via UNIQUE(tenant_id, content_hash). If no hit is found in stages 1 and 2, this constraint prevents a duplicate insert at the database level (ON CONFLICT DO NOTHING).

API response on upload

POST /v1/bank-accounts/:id/upload always returns HTTP 201 — regardless of whether duplicates were included. The response body contains a detailed breakdown:

{
  "batch_id": "550e8400-e29b-41d4-a716-446655440000",
  "total_rows": 50,
  "imported": 47,
  "skipped_duplicates": 3,
  "errors": []
}
FieldMeaning
batch_idUUID of this import run
total_rowsNumber of rows processed
importedTransactions actually saved as new
skipped_duplicatesDetected and silently skipped duplicates
errorsParse or validation errors per row

Duplicates are never treated as errors — they only increase skipped_duplicates. Re-uploading the same bank statement is therefore always safe.

Scopes

bank:readbank:write