Skip to content
Nuits ReceiptsDocs
HomeSearch the docs, Ctrl KGitHubDark mode

Bank CSV import

Mapping fields, accepted formats, built-in layouts, duplicate rules and limits of the bank CSV import.

Updated

The import reads an XLSX, CSV or PDF statement of booked payments. There are presets for some layouts, other layouts are read automatically, and a column mapper remains as a last resort. It has been tested with Holvi exports so far. A mapping says which column holds which value. A layout the app works out, or that you set in the column editor, is saved on a successful import and used again for files with the same column names.

Flow

Step Page Request Writes
Import Import a bank statement (/import), one file field and Import statement POST /import R2 original, D1 import and bank rows
Which account (only when unclear) The same page, asking Which account is this? POST /import with account As above
Column editor (only when needed) /imports/csv POST /imports/csv/preview (button Check again), then POST /imports/csv/confirm (button Import N payments) Nothing until the confirm
Import anyway /import/anyway POST /import/anyway Extra payments, as a second import of the same file

The account is, first hit: the one chosen on the question, the only account, the account whose bank the layout names, a new account named for that bank when there is none, else the question. The layout is, first hit: a layout saved for these column names, the built-in layout for them, the model’s proposal when it reads the whole file, else the column editor. The editor also opens when rows have errors, the stated totals do not add up, or the delimiter or a slash date order is ambiguous. A file that is not UTF-8 is read as Windows-1252.

In the editor, the preview reads the whole file and shows up to 50 rows and up to 100 row problems. Any row problem blocks the import. A preview is valid for 30 minutes and is signed. After import the browser goes to Bank for the month of the first row, where the banner offers Undo for the whole import.

Column editor fields

The editor shows these with the file it was given.

Label Field Values
Bank statement (XLSX, CSV or PDF) file .xlsx, .csv, .pdf or .txt file
Which account is this? account An existing account
Import into account_action existing: the account chosen here; new: a new account
Account name account_label New account only
Bank bank_name New account only
Currency account_currency New account only. One of the ten supported currencies.
Text encoding encoding utf-8, utf-16le, utf-16be or windows-1252, shown as those values. The form also accepts auto, which the one-step import uses: UTF-8 or the file’s BOM, else Windows-1252.

A new account is created only when the import is confirmed. The editor’s Text encoding sits under The file.

Mapping fields

Shown under The columns look wrong? Adjust how we read the file. Column numbers in the app start at 1; row numbers for Which row has the column names? start at 0.

The file

Label Mapping key Values
Layout Choose layout, Custom mapping, or a saved or built-in layout that matches the column names
Text encoding encoding utf-8, utf-16le, utf-16be, windows-1252
Column separator delimiter Comma, Semicolon, Tab, Pipe
Which row has the column names? headerRecord 0 to 100. Rows above it are left out.
Rows to skip at the end trailingRecords 0 to 100

Dates

Label Mapping key Values
Date column date.column Required
Date format date.format ISO (YYYY-MM-DD), DD.MM.YYYY, DD/MM/YYYY, MM/DD/YYYY, ISO_OR_DOTTED (either YYYY-MM-DD or DD.MM.YYYY per row), D MMM YYYY (31 May 2026, 1 Sept 2026: English month names, short or full)
Dates include a time date.time No (none), Sometimes (optional)

With Sometimes, a date may be followed by T or a space and HH:MM, optional seconds and fractions, and an optional Z or +HH:MM offset. The printed calendar day is kept. A date format with slashes needs the tick The day and month order above is right for dates written with slashes.

Amounts

Label Mapping key Values
Decimal mark number.decimal ., ,, dot-or-comma
Thousands separator number.grouping none, ., ,, space, '
How amounts are shown amount.kind One amount column (signed), Separate money out and money in columns (split), An amount column plus an in or out column (direction)
Amount column amount.column or amount.amount For signed and direction
Money out is shown as amount.outgoing Negative numbers, Positive numbers. For signed.
Money out column amount.debit For split
Money in column amount.credit For split
In or out column amount.direction For direction
Words that mean money out amount.debit For direction. Exact text; several separated by |. Default OUT.
Words that mean money in amount.credit For direction. Default IN.

dot-or-comma takes whichever of . or , appears and cannot be combined with a thousands separator. space accepts a space, a no-break space or a narrow no-break space. Groups must be 3 digits after a first group of 1 to 3. Money out is stored as a negative amount.

Currency and names

