Bank statement extraction API
REST API to convert PDF bank statements into structured JSON. 99% accuracy, auto-refunded on failure.
$ curl https://api.bankstatementlab.com/v1/extractions \
-H "Authorization: Bearer bsl_live_..." \
-F "file=@statement.pdf" Bank statements extraction
Extract transactions, balances and metadata from any PDF.
Structured JSON output
Predictable schema across 10 supported languages.
99% accuracy
Auto-refunded on failure. No charge for failed extractions.
Sync & async modes
Synchronous for small PDFs, async + polling for large batches.
Code samples
Integrate in any language. Examples below.
$ curl https://api.bankstatementlab.com/v1/extractions \
-H "Authorization: Bearer bsl_live_..." \
-F "file=@statement.pdf" const form = new FormData();
form.append("file", fs.createReadStream("statement.pdf"));
const res = await fetch("https://api.bankstatementlab.com/v1/extractions", {
method: "POST",
headers: { Authorization: `Bearer $${process.env.BSL_KEY}` },
body: form,
});
const data = await res.json(); import requests
with open("statement.pdf", "rb") as f:
r = requests.post(
"https://api.bankstatementlab.com/v1/extractions",
headers={"Authorization": f"Bearer {BSL_KEY}"},
files={"file": f},
)
data = r.json() $ch = curl_init("https://api.bankstatementlab.com/v1/extractions");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer " . getenv("BSL_KEY")]);
curl_setopt($ch, CURLOPT_POSTFIELDS, [
"file" => new CURLFile("statement.pdf"),
]);
$data = json_decode(curl_exec($ch), true); Responsformaten
De velden data, column_names en transaction_count zijn alleen aanwezig wanneer status gelijk is aan "completed". Anders worden ze weggelaten uit de JSON (afwezig, niet null).
GET /v1/extractions/:id
200 OK — Extractie voltooid
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "ext_3f8a9b2c1d4e5f6a7b8c9d0e",
"status": "completed",
"file_name": "statement-march-2026.pdf",
"created_at": "2026-03-15T10:23:00.000Z",
"completed_at": "2026-03-15T10:23:18.000Z",
"page_count": 3,
"credits_charged": 3,
"api_key_id": "ak_abc123",
"column_names": ["Date", "Description", "Amount"],
"transaction_count": 42,
"data": {
"columns": ["Date", "Description", "Amount"],
"transactions": [
["2026-03-01", "VIREMENT SEPA", "1500.00"],
["2026-03-02", "CB CARREFOUR", "-45.20"]
]
}
} 200 OK — Extractie wordt uitgevoerd
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "ext_3f8a9b2c1d4e5f6a7b8c9d0e",
"status": "processing",
"file_name": "statement-march-2026.pdf",
"created_at": "2026-03-15T10:23:00.000Z",
"page_count": 3,
"credits_charged": 3,
"api_key_id": "ak_abc123"
} 200 OK — Extractie mislukt
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "ext_3f8a9b2c1d4e5f6a7b8c9d0e",
"status": "failed",
"file_name": "statement-march-2026.pdf",
"created_at": "2026-03-15T10:23:00.000Z",
"completed_at": "2026-03-15T10:23:32.000Z",
"page_count": 3,
"credits_charged": 3,
"api_key_id": "ak_abc123",
"error": {
"type": "extraction_failed",
"message": "Extraction failed due to an internal error. Contact support if the issue persists."
}
} Polling-patroon
Wanneer een extractie in async-modus draait, bevat de respons status: "processing" totdat de worker klaar is. Controleer altijd dat status gelijk is aan "completed" VOORDAT u de velden data, transaction_count en column_names leest — ze worden weggelaten uit de JSON totdat de extractie voltooid is.
Aanbevolen polling-frequentie aan de clientzijde: 5 tot 10 seconden. De worker aan de serverzijde draait elke 10 seconden — sneller pollen versnelt het resultaat niet.
GET /v1/extractions
200 OK — Gemengde pagina (één element per status)
HTTP/1.1 200 OK
Content-Type: application/json
{
"data": [
{
"id": "ext_001",
"status": "completed",
"file_name": "march.pdf",
"created_at": "2026-03-15T10:00:00.000Z",
"completed_at": "2026-03-15T10:00:18.000Z",
"page_count": 3,
"credits_charged": 3,
"api_key_id": "ak_abc123",
"column_names": ["Date", "Description", "Amount"],
"transaction_count": 42
},
{
"id": "ext_002",
"status": "processing",
"file_name": "april.pdf",
"created_at": "2026-04-15T10:00:00.000Z",
"page_count": 5,
"credits_charged": 5,
"api_key_id": "ak_abc123"
},
{
"id": "ext_003",
"status": "failed",
"file_name": "may.pdf",
"created_at": "2026-05-15T10:00:00.000Z",
"completed_at": "2026-05-15T10:00:42.000Z",
"page_count": 2,
"credits_charged": 2,
"api_key_id": "ak_abc123",
"error": {
"type": "extraction_failed",
"message": "Extraction failed due to an internal error. Contact support if the issue persists."
}
}
],
"has_more": false
} Polling-patroon
Wanneer een extractie in async-modus draait, bevat de respons status: "processing" totdat de worker klaar is. Controleer altijd dat status gelijk is aan "completed" VOORDAT u de velden data, transaction_count en column_names leest — ze worden weggelaten uit de JSON totdat de extractie voltooid is.
Aanbevolen polling-frequentie aan de clientzijde: 5 tot 10 seconden. De worker aan de serverzijde draait elke 10 seconden — sneller pollen versnelt het resultaat niet.
Built for
Accounting automation
Import client statements directly into your bookkeeping pipeline.
Lending due diligence
Verify income and cash flow from applicant bank statements.
Personal finance apps
Let users connect their statements without manual data entry.
Frequently asked questions
Send your API key as a Bearer token in the Authorization header. We use API keys — no OAuth in v1.
10 requests/second and 1,000 requests/hour per API key. Need higher limits? Contact us.
We target 99% uptime on a best-effort basis. No contractual SLA in v1 — reach out for enterprise commitments.
Failed extractions are automatically refunded to your credit balance. You only pay for successful pages.
PDF only in v1. Max 20 MB per file. Image and CSV support coming later.
English, French, Spanish, German, Italian, Portuguese, Japanese, Dutch, Korean, Hindi.