Skip to content

Banking

The banking module follows a feeds model: import a statement, then either match its lines to entities already on the books or categorize them into new bank transactions — with rules to automate the routine cases and reconciliation to prove the book against the bank.

  • Bank accounts — with optional IFSC, SWIFT/BIC and IBAN identifiers (validated, IBAN by mod-97 checksum), an opening balance, and a linked GL account through which the account posts.
  • Bank transactions — the bank book. Each has a type in the deposit family (into the account), the withdrawal family (out), or TRANSFER between two accounts, and a status of UNCATEGORIZED, CATEGORIZED, MATCHED or EXCLUDED. Only categorized and matched transactions count toward the derived balance.
  • Statement lines — rows imported from a bank file, signed as the bank reports them (credit positive, debit negative).
  • Bank rules — a condition plus an action, run over unmatched statement lines in priority order. See Bank rules.
  • Reconciliations — a frozen statement-date snapshot of the cleared balance against the statement’s closing balance.
  • Imports OFX and QIF files into a common line shape. OFX dates, signed amounts and the bank’s own transaction id (FITID) are read; QIF, which has no stable id, is fingerprinted per line.
  • Two ways in. Upload the .ofx/.qif export and the server parses it, or paste rows (date,description,reference,payee,amount) into the manual dialog, which checks every row in the browser and sends 1–1000 signed, non-zero lines through a JSON import — useful for an export the parsers do not cover.
  • De-duplication is built in: a re-import lands on the same (account, external id) and is skipped rather than double-counted, using the FITID where present and a content fingerprint otherwise. The manual import uses the same fingerprint.
  • Ambiguous or invalid dates are rejected as parse errors that name the offending value, not swallowed.
  • Running rules on import is opt-in and off by default, so an import is a pure ingest that never silently posts to the ledger. Both import calls accept an apply_rules flag. With it set, the tenant’s bank rules run inside the same transaction against every unmatched line on that account — not only the ones the import just added — and the response carries the per-rule result. The web app leaves the flag off and gives you an explicit Apply rules button instead.
  • An imported line can be matched to an existing book entity, or categorized into a new bank transaction against a target GL account.
  • Categorizing is one step, not two: the new transaction is born already matched to its line, so both sides land on MATCHED together. The direction has to agree — a credit line can only become a deposit-side type and a debit line a withdrawal-side type, otherwise the request is refused. A transfer has no destination field on the categorize call; record it from the account’s Transactions tab, or let a transfer rule create it — those rules are API-created only today.
  • Categorized transactions post to the ledger: a deposit debits the bank GL and credits the target account (withdrawals the reverse; a transfer moves between two bank GLs). Optional bank charges add a balanced expense pair to the same journal. Transactions with no GL target still move the derived bank balance without posting.

A rule is a condition and an action. Rules do not run on a schedule — they run when you apply them to an account’s unmatched lines, either from the Apply rules button or by asking an import to apply them.

  • One text predicate on description, payee or reference number, with contains, equals or starts with. Matching is case-insensitive.
  • An optional amount window — a minimum and/or maximum on the line’s absolute amount, so one rule can cover both signs.
  • A direction gate: deposits (credit lines), withdrawals (debit lines) or both.
  • A scope: one bank account, or every account when the account is left empty.
Action What it does when it fires Target it needs
CATEGORIZE_DEPOSIT Turns a credit line into a deposit bank transaction GL account
CATEGORIZE_EXPENSE Turns a debit line into a withdrawal bank transaction GL account
CATEGORIZE_TRANSFER Creates the transfer between the statement’s account and the destination — a debit line moves money out, a credit line in Destination bank account
MATCH_CUSTOMER_PAYMENT Matches a credit line to a completed customer payment of the same amount — (contact optional)
MATCH_VENDOR_PAYMENT Matches a debit line to a completed vendor payment of the same amount — (contact optional)

A rule can also carry a tax code and a contact. Both are stamped onto the transaction a deposit or expense rule creates; for the two match actions the contact narrows the search instead. Matching is deliberately conservative — it fires only when exactly one completed payment of that amount (and contact, if named) exists. Zero candidates or several is simply no match, never an error.