Label Mapping key Values
Currency currency.kind The same for every row (default), Read from a column (column)
Currency for every row currency.currency For default
Currency column currency.column For column
Currency when that column is empty currency.blankDefault For column. Empty means a blank cell is an error.
Paid to column merchant Required. A blank cell is an error.
Reference column reference Optional
moreReferences Optional, set by layouts only. Up to 5 more text columns, such as a message or description, joined onto the reference with /. A value already contained in an earlier one is left out.
Transaction ID column externalId Optional. The bank’s own ID for the row.
Original amount column original.amount Optional. Must be paired with the next.
Original currency column original.currency Optional. Must be paired with the previous.

Already imported?

Label Field Values
If a payment was already imported collision Ask me (empty), Skip the ones already imported (keep_existing), Import them as extra payments (additional)
I checked the account. Similar payments in my other accounts are separate payments. acknowledge_other_account Tick

Saved layouts

There is no form for this. A layout the model proposed or you set in the editor is saved when the import succeeds, with a fingerprint of the normalised column names, and is used for files whose column names give the same fingerprint, the account’s bank first. Built-in and saved layouts are not saved again. A failure to save the layout does not undo the import.

Accepted formats

Item Accepted
Encodings UTF-8, UTF-16 LE, UTF-16 BE, Windows-1252. A byte order mark selects the UTF encoding. Without one, the file must be valid in the chosen encoding.
Files .xlsx (first sheet; inline and shared strings, numbers, and dates stored as Excel serial numbers) and CSV. A spreadsheet is turned into a CSV on upload, and that CSV is what is checked and stored as the original.
PDF A statement with a text layer, up to 400 pages. It is turned into a CSV on upload the same way; see PDF statements.
Separators , ; tab |. Detected from the column names row when not chosen.
Currencies EUR, USD, GBP, CHF, SEK, NOK, DKK, CAD, AUD, JPY
Amounts Integer minor units. More decimals than the currency has are allowed only when they are zero.
Not accepted Scanned PDFs without text, .xls, bank API connections, filtering of pending rows

Built-in layouts

Built-in layouts are matched by column names. They were tested with synthetic files only and are named after the CSV layout, not the bank. Presets match common CSV export layouts; Nuits Receipts is not affiliated with any bank.

Layout Matches column names Date Decimal Separator
Holvi (CSV layout), statement Value date, Booking date, Amount, Currency, Counterparty, Description, Filing ID (XLSX or CSV statement). Date from Booking date; Reference, Description and Message joined into the reference; Filing ID is the transaction ID; a Currency and amount: USD 10.46 line in Description is the original amount and currency. D MMM YYYY . ,
PDF statement (CSV layout) Date, Amount, Counterparty, Description, Reference, Transaction ID, Currency, in that order: what a PDF statement of another bank becomes on upload. A blank currency is the account currency. ISO . ,
Holvi (CSV layout) Recognised aliases for date, payee, amount or debit and credit, and optional currency, reference, transaction ID and original amount and currency ISO_OR_DOTTED dot-or-comma ;
Nordea (CSV layout) Kirjauspäivä, Saaja, Summa, Valuutta, Viite DD.MM.YYYY , with space grouping ;
OP (CSV layout) Same as Nordea DD.MM.YYYY , with space grouping ;
Revolut (CSV layout) Started Date, Completed Date, Description, Amount, Currency, ID ISO, date from Completed Date . ,
Wise (CSV layout) ID, Date, Amount, Currency, Description, Reference ISO . ,
N26 (CSV layout) Date, Payee, Payment reference, Amount (EUR), Currency ISO . ,

When exactly one layout matches, it is applied automatically. When several match, you choose one or Custom mapping.

Column names row

For a new file, the row with the column names is found automatically: the first row of two or more names with no gaps, none of them a number or a date, whose following rows fit under it. Rows above it, such as an account line or stated totals, are left out and listed under the preview. When no row qualifies, the first row is used. Which row has the column names? overrides it.

Stated totals

Above the column names, a label that names a volume, sum or amount, or a count or number, of credits or debits (for example Total volume of credits and Total count of debits) is read with the figure in the cell below it. Credits are compared with the payments read as money in and debits with money out. Opening balance and Closing balance are read the same way: the opening balance plus every payment must come to the closing balance. A different count, sum or balance is a problem and blocks the import.

Layouts read automatically

