Skip to main content

Bank Reconciliation

Match external bank transactions to ledger-backed accounting events.

Bank reconciliation in SpeyBooks is a controlled alignment process between:

  • External bank statements — what the bank says happened
  • Internal ledger events — what your books say happened

SpeyBooks never mutates the ledger to "make things match". Reconciliation only links evidence to existing accounting records or creates new, explicit ones.

Conceptual model

Bank reconciliation operates on a separate data stream:

Bank statements (external, mutable source)

Imported bank transactions (read-only)

Matching / categorisation

Ledger transactions (double-entry, immutable)

Key properties

  • Imported bank transactions are not ledger entries
  • Ledger transactions remain append-only
  • Reconciliation is explicit and auditable

Supported import methods

SpeyBooks currently supports:

  • Manual entry
  • CSV import from your bank
  • Open Banking (coming soon)

All methods normalise into the same internal bank transaction format.


Import bank transactions

CSV format

Prepare a CSV file with the following columns:

date,description,amount,reference
2026-01-15,BACS Payment - Acme Corp,1200.00,INV-0001
2026-01-16,Direct Debit - AWS,-45.00,
2026-01-17,Card Payment - Office Supplies,-89.50,

Rules

FieldFormat
amountMajor units (GBP) in CSV, converted to minor units on import
PositiveMoney into the bank account
NegativeMoney out of the bank account

Upload via API

curl -X POST https://api.speybooks.com/v1/bank/import \
-H "Authorization: Bearer sk_live_your_api_key" \
-H "Content-Type: multipart/form-data" \
-F "file=@bank-statement.csv" \
-F "accountId=acc_1200"

Response

{
"success": true,
"data": {
"imported": 3,
"duplicatesSkipped": 0,
"transactions": [
{
"id": "btx_001",
"date": "2026-01-15",
"description": "BACS Payment - Acme Corp",
"amount": 120000,
"status": "unmatched"
}
]
}
}

Import guarantees

  • Duplicate detection is deterministic (date + amount + reference)
  • Imported bank transactions are immutable
  • Re-importing the same file is safe and idempotent

Bank transaction lifecycle

Each imported bank transaction progresses through a strict state machine:

StatusMeaning
unmatchedNo accounting record linked
matchedLinked to an invoice, payment, or expense
reconciledConfirmed and locked

Once a transaction reaches reconciled, it cannot be modified or re-matched.


Automatic matching

SpeyBooks attempts non-destructive matching using:

  • Explicit references (e.g., INV-0001)
  • Exact amount matches
  • Contact names found in descriptions
  • Date proximity

Automatic matching never creates ledger entries. It only proposes links to existing records.


Manual matching

If a bank transaction is unmatched, you may explicitly link it to an existing accounting record.

curl -X POST https://api.speybooks.com/v1/bank/transactions/btx_001/match \
-H "Authorization: Bearer sk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"invoiceId": "inv_42"
}'

Response

{
"success": true,
"data": {
"id": "btx_001",
"status": "matched",
"matchedTo": {
"type": "invoice",
"id": "inv_42"
}
}
}

Effects

  • The bank transaction is linked to the invoice payment
  • No ledger data is altered
  • The transaction moves to matched

Create a new accounting transaction

If a bank transaction does not correspond to an existing record, you may categorise it.

curl -X POST https://api.speybooks.com/v1/bank/transactions/btx_002/categorise \
-H "Authorization: Bearer sk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"accountId": "acc_5200",
"vatRate": "standard",
"description": "AWS monthly hosting"
}'

Response

{
"success": true,
"data": {
"id": "btx_002",
"status": "matched",
"transaction": {
"id": "txn_891",
"description": "AWS monthly hosting",
"accountId": "acc_5200",
"amount": 4500,
"vatRate": "standard"
}
}
}

Effects

  • Creates a new double-entry ledger transaction
  • Links it to the bank transaction
  • Preserves full audit traceability
  • Transitions the bank transaction to matched

Reconciliation and locking

Once you have reviewed matched transactions, you may reconcile them.

Reconciliation means:

  • The bank transaction is confirmed as correct
  • The linkage to ledger data is locked
  • The transaction becomes read-only

This step prevents accidental drift between bank statements and the ledger.


Best practices

PracticeRationale
Reconcile frequentlyWeekly reconciliation reduces ambiguity and errors
Use strong referencesInclude invoice IDs in payment references wherever possible
Investigate unmatchedPersistent unmatched entries indicate missing or misclassified events
Lock completed periodsReconcile and lock each month to preserve audit integrity

Key invariants

  • Bank imports never mutate the ledger
  • Ledger entries are never inferred from bank data
  • All reconciliation actions are explicit
  • Every reconciled balance is reproducible

Error codes

CodeHTTPDescription
validation_error400Invalid CSV format or missing required columns
invalid_id400Malformed account or transaction ID
not_found404Bank transaction or invoice does not exist
conflict409Transaction already matched or reconciled
unprocessable_entity422Cannot modify reconciled transaction

Amount format

Bank transaction amounts are stored in minor units (pence for GBP):

120000 = £1,200.00
4500 = £45.00

CSV imports use major units; SpeyBooks converts on import.