Transfer rules have to be created through the API: the Rules screen has no destination-account field, and the API will not accept a CATEGORIZE_TRANSFER rule without one.

Every rule has a priority between 1 and 10,000, defaulting to 100. For each unmatched line the rules are tried lowest number first — ties broken by the order they were created — and the first one that applies takes the line; nothing after it is tried. So give your specific rules low numbers and leave the catch-alls high.

A rule whose condition matches but which cannot act does not consume the line; evaluation simply moves on to the next rule. That happens when a deposit rule meets a debit line (or an expense rule a credit line), when a payment-match rule finds no single candidate, and when a transfer rule’s destination is missing, is the same account, or either account has no linked GL account. Transfer rules blocked that way are counted as skips in the run result, so a misconfigured rule shows up rather than failing silently.

Applying rules to an account walks its unmatched lines with the active rules scoped to that account plus the all-accounts ones, and reports how many lines it processed, how many it changed, and the hit and skip counts per rule. Deleting a rule stops it applying to future runs; lines it already categorized or matched are untouched.

You manage rules from the bank-account workspace’s Rules tab, which lists the account’s effective set in priority order — criteria in plain language, scope, action, targets and whether it is active — with a dialog to create or edit one. All-accounts rules apply here too, so they are listed alongside the account’s own.

Nothing in the bank book is deleted to get it out of the way. Both sides of the feed have a parking status, and taking a posted transaction out of the way reverses its ledger effect rather than erasing it.

Move Status change Effect
Exclude a bank transaction CATEGORIZED → EXCLUDED Drops out of the derived bank balance, and any journal it posted is reversed by a counter-entry and unlinked
Restore a bank transaction EXCLUDED → CATEGORIZED Re-posts a fresh journal when the transaction is a transfer or has a GL target
Exclude a statement line UNMATCHED → EXCLUDED Parks the line out of reconciliation; it cannot be matched until restored
Restore a statement line EXCLUDED → UNMATCHED Back in play for matching, categorizing and rules
Unmatch a statement line MATCHED → UNMATCHED Removes every match on the line

A transaction that is matched to a statement line cannot be excluded — unmatch the line first. Unmatching returns the transaction to CATEGORIZED unless another line still matches it, and un-clears the bridged row of a matched payment. A line that belongs to a completed reconciliation cannot be unmatched at all: reopen that reconciliation first. That is what stops a signed-off balance being quietly changed.

Customer payments, vendor payments and expenses post their cash leg straight to the bank’s GL account. So they can still be reconciled, each is mirrored into the bank book as a non-posting bank transaction carrying the net amount the statement will show. Matching a statement line to the payment clears the mirrored row; voiding the payment removes it (blocked while it is matched to a confirmed statement line).

  • The cleared balance is the opening balance plus the signed deltas of all matched transactions up to the statement date; the difference against the statement’s closing balance is zero (within rounding) when reconciled.
  • Categorized-but-unmatched items dated in the period are listed as outstanding — the uncleared cheques and deposits in transit that explain the gap.
  • Completing a reconciliation freezes the computed state; it can be reopened.

The Android app carries the two banking jobs that happen away from a desk. Bank accounts and their transactions are read-only there; matching, categorizing and bank rules stay on the web.

  • Import a statement — pick the .ofx/.qif export with the system file picker. The format is pre-selected from the file extension, and the result reports how many lines were new versus how many were already imported and skipped.
  • Reconcile — the account’s reconciliations, plus a worksheet that lays the arithmetic out on a phone: opening balance plus cleared movement against the statement’s closing balance, the difference called out, outstanding items underneath. A draft can be completed or discarded, and a completed one reopened.
  • General ledger — categorized bank transactions post here through the shared seam.
  • Receivables & payables — payments and refunds are the documents mirrored into the bank book for matching.
  • Reports — the cash-and-bank dashboard figure and the cash-flow statement use the same balance formula.