How to Extract Transactions From a PDF Bank Statement

Extract transactions from a PDF bank statement. Normalize dates, debits, credits, and balances. Check duplicates and reconcile the result.

PdfParse Team

A bank statement can run to hundreds of transactions, and manual copy-paste is quietly dangerous: it moves values to the wrong row, mangles dates, and eats negative signs. It works right up until it doesn't — and it never tells you when.

This guide extracts transactions from a PDF bank statement the controlled way, then checks for duplicates and reconciles the closing balance. Extraction without reconciliation is just optimism.

One rule before anything else: use synthetic or authorized statements. If you don't have permission to process a statement, don't upload it.

What good output looks like

One row per transaction:

transaction_datedescriptiondebitcreditbalancecurrency
2026-06-02Payroll deposit2450.005320.18JMD
2026-06-03Office supply store297.005023.18JMD
2026-06-04Monthly account fee25.004998.18JMD

Statement-level values live in their own record:

bank_nameaccount_number_maskedperiod_startperiod_endopening_balanceclosing_balance
Example Bank****18422026-06-012026-06-302870.184998.18

Don't repeat the full account number on every transaction row. Keep only what your workflow actually needs — your security policy will thank you.

1. Define the transaction fields

These fields cover most bank statements:

FieldTypeExtraction rule
transaction_datedateUse YYYY-MM-DD
descriptiontextKeep all text for the transaction
debitnumberUse a positive number for money out
creditnumberUse a positive number for money in
balancenumberUse the running balance after the transaction
currencytextUse the statement currency code

Some banks prefer a single amount column and mark direction with a minus sign, or with DR and CR markers.

Pick one convention before extraction and hold the line. Separate debit and credit columns are usually the clearest for accounting imports — and whatever you choose, never mix negative debits with positive debit values in the same file.

2. Define the statement fields

Extract these values once per statement:

  • bank name
  • masked account number
  • account holder name, when necessary
  • statement start date
  • statement end date
  • opening balance
  • closing balance
  • currency

This split — statement once, transactions many — isn't just tidiness. It's how you spot a missing page, or the same statement uploaded twice.

3. Check the PDF type

Try to select one transaction description in your PDF viewer.

If the text highlights, the statement is usually digital. If it doesn't, you're looking at a scan, and OCR goes first.

On scanned statements, interrogate the usual suspects:

  • 0 and O
  • 1, I, and l
  • decimal points
  • commas in large values
  • minus signs
  • DR and CR markers

A missing decimal point turns 25.00 into 2500, which makes for a very different month. Always re-check high-value transactions after OCR.

4. Extract a small sample

Open the bank statement parser. Then:

  1. Upload one representative statement.
  2. Confirm the statement fields.
  3. Confirm the transaction fields.
  4. Start the extraction.
  5. Compare the rows with the source statement.
  6. Correct the schema rules when necessary.
  7. Process the remaining statements.

Pick a difficult sample on purpose — one with a page break, a wrapped description, or more than one amount column.

Resist the urge to run everything at once. A field error doesn't stay in one row; it quietly multiplies across the entire batch.

A statement goes in, transaction tables come out. Review the extracted rows against the source before you trust them.

5. Normalize the dates

Statements love omitting the year — 03 JUN, 06/03, take your pick.

Fill in the year from the statement period, and stay alert when the period crosses a year boundary. A statement running from 2025-12-20 to 2026-01-19 contains both years, so stamping 2026 on everything gets two weeks of transactions wrong.

Store dates in YYYY-MM-DD format. It sorts correctly and sidesteps the regional day-month guessing game.

6. Keep wrapped descriptions in one row

Banks often split a transaction across two lines — the merchant on one, a reference on the next:

03 JUN  OFFICE SUPPLY STORE       297.00 DR
        CARD 1842 KINGSTON

That's one transaction, and the output keeps it that way:

transaction_date,description,debit,credit
2026-06-03,"OFFICE SUPPLY STORE CARD 1842 KINGSTON",297.00,

The continuation line is not a second transaction. Don't let it become one.

7. Detect duplicate transactions

Upload the same statement twice and you'll get every row twice. But two genuinely identical purchases also happen — two coffees, same day, same amount. So deduplication needs more than one field.

Build a comparison key from several:

account + date + normalized description + debit + credit + balance

Flag matching keys for review, and don't delete them automatically unless your business rules allow it. When two rows look identical, the running balance or a transaction reference is usually what separates "duplicate upload" from "yes, I really did buy two."

8. Reconcile the balance

This is the check that catches everything else. With debits and credits as positive values in separate columns:

expected closing balance = opening balance + credits - debits

A quick Python check:

from decimal import Decimal

opening = Decimal("2870.18")
credits = Decimal("2450.00")
debits = Decimal("322.00")
expected_closing = opening + credits - debits

assert expected_closing == Decimal("4998.18")

If the numbers don't reconcile, the usual causes are:

  • a missing page
  • a missing transaction
  • a duplicate transaction
  • a debit in the credit column
  • an OCR error
  • a fee outside the main transaction table
  • a different balance convention

One firm rule: never edit a value just to make the balance agree. Find the real discrepancy in the source statement — adjusting numbers to fit is how small errors become audit findings.

9. Protect sensitive data

Bank statements are about as sensitive as documents get. Treat them that way:

  • Limit access to authorized users.
  • Keep API keys on the server.
  • Do not put statement data in application logs.
  • Mask account numbers in previews and media.
  • Delete temporary files according to your retention policy.
  • Keep a record of manual corrections.

For accounting or lending decisions that carry consequences, put a human review between extraction and final use.

Select the output format

CSV for spreadsheets and accounting imports. JSON for an API or automation workflow. SQLite when you want SQL queries across many statements.

Start with the bank statement parser. You can also use the PDF to CSV converter, review the API documentation, or check pricing.