ParseBank

Developer API

Bank statement OCR & parsing API

Turn statement PDFs, scans, and photos into structured transactions with three REST calls. Vision-based extraction works with any bank; every row is verified against the statement's running balance before you ever see it.

Open interactive referenceGet an API keyopenapi.yaml

Quickstart

Create a key at /dashboard/api (Business plan or higher), then it's upload → poll → export:

# 1. Upload
curl -X POST https://parsebank.io/api/v1/statements \
  -H "Authorization: Bearer sk_live_..." \
  -F "[email protected]"
# → { "data": { "id": "abc123", "status": "processing", "pages": 12 } }

# 2. Poll until completed
curl https://parsebank.io/api/v1/statements/abc123 \
  -H "Authorization: Bearer sk_live_..."

# 3. Download the export
curl -o statement.csv \
  "https://parsebank.io/api/v1/statements/abc123/export?format=csv" \
  -H "Authorization: Bearer sk_live_..."

Authentication

Every request carries your key as a Bearer token: Authorization: Bearer sk_live_…. Keys are shown once at creation and can be revoked instantly from the dashboard. We store only a hash — treat the key like a password and keep it server-side.

Node.js

const BASE = "https://parsebank.io/api/v1";
const KEY = process.env.STATEMENT_API_KEY; // sk_live_...

const headers = { Authorization: `Bearer ${KEY}` };

// 1. Upload
const form = new FormData();
form.append("file", new Blob([await fs.readFile("statement.pdf")]), "statement.pdf");
const upload = await fetch(`${BASE}/statements`, {
  method: "POST",
  headers: { ...headers, "Idempotency-Key": "invoice-2026-07-run1" },
  body: form,
});
const { data: { id } } = await upload.json();

// 2. Poll until completed
let statement;
do {
  await new Promise((r) => setTimeout(r, 2000));
  statement = (await (await fetch(`${BASE}/statements/${id}`, { headers })).json()).data;
} while (statement.status === "processing");

if (statement.status === "failed") throw new Error(statement.error.message);
console.log(statement.validation.balance_check, statement.transactions.length, "rows");

// 3. Export as CSV
const csv = await (await fetch(`${BASE}/statements/${id}/export?format=csv`, { headers })).text();

Python

import os, time, requests

BASE = "https://parsebank.io/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['STATEMENT_API_KEY']}"}

# 1. Upload
with open("statement.pdf", "rb") as f:
    r = requests.post(
        f"{BASE}/statements",
        headers={**HEADERS, "Idempotency-Key": "invoice-2026-07-run1"},
        files={"file": ("statement.pdf", f, "application/pdf")},
    )
r.raise_for_status()
statement_id = r.json()["data"]["id"]

# 2. Poll until completed
while True:
    data = requests.get(f"{BASE}/statements/{statement_id}", headers=HEADERS).json()["data"]
    if data["status"] != "processing":
        break
    time.sleep(2)

if data["status"] == "failed":
    raise RuntimeError(data["error"]["message"])
print(data["validation"]["balance_check"], len(data["transactions"]), "rows")

# 3. Export as CSV
csv = requests.get(
    f"{BASE}/statements/{statement_id}/export", params={"format": "csv"}, headers=HEADERS
).text

Errors

Failures return { "error": { "code", "message" } }:

CodeHTTPMeaning
invalid_api_key401Missing, malformed, or revoked key
plan_required403API needs the Business plan or higher
insufficient_credits402Document exceeds remaining page credits
file_too_large413Over 50MB or over 100 pages
unsupported_format415Not a PDF, JPEG, or PNG
password_required422Protected PDF — send the password field
password_incorrect422Wrong PDF password
extraction_failedJob failed; credits refunded automatically
not_found404No statement with this id on your account
rate_limited429Over 60 req/min — honor Retry-After

Rate limits & credits

Data retention

Original files are deleted from storage as soon as page rendering completes — before extraction even finishes. Extracted transactions follow your account's retention setting (7 days to 1 year, or Never) and can be removed immediately with DELETE /api/v1/statements/{id}. PDF passwords are used once in memory and never stored. ParseBank never trains AI models on your data.

FAQ

What does the bank statement API return?

Structured transactions — date, description, debit, credit, balance, currency — as JSON, CSV, or XLSX. Every row is verified against the statement's printed running balance, and each statement reports a balance_check of passed, failed, or n/a.

Which banks and formats are supported?

Any bank — extraction is vision-based, not template-based, so it works with statements from any institution, in English, French, German, Spanish, or Italian. PDFs, scans, and phone photos are all supported, including password-protected PDFs.

How is the API priced?

API calls use the same page credits as the web app: 1 page = 1 credit, included in Business ($10/mo, 500 pages) and Corporate ($20/mo, 2,000 pages) plans. Credits are only charged for completed conversions — failures refund automatically.

Is uploaded data retained?

Original files are deleted the moment page rendering completes. Extracted data follows your retention setting (7 days to a year, or Never) and can be deleted anytime via the API. Nothing is used to train AI models.