Skip to main content
BankFlow logoBankFlow

API reference

BankFlow v1 API

Parse bank statements programmatically. POST a PDF, CSV, XLSX, or JSON file, get structured JSON back. The same engine that powers the app, available over a simple REST API. API access is available on every plan, including free: usage is metered by your credit balance.

Authentication

Generate a personal access token (prefixed bnfw_) from the API settings in the app. Pass it as a bearer token on every request - including the OpenAPI endpoint.

http
Authorization: Bearer bnfw_your_api_key_here

Quickstart

Send a PDF, CSV, XLSX, or JSON file to /api/v1/parse and receive the parsed bank and transactions synchronously.

curl
curl -X POST https://api.bankflow.app/api/v1/parse \
  -H "Authorization: Bearer bnfw_your_api_key_here" \
  -H "Content-Type: application/pdf" \
  --data-binary @statement.pdf
javascript (Node.js)
const fs = require('fs');

const pdf = fs.readFileSync('statement.pdf');

const res = await fetch('https://api.bankflow.app/api/v1/parse', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer bnfw_your_api_key_here',
    'Content-Type': 'application/pdf',
  },
  body: pdf,
});

const { data, transactions } = await res.json();
console.log(data.bankName);
console.log(transactions);
python
import requests

with open('statement.pdf', 'rb') as f:
    pdf_bytes = f.read()

response = requests.post(
    'https://api.bankflow.app/api/v1/parse',
    headers={
        'Authorization': 'Bearer bnfw_your_api_key_here',
        'Content-Type': 'application/pdf',
    },
    data=pdf_bytes,
)

body = response.json()
print(body['data']['bankName'])
for txn in body['transactions']:
    print(txn['date'], txn['description'], txn['amount'], txn['type'])

Example response

json
{
  "data": {
    "id": 1042,
    "fileName": "statement.pdf",
    "status": "completed",
    "bankName": "Bank of America",
    "currency": "USD",
    "transactionCount": 2,
    "openingBalance": 25000.00,
    "closingBalance": 109550.00
  },
  "transactions": [
    {
      "id": 90211,
      "date": "2024-01-03",
      "description": "UPI/SWIGGY/Food Order",
      "amount": 450.00,
      "type": "debit",
      "category": "Food & Dining",
      "tags": [],
      "balance": 24550.00
    },
    {
      "id": 90212,
      "date": "2024-01-05",
      "description": "SALARY CREDIT",
      "amount": 85000.00,
      "type": "credit",
      "category": "Income",
      "tags": [],
      "balance": 109550.00
    }
  ]
}

Statements

Upload, inspect, delete, analyze, and export parsed statements.

GET/api/v1/statementsList statements

Returns paginated statements with processing status, bank, source, and transaction count.

Query

page, limit

status=processing|completed|failed

search, from, to

Response

{ data: Statement[], pagination }

POST/api/v1/statementsUpload and persist a statement

Accepts multipart form-data (field file), or raw file bytes with an X-File-Name header: PDF, CSV, XLSX, or JSON. Parses synchronously and stores the statement plus transactions. Add ?include=transactions to embed the parsed transactions in the response.

Body

multipart/form-data → file

raw bytes (application/pdf or application/octet-stream)

Query

include=transactions → embed parsed transactions inline

Headers

X-File-Name (raw uploads)

X-PDF-Password (encrypted PDFs)

X-Column-Mapping (CSV/XLSX)

Non-ASCII header values: send raw UTF-8, or percent-encode and add <header>-Encoding: url

Limits

Max 50MB per file

POST/api/v1/parseParse and return transactions

One-shot parse: POST a PDF (or CSV/XLSX/JSON file) and get the parsed transactions back inline, alongside the persisted statement, no follow-up call. Same auth, limits, and credit cost as the upload endpoint.

Body

multipart/form-data → file

application/pdf raw body

Response

{ data: StatementDetail, transactions: Transaction[] }

POST/api/v1/statements/detect-columnsPreview & auto-detect columns

For CSV/XLSX uploads: returns the auto-detected column mapping along with the file's headers and a sample of rows, so you can confirm or override the mapping before importing. Nothing is persisted.

Body

multipart/form-data → file

raw bytes + X-File-Name header

Response

