Back to Blog
June 9, 2026

Bank Statement API for Developers: Complete Integration Guide 2026

TL;DR

A bank statement API takes a PDF upload and returns structured JSON — a transactions array with date, description, amount, and balance, plus page count and detected format. Authenticate with an API key, POST the file to the extract endpoint, and handle the synchronous response or a webhook for large files. Most APIs bill per page.

Bank Statement API: Complete Integration Guide for Developers

Whether you're building a fintech app, accounting software, or a data pipeline, integrating bank statement parsing via API saves months of development time.

Why Use an API Instead of Building Your Own?

Building a reliable bank statement parser from scratch requires:

  • Handling hundreds of different PDF layouts across dozens of countries
  • Parsing dates in many formats across languages
  • Distinguishing debits from credits across different conventions
  • Rebuilding logic every time any bank updates its format

An API abstracts all of this. You send a PDF, you get structured JSON.

Authentication

Get an API key from your dashboard (starts with pex_):

curl -X POST https://api.bankstatementparser.net/extract \

-H "X-Api-Key: pex_your_api_key" \

-F "file=@statement.pdf"

Python Integration

import requests

from pathlib import Path

class BankStatementParser:

BASE_URL = "https://api.bankstatementparser.net"

def __init__(self, api_key: str):

self.session = requests.Session()

self.session.headers.update({"X-Api-Key": api_key})

def extract(self, pdf_path: str | Path) -> dict:

with open(pdf_path, "rb") as f:

response = self.session.post(

f"{self.BASE_URL}/extract",

files={"file": (Path(pdf_path).name, f, "application/pdf")}

)

response.raise_for_status()

return response.json()

def extract_batch(self, pdf_paths: list) -> list[dict]:

return [self.extract(p) for p in pdf_paths]

# Usage

parser = BankStatementParser("pex_your_api_key")

result = parser.extract("statement.pdf")

print(f"Format: {result['bankKey']}")

print(f"Pages: {result['pageCount']}")

print(f"Transactions: {len(result['transactions'])}")

Node.js / TypeScript Integration

import FormData from 'form-data';

import fs from 'fs';

interface Transaction {

date: string;

description: string;

amount: number;

balance: number;

}

interface ParseResult {

bankKey: string;

pageCount: number;

transactions: Transaction[];

}

async function parseStatement(filePath: string): Promise {

const form = new FormData();

form.append('file', fs.createReadStream(filePath));

const response = await fetch(

'https://api.bankstatementparser.net/extract',

{

method: 'POST',

headers: {

'X-Api-Key': 'pex_your_api_key',

...form.getHeaders(),

},

body: form as unknown as BodyInit,

}

);

if (!response.ok) {

throw new Error(Parse failed: ${response.status} ${response.statusText});

}

return response.json();

}

Error Handling

import requests

def safe_extract(pdf_path: str, api_key: str) -> dict | None:

try:

response = requests.post(

"https://api.bankstatementparser.net/extract",

headers={"X-Api-Key": api_key},

files={"file": open(pdf_path, "rb")},

timeout=60

)

match response.status_code:

case 200:

return response.json()

case 402:

print("Monthly quota exceeded — upgrade your plan")

case 415:

print("File is image-based (OCR not yet supported)")

case 422:

print("Could not parse this format")

case 429:

print("Rate limited — slow down requests")

case _:

response.raise_for_status()

except requests.Timeout:

print("Request timed out — file may be too large")

except requests.ConnectionError:

print("Connection error")

return None

Webhook Integration

For async processing (large files, high-volume workflows):

from flask import Flask, request, jsonify

import requests

app = Flask(__name__)

def submit_async(pdf_path: str, webhook_url: str):

return requests.post(

"https://api.bankstatementparser.net/extract",

headers={

"X-Api-Key": "pex_your_api_key",

"X-Webhook-Url": webhook_url,

},

files={"file": open(pdf_path, "rb")}

).json()

@app.route("/bank-callback", methods=["POST"])

def handle_result():

data = request.json

transactions = data["transactions"]

format_key = data["bankKey"]

print(f"Received {len(transactions)} transactions for format {format_key}")

return jsonify({"ok": True})

Response Schema

{

bankKey: string; // e.g. "bank_v1", "format_v2"

pageCount: number; // number of PDF pages processed

transactions: Array<{

date: string; // ISO 8601: "2026-05-15"

description: string; // raw transaction description

amount: number; // negative = debit, positive = credit

balance: number | null; // running balance (null if not in PDF)

}>;

}

Rate Limits & Quotas

| Plan | Pages/month | Requests/min |

|------|-------------|--------------|

| Free | 50 | 10 |

| Starter | 500 | 30 |

| Professional | 3,000 | 60 |

| Enterprise | 15,000 | 200 |

Get Your API Key

[Create a free account →](https://bankstatementparser.net/en/register) — 50 pages/month free, no credit card.

Get Started for Free

Up to 50 pages/month free. No credit card required.

Create Account