# Register your bank accounts and import a statement

> Register each real account once with its purpose and its opening balance as at a date, using only the last four digits. Then export the account's transactions from internet banking as a CSV and import it into that account. The import checks the file chains onto the account's last balance before writing anything, and refuses with the expected and actual figures if it does not. Import weekly, because the export window rolls and a skipped week is a hole the close will refuse over.

URL: https://biloh.com.au/docs/how-to/register-bank-accounts-and-import-a-statement
Category: How-to guides | Audience: operator | Updated: 2026-09-18

## Before you start

You need the last four digits of each account, and for each one an opening
balance and the date it was true. The cleanest anchor is the closing balance
on the last statement before you started using Biloh for money.

## Step 1: register each account

Say it, or fill the form on Finance, then Bank accounts, then "Register a
bank account":

> "Register my everyday account, transaction, ending 1234, opening balance
> $2,500.00 as at 1 August."

`create_bank_account` stores the name, institution, a masked identifier (the
last four digits, or `****1234`), the kind (transaction or savings), the
purpose (`operating`, `tax_set_aside`, `contractor_buffer`), and the opening
balance with its date. A full account number or BSB is refused with
`identifier_not_masked`; Biloh never holds one. Names must be unique within
the business.

Do the same for the tax set-aside and the contractor buffer. Their purposes
are what turn the [envelope targets](/docs/concepts/envelopes-tax-set-aside-and-contractor-buffer)
into a measured gap.

To correct an account, use `update_bank_account`. To retire one, set it
inactive with the same tool. Accounts are never deleted, and an archived
account's lines still count in completeness.

## Step 2: export the statement

In internet banking, export the account's transactions for the window since
your last import as a CSV. The expected shape is header-less, four columns:
date as `DD/MM/YYYY`, signed amount (credit positive, debit negative),
description, running balance. The running balance column is what makes the
[balance chain](/docs/concepts/the-balance-chain) possible; do not strip it.

## Step 3: import it into the right account

> "Import this file into the everyday account."

On screen: Finance, then Reconcile, then "Import bank CSV", choose the file,
pick the account under "Bank account for this statement", and "Import into
this account". Over MCP the agent calls `list_bank_accounts` to find the
account id and then `import_bank_csv` with the file contents and
`bank_account_id`.

Before a single row is written the import checks that the file's implied
opening balance chains onto the account: its current closing balance, its
declared opening balance on a first import, or a balance it has already
recorded if the window overlaps. Three outcomes:

- **It chains.** Every line lands. The response says how many were inserted
  and how many were already present. Re-importing an overlapping window adds
  zero duplicates.
- **It does not chain.** The whole import is refused with
  `wrong_account_or_gap`, naming the balance the account expected and the
  balance the file starts from, and zero rows are written. Either this is the
  set-aside's statement in the everyday account, or a window is missing.
  Export the right days and import again.
- **The gap is real and unrecoverable.** Import anyway with
  `override_chain_gap: true` and an `override_reason`. On screen that is the
  "Reason for importing over the statement gap" box and "Import anyway with
  this reason". An empty reason is refused. The override is audit-logged and
  the completeness read still reports the break.

## Step 4: check the feed's health

> "Where has each account's feed got to?"

`list_bank_accounts` returns, per account, the chained current balance, the
coverage span, the line count, whether the chain is intact, and a
`feed_health` verdict of fresh, stale or never imported measured in your
timezone against `finance.bankfeed.stale_after_days`. A stale account is named
in the attention digest so it is not forgotten.

## Import weekly

The internet-banking export is a rolling window of recent transactions. Skip
too long and the oldest lines roll off before you export them, and that
becomes a gap the close will refuse over. Weekly is the cadence the platform
is designed around; the bookkeeper desk's worklist starts every session with
the feed's freshness.

## Starting mid-history: the cutover

If the account has years of history before Biloh, set
`finance.bankfeed.cutover_date` to the day you started invoicing here and run
`ignore_pre_cutover_transactions` once. Every unmatched line dated before the
cutover is marked as pre-Biloh history in one call, so the reconcile worklist
opens on deposits Biloh can actually settle. The sweep will not touch lines
on or after `finance.close.pre_cutover_boundary`. See
[triage invoices after a billing cutover](/docs/how-to/triage-invoices-after-a-billing-cutover)
for the invoice side.

## Next

- [Reconcile money in](/docs/how-to/reconcile-money-in)
- [Reconcile money out](/docs/how-to/reconcile-money-out)