{ data: { headers, sampleRows, rowCount, mapping, detectionSource, confident } }

GET/api/v1/statements/:idGet statement details

Fetches one statement with processing status, balances, period, and metadata.

Path

:id = statement id

Response

{ data: StatementDetail }

DELETE/api/v1/statements/:idDelete a statement

Deletes the statement and all associated transactions.

Path

:id = statement id

Response

{ success: true }

GET/api/v1/statements/:id/transactionsList statement transactions

Returns paginated transactions for a single statement with category, type, search, and date filters.

Query

page, limit

category, type

search, from, to

Response

{ data: Transaction[], pagination }

GET/api/v1/statements/:id/insightsGet financial insights

Computes income, expenses, savings, top categories, recurring payments, salary detection, and monthly cashflow.

Path

:id = statement id

Response

{ data: Insights }

GET/api/v1/statements/:id/exportExport a statement

Exports one statement as JSON, CSV, or XLSX with optional filters.

Query

format=json|csv|xlsx

category, type

search, from, to

Response

JSON envelope or file download

Transactions

Import transactions directly from structured data, and correct stored transaction metadata.

POST/api/v1/transactions/bulkImport transactions directly

Imports a canonical JSON transactions payload, no source file needed. Send a raw array of transactions, or an object with statement metadata and a transactions array. Creates a statement to hold them and runs the same persist pipeline as a file upload (costs 1 credit).

Body

Transaction[]

or { bankName?, currency?, openingBalance?, closingBalance?, transactions: Transaction[] }

Transaction → { date, description?, amount? | debit?/credit?, type?, balance? }

Response

201 { data: Statement }

PATCH/api/v1/transactions/:idUpdate transaction metadata

Updates category, notes, and tags for a stored transaction.

Body

{ category?, notes?, tags?: string[] }

Response

{ success: true }

Webhooks

Events BankFlow delivers to endpoints you register. Each delivery is a POST with body { "event", "data" } and an X-BankFlow-Signature: sha256=<hmac> header: an HMAC-SHA256 of the raw body, keyed with your webhook secret. Verify it before trusting a payload. Deliveries are single-attempt; failures are logged and can be replayed.

statement.completed

A statement finished parsing and its transactions are stored (lightweight, no transaction data).

data

{ statementId, fileName, transactionCount, bankName }

transactions.created

A statement finished importing: carries the full parsed transactions inline. Fires on every import (API upload, queued upload, Gmail auto-import), so it's how async flows receive their transactions.

data

{ statementId, bankName, transactionCount, transactions: Transaction[] }

statement.failed

A statement could not be parsed. No statementId, nothing was stored; correlate by fileName.

data

{ fileName, error }

statement.deleted

A statement (and its transactions) was deleted.

data

{ statementId, fileName }

transaction.updated

A single transaction was edited (category/notes/tags). Does not fire on import.

data

{ transactionId, statementId, category }

Webhook management

Endpoints to register, list, and delete webhook endpoints. For the events you receive and their payloads, see the Webhooks section above.

GET/api/v1/webhooksList registered webhooks

Returns every webhook endpoint registered for your API key owner.

Response

{ data: Webhook[] }

POST/api/v1/webhooksRegister a webhook

Creates a webhook endpoint and returns the generated signing secret once.

Body

{ url: string, events: string[] }

Response

{ data: { id, url, events, secret } }

POST/api/v1/webhooks/:id/rotateRotate signing secret

Generates a fresh signing secret for the endpoint and returns it once. The previous secret stops validating immediately, so update your verifier in the same step.

Path

:id = webhook id

Response

{ data: { id, url, events, secret } }

DELETE/api/v1/webhooks/:idDelete a webhook

Removes a registered webhook endpoint.

Path

:id = webhook id

Response

{ success: true }

OpenAPI

Machine-readable API specification for tooling and Swagger-style docs.

GET/api/v1/openapi.jsonRaw OpenAPI 3.0 spec

Returns the complete BankFlow v1 OpenAPI document as JSON.

Use cases

Swagger UI

SDK generation

Schema inspection

Response

OpenAPI 3.0.3 JSON document

Need the machine-readable spec?

The full OpenAPI 3.0 document is available at https://api.bankflow.app/api/v1/openapi.json for Swagger UI and SDK generation.