When no saved or built-in layout matches, one request goes to Workers AI (Clef). It sends only the column names and up to 5 rows, each cell cut to 40 characters, and asks which column holds the date, the amount (or money out and money in), the currency, the payee, a description, a reference and the transaction ID, plus the date format and how money out is shown. The answer can only name columns of the file. The decimal mark and the date format are confirmed against the sample rows, and the account currency is used when there is no currency column.

The proposal is used only if the whole file then reads with no row problems. Otherwise, or if the request fails, the page asks for the columns as before. The proposal travels with the preview, so Check again and Import make no further requests. With AI_MODE mock, columns are picked by their names instead.

PDF statements

A PDF statement is turned into a CSV on upload, with the statement’s printed balances and totals above the column names, so the checks above apply to it. The text is read with its position on the page, which keeps the columns apart.

  • Holvi (EUR - ACCOUNT STATEMENT, columns Booking date, Payment information, Transaction no., Amount EUR) is read by its layout, with no model request. Each payment becomes a row of the Holvi statement layout: the booking date, the signed amount, the other party from the payment information (an IBAN line left out), the payment type, the Message and Reference parts, the Currency and amount line of a card payment abroad, and the Filing ID as the transaction ID. The BALANCE lines and the TOTAL NUMBER OF DEPOSITS and WITHDRAWALS lines are the stated figures. A line in no known place stops the read instead of being skipped.
  • Other layouts are cut into one block per payment: a line that starts with a date, up to the next one. Lines printed in the same place on most pages, such as page headers and footers, are left out, and labelled opening and closing balance and total lines are read as stated figures. Workers AI (Clairic) reads the date, amount, currency, other party, description, reference and transaction ID of each block, 20 blocks per request and up to 4 requests at a time, at most 1,000 blocks. Each value is then checked against the block’s own text: the amount must be printed in it, the date must be a reading of its leading date, and text values must appear in it. A value that fails, or that Clairic is not sure of, is left blank, so the row is listed as a problem.

The PDF is read once, on upload. Check again and Import use the CSV it became, which is also what is stored as the original. With AI_MODE mock, other layouts are read by a fixed local reader instead.

Column name aliases (Holvi layout)

Column names are compared after normalisation (lower case, accents removed, punctuation as spaces).

Value Aliases
Transaction ID transaction id, transaction number, tapahtumatunnus, tapahtuma id
Date booking date, date, kirjauspaiva, tapahtumapaiva
Amount amount, summa, maara
Currency currency, valuutta
Paid to payee, recipient, counterparty, name, saaja, maksaja, nimi
Reference reference, message, description, viite, viitenumero, viesti, selite
Original amount original amount
Original currency original currency
Money out debit
Money in credit

Row problem codes

Shown in the preview as “Row N, field: message (code)”.

Code Meaning
csv_syntax The CSV parser could not read the row.
column_count The row has a different number of columns from the column names row.
mapping_column A mapped column is not in the column names row.
invalid_date The date does not match the format, or a time is present when not allowed.
invalid_merchant The paid-to cell is empty.
invalid_currency Unsupported or empty currency.
invalid_amount The amount does not parse, the debit and credit cells conflict, or the sign conflicts with the direction word.
invalid_original_currency Unsupported original currency.
invalid_original_amount Original amount does not parse, or its sign differs from the amount.

Duplicates and re-imports

Situation Result
Same file bytes, same account, import complete Nothing new is imported. Existing matches and exemptions stay.
Same file bytes, same account, import pending The import resumes with the settings it was started with.
Same file bytes, another account Refused with HTTP 409.
Row with a transaction ID already stored in this account with the same facts Skipped.
Row with a transaction ID already stored in this account with different facts Import refused with HTTP 409.
Row without a transaction ID equal to one from another file in the same account Skipped and counted; the banner offers Import anyway, which adds them as extra payments. In the editor, If a payment was already imported chooses (keep_existing or additional).
Equal rows without a transaction ID inside one file Kept as separate payments.
Same date and amount, or same transaction ID, in another account Imported and counted in the banner. In the editor it needs the account tick. Rows are never merged across accounts.

A row’s identity is a hash of the account and either the transaction ID or its facts: booking date, amount, currency, normalised merchant, reference, original amount and original currency, plus a count of equal rows before it in the file.

Limits

Limit Value
File size 2 MiB
Rows 1 to 5,000, not counting the column names row and skipped rows
Columns 100
Cell size 64 KiB decoded
Stored raw row 256 KiB of JSON
Saved mapping 32 KiB
Import record (manifest) 1 MiB

Type to search…

↑↓ navigate↵ selectEsc close