# Bank Statement Converter - PDF to Excel, CSV & JSON (`alex9080/bank-statement-converter`) Actor

Convert bank statement PDFs (and scanned statements or photos) into clean transactions: date, description, debit, credit, amount and running balance. Any bank, no templates. Every row is checked against the running balance. Export to Excel, CSV or JSON.

- **URL**: https://apify.com/alex9080/bank-statement-converter.md
- **Developed by:** [Alex](https://apify.com/alex9080) (community)
- **Categories:** Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 statement pages

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### Bank Statement Converter: PDF to Excel, CSV and JSON

Turn bank statement PDFs into a clean table of transactions. Upload a statement (or paste links to many) and get every transaction with **date, description, debit, credit, signed amount and running balance**, ready for Excel, Google Sheets, QuickBooks, Xero or your own code.

It works with **any bank and any layout, without templates**: the Actor finds the date column and the money columns on its own, joins descriptions that wrap over several lines, and then **checks every row against the running balance**, so you can see at a glance that nothing was missed or misread.

#### What it handles

- **Text PDFs** downloaded from online banking, and **scanned statements or phone photos** (built-in OCR, 10 languages).
- **Any column layout**: Debit / Credit / Balance, Paid out / Paid in, Money out / Money in, Withdrawals / Deposits, a single signed Amount column, amounts with `CR` / `DR`, `-` or `+` after the number, amounts in brackets.
- **Number formats**: `1,234.56`, `1.234,56`, `1 234,56`, Indian `1,23,456.78`, currency symbols and codes.
- **Date formats**: `01/15`, `15/01/2026`, `2026-01-15`, `15.01.2026`, `15 Jan`, `Jan 15, 2026`, `15JAN26`, date with time; years are filled in when the statement leaves them out.
- **Statement quirks**: the date printed only once per day, the balance shown only at the end of each day, the amount on the last line of a multi-line description, newest-first order, balance brought/carried forward between pages, a separate value date column.
- **Password-protected PDFs** (the password field is encrypted).
- **Many statements in one run**: each file gets its own Excel and CSV plus one combined dataset.

#### What you get

| Field | Example |
|---|---|
| `date` | `2026-01-15` |
| `description` | `CARD PAYMENT TO TESCO STORES 3412` |
| `debit` | `45.20` |
| `credit` | `null` |
| `amount` | `-45.20` (negative = money out) |
| `balance` | `1,254.80` |
| `currency` | `GBP` |
| `balanceCheck` | `ok`, `mismatch`, `corrected` or `n/a` |
| `valueDate`, `page`, `file` | when available |

Per statement, the key-value store also gets:

- `<file>.xlsx` with a **Transactions** sheet (real dates and numbers, filters, frozen header) and a **Summary** sheet,
- `<file>.csv` (UTF-8, opens directly in Excel and Google Sheets),
- `SUMMARY` with opening and closing balance, total credits and debits, first and last date, how many rows passed the balance check, and whether opening balance + movements = closing balance.

#### Balance check: why you can trust the numbers

For every transaction the Actor computes *previous balance + amount* and compares it with the balance printed on the statement. Rows that add up are marked `ok`. If a scanned page has a misread digit and the balance proves what the amount must be, the amount is fixed and marked `corrected`. Anything else is marked `mismatch`, so you know exactly which rows to look at. Statements without a balance column are checked with opening + movements = closing.

#### How to use it

1. Upload a PDF in **Upload a statement**, or paste one or more links in **Statement URLs** (Google Drive and Dropbox share links work).
2. If the PDF has a password, enter it.
3. Click **Start**. Download the table from the **Output** tab as Excel, CSV or JSON, or open the per-statement Excel file from the key-value store.

##### Input example

```json
{
  "statementUrls": ["https://example.com/statements/2026-01.pdf"],
  "dateFormat": "auto",
  "ocr": "auto",
  "ocrLanguages": "eng"
}
```

##### From code

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("alex9080/bank-statement-converter").call(run_input={
    "statementUrls": ["https://example.com/statements/2026-01.pdf"],
})
for tx in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(tx["date"], tx["amount"], tx["description"])
```

It also works from Make, Zapier, n8n and AI agents through the Apify API and MCP server.

#### Pricing

You pay only for pages that contain transactions:

- **$0.01 per text page** (a regular PDF from online banking),
- **$0.02 per scanned page** (OCR).

Cover pages, legal notes and pages without transactions are free, and so are files that fail to download or contain no transactions. A typical 4-page monthly statement costs about $0.03.

#### Tips

- **Ambiguous dates** like `03/04/2026`: Auto decides from the file (any day above 12 settles it; otherwise `$` statements are read as month-first and others as day-first). Set **Date format** if your bank uses the other order.
- **Scans**: 300 dpi or a sharp phone photo gives the best results. Add your language in **OCR languages**, e.g. `eng+deu`.
- If a statement is not converted correctly, open an issue on the **Issues** tab with the bank name and what went wrong (no need to share the file). Layout fixes are usually quick.

#### Privacy

Files are processed inside your own Apify run and stored only in your own Apify storage. Nothing is sent to third-party services or AI models. Delete the run's storage whenever you like.

#### FAQ

**Which banks are supported?** Any bank whose statement lists transactions as a table with dates and amounts, from US, UK and EU banks to India, Australia, Ukraine and fintechs like Revolut or Monzo. There are no per-bank templates to wait for.

**Does it read credit card statements?** Yes, as long as they list transactions with dates and amounts.

**Is my data used for anything else?** No. The Actor does not keep copies and does not use AI services.

# Actor input Schema

## `statementFile` (type: `string`):

PDF bank statement, or a scan/photo (PNG, JPG, TIFF). Text PDFs and scanned PDFs both work.

## `statementUrls` (type: `array`):

Direct links to statement files. Google Drive and Dropbox share links are converted automatically. Each file is processed separately.

## `password` (type: `string`):

Only for password-protected statements. Stored encrypted.

## `dateFormat` (type: `string`):

Order of day and month in numeric dates like 03/04/2026. Auto works it out from the file (a day above 12 settles it; otherwise $ statements are read as MM/DD, the rest as DD/MM).

## `ocr` (type: `string`):

Auto uses OCR only on pages without a text layer.

## `ocrLanguages` (type: `string`):

Tesseract language codes joined with +. Available: eng, deu, fra, spa, ita, por, nld, pol, ukr, rus. Example: eng+deu

## `currency` (type: `string`):

ISO code to put in the currency column when the statement does not show one, e.g. USD, GBP, EUR.

## `excel` (type: `boolean`):

Save an .xlsx with a Transactions sheet and a Summary sheet to the key-value store.

## `csv` (type: `boolean`):

Save a .csv (UTF-8, opens in Excel and Google Sheets) to the key-value store.

## Actor input object example

```json
{
  "statementUrls": [
    "https://api.apify.com/v2/key-value-stores/TLvsglAihwETQvW16/records/sample-bank-statement.pdf"
  ],
  "dateFormat": "auto",
  "ocr": "auto",
  "ocrLanguages": "eng",
  "excel": true,
  "csv": true
}
```

# Actor output Schema

## `transactions` (type: `string`):

No description

## `files` (type: `string`):

No description

## `summary` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "statementUrls": [
        "https://api.apify.com/v2/key-value-stores/TLvsglAihwETQvW16/records/sample-bank-statement.pdf"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("alex9080/bank-statement-converter").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "statementUrls": ["https://api.apify.com/v2/key-value-stores/TLvsglAihwETQvW16/records/sample-bank-statement.pdf"] }

# Run the Actor and wait for it to finish
run = client.actor("alex9080/bank-statement-converter").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "statementUrls": [
    "https://api.apify.com/v2/key-value-stores/TLvsglAihwETQvW16/records/sample-bank-statement.pdf"
  ]
}' |
apify call alex9080/bank-statement-converter --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,alex9080/bank-statement-converter"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/oBMPZACf7UONJqmAQ/builds/FL0XcUItqrcDYmDBd/openapi.json
