← Selected work

Finance automation · MVP

Bank Statement Automation

A controlled pipeline that turns PDF bank statements into reviewed, de-duplicated entries in Finmap.

  • Python
  • Streamlit
  • SQLite
  • Finmap API
2026

One line at a time

A bank PDF is not data yet

A statement line is a date, an amount and a paragraph the bank wrote for itself. Somebody used to turn that into an entry by hand, every month. Pick a line and see what the pipeline does instead.

The statement, as it was exported

kredo-2026-03.pdf01–31 March 2026 · Main account

Pick a line

What Finmap receives

One incoming line, two operations

1 line → 2 operations
incomeNet income
Account
Main · UA…3099
Amount
35 000.00 UAH
Category
Legal services
Counterparty
Meridian Foods
External id
…7c4a1f:main
incomeПДВ
Account
Main · UA…3099
Amount
7 000.00 UAH
Category
ПДВ
Project
ПДВ
External id
…7c4a1f:pdv
How it decided
  1. The VAT is a fixed sixth of the gross, so the two amounts never round apart.
  2. It splits on the account, not on the wording — a line that forgets to mention ПДВ is split anyway.

A parser per bank format: Kredo, Raiffeisen, the operational export and the Mono payroll sheet, with a generic fallback behind them. Amounts, names and account tails here are stand-ins.

Why it is safe to press twice

Import the same statement again. Nothing doubles

A period extended by two days, a run from a second machine, a file dragged in twice — by hand every one of those doubles the month, and somebody finds it weeks later. Here nothing doubles, because every operation carries an identity of its own.

The file being importedkredo-2026-03.pdf32 lines · re-exported on 30 March with two extra days on the end16In Finmapoperations so far

Import it again

  1. 01First import28 March, the statement as it stood
    Lines read
    16
    Already there
    0
    Written
    16

    Sixteen operations written.

  2. 02Re-exported file30 March, same period plus two days
    Lines read
    32
    Already there
    16
    Written
    16

    The overlap is recognised. Only the new days are written.

  3. 03The very same fileDragged in again, on purpose
    Lines read
    32
    Already there
    32
    Written
    0

    Read in full, written nowhere.

Three places a repeat is caught
  1. 01Inside the batchTwo exports in one folder overlap. The second copy is marked before anything is sent.
  2. 02Against what was postedEvery published operation keeps its identity locally, with the date it went — so a re-exported period is caught and dated.
  3. 03At the far endIf both miss, Finmap refuses the identity itself — and that refusal is read as success, not an error.
What the identity is made of

Ten things, hashed. Same line, same identity, forever.

  • 01bank
  • 02account IBAN
  • 03booking time
  • 04amount
  • 05currency
  • 06direction
  • 07counterparty IBAN
  • 08document number
  • 09purpose
  • 10recipe version

IBANs and wording are normalised first, so spacing and case cannot make one line look like two.

Every run also checks the statement’s own arithmetic — opening balance plus everything that moved, against the closing balance — and a difference is a warning on the draft rather than a block.

What it changed

The same statement, typed and imported

The bank sends the same PDF either way. What changes is how many decisions a person makes by hand, and what happens when the file arrives twice.

The same bank statement, entered by hand and imported through the pipeline
What changesBy handOne line at a time, into FinmapThrough the pipelineA draft first, then published
Getting a statement inBy handEvery line read off a PDF and retyped, for each account and each monthThrough the pipelineThe PDF is parsed and every line arrives as a draft operation
Deciding what a line isBy handA category chosen from memory, and differently depending on who is doing itThrough the pipelineKeyword rules, tax detection and the payment plan decide — and each says why
Money moved between own accountsBy handEntered twice, as an expense and as an income, and the month looks busier than it wasThrough the pipelineRecognised as a transfer from the account registry, so it never reaches profit
VAT inside a client paymentBy handSplit by hand at the end of the quarter, or not split at allThrough the pipelineOne incoming line becomes net income and a ПДВ line, five sixths and one sixth
The same period imported twiceBy handDoubled, and found weeks later by whoever notices the balanceThrough the pipelineCaught at three levels before anything is written, with the date of the original
Checking nothing was lostBy handThe closing balance is compared by hand, when there is timeThrough the pipelineOpening plus movements is checked against closing on every run
A line nobody has a rule forBy handGuessed at, or parked in a note that outlives the monthThrough the pipelineLands in a fallback category with an unmapped tag, waiting for a person
If your statements still get typed in line by line, let’s talk.