Skip to content

Bank statement API

Send a PDF bank or credit card statement, get every transaction back as JSON — or as Excel, CSV, QuickBooks, OFX, QIF or Xero files. The same reader as the website, with the running-balance check. Free, no limits.

1. Get a key

Create a free account, confirm your email, and create a key on your API page. Keys look like sg_live_… and are shown once.

2. Convert a statement

curl https://statementeasy.com/api/v1/convert \
  -H "Authorization: Bearer sg_live_your_key" \
  -F [email protected]

Answer (shortened):

{
  "bank": { "slug": "barclays", "name": "Barclays" },
  "pages": 2,
  "period": { "from": "2025-09-25", "to": "2025-10-01" },
  "opening_balance": 90601.11,
  "closing_balance": 122693.89,
  "total_in": 40657.5,
  "total_out": 8564.72,
  "check": { "status": "ok", "checked_rows": 7, "mismatched_rows": 0,
             "message": "Balances match on all 7 checked rows" },
  "count": 8,
  "transactions": [
    { "date": "2025-10-01", "value_date": null,
      "description": "Bill Payment ARTHUR J GALLAGHER 548838138 BBP",
      "amount": -566.72, "money_in": null, "money_out": 566.72,
      "balance": 122693.89, "balance_check": "ok" }
  ]
}

check.status is ok when every row matches the running balance, totals when the statement has no running balance but opening + in − out = closing, warn when something does not add up (look at rows with "balance_check": "mismatch"), and none when there is nothing to check against.

3. Or get a file

curl https://statementeasy.com/api/v1/convert \
  -H "Authorization: Bearer sg_live_your_key" \
  -F [email protected] -F format=qbo -o statement.qbo

Parameters

FieldValuesDefault
fileThe statement (multipart), up to 25 MB: a PDF (text or scanned), a photo (JPG, PNG, WebP, HEIC, TIFF), or a CSV, Excel (.xlsx), OFX, QFX, QBO, QIF, MT940 or CAMT.053 bank filerequired
formatjson, xlsx, csv, qbo, qfx, ofx, qif, iif, mt940, camt, xero, qbocsvjson
pagesOnly these pages of a PDF, e.g. 2-5,8all
passwordPassword of a protected PDF—
date_formatiso, dmy, mdy (files only)iso
layoutsplit (money in / out) or signed (one amount), for xlsx/csvsplit
categoriestrue adds a category to each transactionfalse
payeetrue adds a Payee column (clean merchant name) to xlsx/csv. JSON always includes payee.false
rulesJSON array of your rules: [{"match":"amazon","payee":"Amazon","category":"Shopping","sign":"out"}]. A rule applies when the description contains match (any case, accents ignored); the first match wins; sign is optional.—
insightstrue adds insights to the JSON: months, categories, top payees, average daily balance, days below zero, regular income, recurring payments, large deposits, returned payments and overdraft feesfalse
document_checktrue adds document_check to the JSON: verdict (clean, review or edited) and the reasons (editing tools, saves after creation, amounts in a different font, balance breaks). Text PDFs only. It finds traces of editing; it cannot prove a file is genuine.false
masktrue hides account and card numbers, IBANs and emails (last 4 digits kept)false
credit_cardtrue when the PDF is a card statement with unsigned amountsfalse
date_orderDMY or MDY to force how 03/04 is readdetected
bankA bank slug from supported banksdetected
currencyISO code for OFX/QBO, e.g. GBPfrom the bank, else USD

Scans and photos

Scanned PDFs and photos are read with OCR on our server, then converted like any other statement. The call waits up to about 100 seconds; most one- or two-page scans are back well before that. If it takes longer, you get 202 with a job id:

{ "status": "processing", "job": "9a8c8c2a-…", "status_url": "https://statementeasy.com/api/v1/jobs/9a8c8c2a-…" }

Call GET /api/v1/jobs/{id} with the same key: 202 while it runs, then the same answer /convert would have given (JSON or file). Results are kept for 30 minutes. Add webhook_url=https://… to be called with {"id", "status"} when the job ends, and ocr_language=fr (or ar, es, pt, de) for statements that are not in English.

Errors

Errors come back as {"error": {"code": "…", "message": "…"}} with an HTTP status: 401 missing or invalid key, 413 file too large, 422 for not_a_pdf, password_required, wrong_password, ocr_failed, no_table, no_movements, 429 above 60 requests a minute per key, and 503 when the converter is busy (retry after a few seconds).

Check a key

curl https://statementeasy.com/api/v1/me -H "Authorization: Bearer sg_live_your_key"

OpenAPI and Postman

The full description is in openapi.json (OpenAPI 3). Import it into Postman, Insomnia or a code generator to get a ready client.

What happens to the file

Unlike the website, the API needs the PDF on our server: it is written to a private temporary file, converted, and deleted as soon as the answer is ready — usually within a second or two. It is never stored, logged or looked at. We keep a usage record per call (time, size, pages, rows, result) to run the service, without any statement content.

Scans and photos are read by our OCR worker: the file is deleted as soon as it has been read, and the converted result is kept encrypted for 30 minutes so you can collect it, then deleted.