A bank statement converted to JSON should hold one object with two parts: a header describing the account, the statement period and the opening and closing balances, and a transactions array with one object per line. Each transaction needs a date, a description, a signed amount and, where the bank prints it, the running balance.
What belongs in a bank statement JSON file?
A bank statement JSON file needs three things a developer can rely on: a header object for the statement as a whole, an array of transactions in printed order, and a small set of agreed types for dates and money. If any of the three is missing, the code that reads the file starts guessing, and guesses become bugs.
The header answers "which account, which month, what totals". The array answers "what happened, line by line". The types answer "how do I parse this without surprises". Everything else, such as the bank's logo text, the marketing panel on page one or the legal small print on the last page, can stay out of the file.
Developers also expect the file to be valid JSON in the strict sense. The JSON standard, RFC 8259 says JSON exchanged between systems outside a closed ecosystem must be encoded as UTF-8, and that names inside one object should be unique, because software that meets a duplicated key behaves unpredictably. A converter that writes two "amount" keys in one transaction, one for the debit column and one for the credit column, has produced a file that some parsers read one way and others read another.
A worked example
Here is a complete example document for a short statement. The bank, account and every value are made up for illustration.
{
"statement": {
"bank": "Example Savings Bank",
"accountHolder": "Example Bakery LLC",
"accountNumberLast4": "4417",
"currency": "USD",
"periodStart": "2026-03-01",
"periodEnd": "2026-03-31",
"openingBalance": "9731.07",
"closingBalance": "10602.02"
},
"transactions": [
{
"date": "2026-03-04",
"description": "CARD 1102 FLOUR SUPPLY CO",
"amount": "-412.80",
"balance": "9318.27",
"reference": null,
"page": 1
},
{
"date": "2026-03-15",
"description": "DEPOSIT MOBILE",
"amount": "1500.00",
"balance": "10818.27",
"reference": "DP-2201",
"page": 1
},
{
"date": "2026-03-28",
"description": "MONTHLY SERVICE FEE",
"amount": "-216.25",
"balance": "10602.02",
"reference": null,
"page": 2
}
]
}
Read it top to bottom and the shape is plain. One object per statement, one array per statement, and each line carries the page it came from so a reviewer can find it on paper.
The statement header object: account, period and balances
The statement header object holds the facts that apply to every transaction in the file: who owns the account, which account it is, which dates the statement covers, which currency it is in, and the opening and closing balances. Put them in one nested object so a reader can pass the header around without the long array attached.
A few naming habits save developers time. Pick one case style for keys, such as camelCase, and keep it everywhere. Spell out what a field is rather than copying the bank's label, so openingBalance rather than prevBal or Balance brought forward. Store only the last four digits of the account number, which is what most statements print anyway, and name the field so nobody mistakes it for the full number.
The field table below lists the header fields from the worked example, with the type each one should have.
| Field | Type | Example value |
|---|---|---|
| bank | string | "Example Savings Bank" |
| accountHolder | string | "Example Bakery LLC" |
| accountNumberLast4 | string | "4417" |
| currency | string, three letters | "USD" |
| periodStart | string, YYYY-MM-DD | "2026-03-01" |
| periodEnd | string, YYYY-MM-DD | "2026-03-31" |
| openingBalance | string, decimal | "9731.07" |
| closingBalance | string, decimal | "10602.02" |
Notice that the account number is a string, not a number. An account ending in 0417 would lose its leading zero as a number, and nobody ever does arithmetic on an account number. The same reasoning applies to sort codes, routing numbers and check numbers.
Some statements cover several accounts, such as a checking and a savings account on one PDF. In that case the cleanest file is an array of statement objects, each with its own header and its own transactions. Merging both accounts into one array, with a field to tell them apart, works too, but it pushes the splitting job onto every reader.
The transactions array in bank statement JSON
The transactions array holds one object per printed transaction line, in the order the statement prints them. Each object needs a date, the description text, one signed amount and the running balance when the statement shows one. Optional fields, such as a reference number, should still appear as null when empty.
Keeping the keys identical across objects matters more than it looks. A reader that loads the array into a table, a data frame or a database expects every row to have the same columns. If the reference field appears only on lines that have a reference, the first ten rows may define the columns and the eleventh breaks the import.
Descriptions as printed
Keep the description exactly as the bank printed it, including the odd capitals and card numbers. Cleaning it up, for example turning "CARD 1102 FLOUR SUPPLY CO" into "Flour Supply Co", is useful, but it is a separate step with its own rules. If you want both, add a second field such as payee and keep the raw text in description. That way a later rule change never destroys the original.
Long descriptions often wrap onto a second printed line. In JSON they belong in one string, with the wrapped parts joined by a single space. A converter that turns each printed line into its own transaction object creates fake lines with no amount, which is the first thing to look for when a file seems to have too many rows.
Order and the page field
Keep transactions in statement order rather than sorting by date or amount. Statement order is what the running balance follows, so it is the order you need to check the file. A page field costs a few bytes and makes every disputed line easy to find in the PDF.
Dates, amount signs and money values in statement JSON
Dates, signs and money values cause most of the parsing bugs in statement JSON, because JSON has no date type and its number type is a binary floating-point value in most languages. Write dates as YYYY-MM-DD strings, use a minus sign for money leaving the account, and write amounts as decimal strings or integer cents.
Dates
A statement printed in the United States shows 03/04/2026, which a European reader parses as 3 April. Converting every date to the ISO style, 2026-03-04, removes that doubt and sorts correctly as plain text. If the statement prints month and day only, the converter has to supply the year from the statement period, and a period that crosses New Year needs care: a December line on a January statement belongs to the earlier year.
Signs
Pick one rule and state it. The common rule for a bank account is that money out is negative and money in is positive, seen from the account holder's side. A statement with separate withdrawal and deposit columns maps cleanly onto that: withdrawals get a minus, deposits do not. Credit card statements often print charges as positive numbers, so a converter should say which convention it used rather than leave the reader to infer it from a few rows.
Money
RFC 8259 notes that good interoperability comes from expecting no more precision than IEEE 754 double-precision numbers provide. That is fine for a count of pages, but a sum of many amounts like 0.10 and 0.20 as doubles can drift away from the exact cents. Decimal strings such as "412.80" keep the exact value, and the reader converts them with a decimal type. Integer cents, such as 41280, are the other safe choice. Either works, as long as the file uses one and the header names the currency.
How do you test a bank statement JSON file before trusting it?
You test a bank statement JSON file by checking that it adds up: the opening balance plus every amount in the transactions array should equal the closing balance, and each running balance should equal the previous one plus that line's amount. If both checks pass, no line was dropped, doubled or given the wrong sign.
Work through the example above. The opening balance is 9731.07. The three amounts are -412.80, 1500.00 and -216.25, which sum to 870.95. Adding them gives 10602.02, which matches the closing balance in the header. Line by line, 9731.07 minus 412.80 gives 9318.27, plus 1500.00 gives 10818.27, minus 216.25 gives 10602.02. Every printed balance matches.
A short checklist covers the rest:
- It parses. Run the file through any strict JSON parser. A trailing comma or a single quote fails here.
- Every object has the same keys. Missing keys usually mean a wrapped line was split off as its own row.
- Dates fall inside the period. A date outside periodStart and periodEnd points to a wrong year or a misread day.
- The count looks right. Compare the number of transactions with a quick count on the PDF, page by page.
- Signs agree with the columns. Pick three withdrawals and three deposits from the PDF and confirm their signs.
FastBankConvert, which is getting ready to open, is built to read a statement PDF into Excel, CSV or JSON and to tell you before download when the balances do not add up, so the first of these checks is run for you. You can get started to hear when trial conversions open.
When JSON is the wrong output for a bank statement
JSON is the wrong output when the next reader is a person or an office program rather than code. A bookkeeper who sorts and totals lines needs a spreadsheet, and someone quoting lines in a letter needs a Word table. Pick the file for whoever opens it next.
JSON is at its best when a script, an app or an API reads the file. It keeps types, nests the header with the lines, and carries null values without ambiguity. A spreadsheet user gains nothing from that structure and has to import the file before seeing a single row.
If the statement is going into Excel, convert straight to a workbook. Software that converts PDF to Excel compares the desktop and online options for that route. If you need the statement as a table inside a report or a letter, moving a PDF table into Word covers how to keep the columns intact. If all you want is searchable words, such as finding every line that mentions one landlord across five years, turning a PDF into a plain text file is lighter than any structured format.
A middle case is the developer who also wants to eyeball the data. There the answer is often both: JSON for the code, and a CSV or workbook for the human check. Generating both from the same conversion keeps them in step, so a fix in one never has to be copied by hand into the other.