CSV vs MT940, and why anyone needs to bridge them
CSV is what you get out of a spreadsheet. MT940 is what banks and a lot of accounting software speak. Both describe the same thing, money moving in and out of an account, but they look nothing alike. One’s a grid of columns. The other is a stack of cryptic SWIFT tags like :60F: and :61:, each with its own field order and a comma instead of a dot for the decimal.
So when a finance tool says “import an MT940 file” and all you have is a CSV, you’re stuck. That’s the gap this fills. Paste rows on the left, get a statement block on the right.
How the conversion works
Three columns do the heavy lifting: a date, an amount, and a description. A fourth column, reference, is optional. The tool reads your header row to find them, so date,amount,description works, and so does Value Date,Sum,Narrative. No header? Switch the toggle off and it falls back to column order instead.
Here’s what each row becomes. The amount’s sign decides direction: a positive number turns into a credit (C), a negative one into a debit (D), and that drives the :61: line. The description lands in the matching :86: line right below, wrapped at 65 characters so it doesn’t blow past the SWIFT line limit. Dates get normalized to YYMMDD, whether you typed 2024-03-01, 01/03/2024, or an already-coded 240301.
Balances are where people trip. You set the opening balance, and it’s stamped into :60F: with the date of your first transaction. Then the tool walks every row, adding credits and subtracting debits, and writes the result into :62F:. The math runs in integer cents, so you won’t see a rogue 0.30000004 creeping in from floating point.
A small header block sits up top: :20: for the transaction reference, :25: for your account number, and :28C: for the statement number. All three are yours to set.
A worth-knowing caveat
This produces a simplified MT940. Real bank exports carry extra detail: structured :86: subfields, an envelope of {1:} and {4:} blocks around the message, sometimes a :34F: floor limit. None of that is here. What you get is a clean, minimal statement that’s good for testing an importer, prototyping a reconciliation flow, or feeding software that accepts a basic block. If your auditor needs a byte-perfect file, this isn’t that.
The transaction type defaults to NTRF (a transfer) for every line, since a plain CSV doesn’t say whether a row is a card payment, a standing order, or a fee. Edit the output afterward if you need different codes.
When you’d reach for this
You’re testing an accounting integration and need sample MT940 input fast. Your bookkeeping app only swallows MT940, but your transaction log lives in Sheets. Or you’re learning the format and want a real-ish statement without waiting on a bank export. Drop the data, tweak the account and opening balance, hit Download, and you’ve got an .sta file (or .txt) in seconds. It all runs locally, so account numbers and amounts never leave the page.
FAQ
What columns does my CSV need?
Date, amount, and description, in that order or named in a header. Reference is optional and fills the :61: reference field. Anything beyond those four columns is ignored.
How do debits and credits get decided?
By the sign of the amount. Negative is a debit, positive is a credit. Write -89.99 for money leaving the account and 1250.00 for money coming in.
Is this a real, bank-grade MT940 file?
Nope. It’s a simplified statement with the core tags. It skips the SWIFT message envelope and the structured subfields a production export carries, so treat it as a starting point, not a certified document.
What date formats can I paste?
ISO (2024-03-01), day-first slashes (01/03/2024), dotted dates, or a bare YYMMDD code. They all get converted to the YYMMDD form MT940 uses internally.
Does my financial data get uploaded?
No. The parsing and the balance math both run in JavaScript on your device. Nothing is sent anywhere, which is the whole point when the file is real account activity.
Why does the closing balance look off by a cent sometimes?
It shouldn’t. The running total is computed in whole cents to dodge floating-point drift. If it’s wrong, check that every amount parsed correctly, since a row with an unreadable amount gets skipped and flagged in the notes above the output.