Introduction
The FlowParse API lets you run the platform's deterministic validation engine and export engine from your own code. Send extracted invoice or bank-statement data as JSON; get back a validated quality score or a ready-to-import file. Everything you can do in the app is available here: extraction from a PDF, the quality score, Excel/CSV/XML export, and import files for 14 accounting packages — Xero, QuickBooks, Sage, DATEV, Zoho Books, NetSuite, MYOB, Wave, FreshBooks, FreeAgent, the OFX/QBO/QFX bank-file family and 1С.
Validate
Quality Score + every check
Export
Excel · CSV · XML
Accounting
Xero · QuickBooks · Sage · DATEV · +10
Reconcile
Match invoices ↔ transactions
Smart Merge
100 docs → one workbook
Authentication
All requests require an API key sent as a Bearer token. Get a key in one click, or manage existing keys in your dashboard → API tab. The full key (pf_live_…) is shown only once at creation — store it securely. You can also pass it as X-API-Key.
Authorization: Bearer pf_live_xxxxxxxxxxxxxxxxxxxxKeys are stored as SHA-256 hashes — FlowParse never stores your plaintext key. Revoke a compromised key instantly from the dashboard.
Pricing & billing
€0.035 per page — flat, for every document, whatever it takes to process. No range to estimate, no complexity multiplier: a page is a page, and that is what a top-up converts euros into pages at, too.
Every /extract response carries a priceobject — what the document came to and what that worked out at per page — so you can reconcile spend without estimating. API usage draws from its own balance — top-up pages, which never expire — separate from your account's monthly site-plan pages, which the API never spends.
A document is charged once. /extract bills the pages it read, and asking it for a file in the same call — "export": { "format": "xlsx" } — costs nothing extra, in any number of formats. Calling /export on its own bills per page, because that data was never extracted here. /validate, /reconcile, /usage and accounting previews are free, and a document we cannot convert is never billed.
curl https://flowparse.io/api/v1/usage \
-H "Authorization: Bearer pf_live_xxx"
# → { "plan":"PRO", "pricePerPageEur":0.035,
# "balance": { "pages":812, "monthlyRemaining":712, "bonusPages":100 },
# "thisMonth": { "requests":143, "pages":288, "spendEur":8.18 } }curl -X POST https://flowparse.io/api/v1/topup \
-H "Authorization: Bearer pf_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "eur": 25, "successUrl": "https://your-app.com/billing/done" }'
# → { "url":"https://checkout.stripe.com/c/pay/cs_live_…", "pages":880,
# "amountEur":25, "creditedOn":"payment_confirmed" }
# Send your user to `url`; the pages land the moment Stripe confirms the payment.Add funds to your balance
Bonus pages never expire and are used after your monthly budget.
GET /usage
Balance, plan, allowance and month-to-date spend, broken down per key and per day. Free, and it keeps answering after your pages run out — so your own code can decide whether to process, queue or top up before it sends a document.
curl https://flowparse.io/api/v1/usage \
-H "Authorization: Bearer pf_live_xxx"
# → { "plan":"PRO", "pricePerPageEur":0.035,
# "balance": { "pages":812, "monthlyRemaining":712, "bonusPages":100 },
# "thisMonth": { "requests":143, "pages":288, "spendEur":8.18 } }POST /topup
Buy pages from inside your own application. Send eur for a custom amount (€5–€5000) or pages for a fixed pack, optionally with your own successUrl and cancelUrl. You get a Stripe Checkout link; the pages are credited when the payment settles, never before. Card details never touch your servers or ours. GET /topup returns the same catalogue without starting a payment.
curl -X POST https://flowparse.io/api/v1/topup \
-H "Authorization: Bearer pf_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "eur": 25, "successUrl": "https://your-app.com/billing/done" }'
# → { "url":"https://checkout.stripe.com/c/pay/cs_live_…", "pages":880,
# "amountEur":25, "creditedOn":"payment_confirmed" }
# Send your user to `url`; the pages land the moment Stripe confirms the payment.Data model
Every request describes a document via type plus its data.
// Invoice
{ "type": "invoice", "data": { /* invoice fields */ } }
// Bank statement
{ "type": "bank_statement", "data": { /* statement fields */ } }
// Mixed (both on one document)
{ "type": "mixed", "invoice": { ... }, "bank_statement": { ... } }{
"supplier_name": "string", "supplier_address": "string",
"customer_name": "string", "customer_address": "string",
"invoice_number": "string", "invoice_date": "YYYY-MM-DD",
"due_date": "YYYY-MM-DD", "vat_number": "string",
"currency": "EUR",
"subtotal": 100.0, "tax_amount": 19.0, "total": 119.0,
"line_items": [
{ "description": "string", "quantity": 1, "unit_price": 0,
"tax_rate": 19, "amount": 0 }
]
}{
"bank_name": "string", "account_holder": "string",
"account_number_masked": "string", "statement_period": "string",
"currency": "EUR", "opening_balance": 0.0, "closing_balance": 0.0,
"transactions": [
{ "date": "YYYY-MM-DD", "description": "string",
"category": "string", "amount": -12.50, "balance": 0.0 }
]
}POST /extract
Convert a document into structured JSON in one call. Send a PDF, scanned image (PNG/JPG), XLSX or CSV as base64 in the file field (with an optional filename); the same AI pipeline the FlowParse workspace uses classifies the document, reads digital text geometry, OCRs scanned pages, and returns the typed data schema below. Billed per page; a not-convertible document is free. The output is the exact payload the /validate, /export and /reconcile endpoints accept.
curl -X POST https://flowparse.io/api/v1/extract \
-H "Authorization: Bearer pf_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "file": "JVBERi0xLjcK...", "filename": "october.pdf" }'
# → { "type":"bank_statement", "pages":4, "billedPages":4,
# "price": { "eur":0.14, "perPageEur":0.035, "complexity":"standard" },
# "data": { "type":"bank_statement", "data": { "transactions":[ ... ], ... } } }Add "validate": true for the quality score the workspace shows, and "export" to get the finished file back in the same response. Both are free — the extraction is the only thing billed.
curl -X POST https://flowparse.io/api/v1/extract \
-H "Authorization: Bearer pf_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "file": "JVBERi0xLjcK...", "filename": "october.pdf",
"validate": true, "export": { "format": "xero" } }'
# One charge: the extraction. Returns data + quality score + the Xero import file.POST /validate
Runs the deterministic validation engine (12 invoice + 8 bank checks). Returns a 0–100 Quality Score, grade (green/yellow/red), every check and a summary.
curl -X POST https://flowparse.io/api/v1/validate \
-H "Authorization: Bearer pf_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"type": "invoice",
"data": {
"supplier_name": "Acme Ltd",
"invoice_number": "INV-1024",
"invoice_date": "2026-05-01",
"currency": "EUR",
"subtotal": 100.00,
"tax_amount": 19.00,
"total": 119.00,
"line_items": [
{ "description": "Widget", "quantity": 2, "unit_price": 50, "tax_rate": 19, "amount": 100 }
]
}
}'{
"validations": [
{
"documentType": "invoice",
"score": { "value": 98, "grade": "green" },
"summary": { "passed": 11, "warnings": 1, "errors": 0 },
"issues": [ { "severity": "pass", "title": "Totals reconcile", ... } ]
}
]
}POST /export
Generates a file in the requested format. Spreadsheet formats return text (CSV/XML) or base64 (XLSX); accounting formats also include a preview of the mapped columns and rows.
| format | Target | Output |
|---|---|---|
xlsx | Excel | Styled multi-sheet workbook (base64) |
csv | CSV | UTF-8, 1:1 source columns + line items |
xml | XML | Structured invoice / statement XML |
sheets | Google SheetsNEW | JSON grid — every field, 1 row/line-item |
xero | Xero | Bills & sales invoices CSV |
quickbooks | QuickBooks | Import-ready CSV (plus .QBO bank files) |
sage | Sage | Sage 50 invoice & transaction CSV |
datev | DATEV | EXTF Buchungsstapel |
… | 10 moreSEE BELOW | Zoho Books, NetSuite, MYOB, Wave, FreshBooks, FreeAgent, OFX/QBO/QFX, 1С |
curl -X POST https://flowparse.io/api/v1/export \
-H "Authorization: Bearer pf_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "format": "xlsx", "type": "invoice", "data": { ... } }'
# → { "format":"xlsx", "filename":"...", "encoding":"base64", "content":"UEsDBB..." }Accounting exports
Set format to any target below and you get the import file that package expects — not a generic CSV you have to reshape. Each response also carries a preview of the mapping. GET /export returns this list at runtime, so a client never has to hard-code it.
| format | Package | What you get | File |
|---|---|---|---|
xero | Xero | Xero bills & invoices CSV | .csv |
quickbooks | QuickBooks | QuickBooks-ready CSV import | .csv |
sage | Sage | Sage 50 invoice & transaction CSV | .csv |
datev | DATEV | DATEV EXTF Buchungsstapel | .csv |
zoho | Zoho Books | Zoho Books invoice import CSV | .csv |
netsuite | NetSuite | NetSuite CSV import | .csv |
myob | MYOB | MYOB sales import CSV | .csv |
freshbooks | FreshBooks | FreshBooks transactions CSV | .csv |
freeagent | FreeAgent | FreeAgent bank statement CSV | .csv |
wave | Wave | Wave bank/transaction CSV | .csv |
qbo | QuickBooks (.QBO) | QuickBooks Web Connect bank file | .qbo |
qfx | Quicken (.QFX) | Quicken Web Connect bank file | .qfx |
ofx | OFX | Open Financial Exchange bank file | .ofx |
onec | 1С | 1С exchange format | .txt |
Mapping defaults are sensible but never silent: pass options to set the Xero account code and tax type or the invoice direction (xeroMode: bills or sales invoices), the DATEV consultant, client and SKR accounts, or the 1С account and organisation — and onecLanguage when you need 1С output in a particular language. Whatever you override comes back in the preview, so the mapping is visible before anything is imported.
curl -X POST https://flowparse.io/api/v1/export \
-H "Authorization: Bearer pf_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "format": "xero", "type": "invoice", "data": { ... },
"options": { "xeroMode": "ACCPAY", "accountCode": "400", "xeroTaxType": "Tax Exclusive" } }'
# → { "format":"xero", "filename":"xero-invoices.csv", "encoding":"utf-8",
# "content":"ContactName,InvoiceNumber,InvoiceDate,DueDate,Description,…",
# "preview": { "columns":[...], "rows":[...], "notes":[...] } }curl -X POST https://flowparse.io/api/v1/export \
-H "Authorization: Bearer pf_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "format": "quickbooks", "type": "invoice", "data": { ... } }'Accounting preview
Add "preview": true to any accounting export — Xero, QuickBooks, Sage, DATEV, any of them — to get back just the mapped table (columns, first rows, total count and mapping notes) without generating the file. Ideal for a confirmation screen before import, and free.
curl -X POST https://flowparse.io/api/v1/export \
-H "Authorization: Bearer pf_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "format": "xero", "preview": true, "type": "invoice", "data": { ... } }'
# → free. { "format":"xero", "preview": { "columns":[...], "rows":[...], "totalRows":1 } }curl -X POST https://flowparse.io/api/v1/export \
-H "Authorization: Bearer pf_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "format": "onec", "preview": true, "onecLanguage": "ru", "type": "invoice", "data": { ... } }'
# → { "format":"onec", "preview": { "columns":[...], "rows":[...], "totalRows": 1, "notes":[...] } }The preview mirrors the app's in-product preview exactly, so what you show your users is what imports.
POST /reconcile
Matches each invoice to your bank transactions and returns an Invoice Status Report — paid, unpaid, partial, duplicate or mismatch — with a confidence score per match. Pass invoices plus either transactions (array) or a bank_statement object. Analysis is free and tracked per key like validation.
curl -X POST https://flowparse.io/api/v1/reconcile \
-H "Authorization: Bearer pf_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"invoices": [
{ "supplier_name": "Acme Ltd", "invoice_number": "INV-1024",
"total": 119.00, "currency": "EUR", "invoice_date": "2026-05-01" }
],
"transactions": [
{ "date": "2026-05-03", "description": "ACME LTD INV-1024", "amount": -119.00 }
]
}'
# → { "report": {
# "summary": { "totalInvoices":1, "matched":1, "unpaid":0, "duplicate":0,
# "mismatch":0, "partial":0, "unmatchedTransactions":0 },
# "invoices": [ { "status":"paid", "confidence":0.98, "matches":[...] } ],
# "unmatched": [], "currency":"EUR", "generatedAt":"..." } }POST /merge NEW
Smart Merge consolidates 2–100 already-extracted documents into one Excel workbook: invoices become an Invoice Register (one row per document) and bank statements become a unified Transactions sheet whose columns are matched across different bank formats (e.g. Transaction Date, Datum and Date collapse into one column). Every source row is preserved 1:1 — the response summary returns transactionRows and sourceTransactionRows so you can assert no row was dropped.
| Field | Type | Notes |
|---|---|---|
documents | array (2–100) | Each item is a validate/export-shaped document (type + data), with an optional fileName. |
preview | boolean | When true, returns the summary + a 20-row peek per sheet, with no file. Free. |
curl -X POST https://flowparse.io/api/v1/merge \
-H "Authorization: Bearer pf_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"documents": [
{ "fileName": "jan.pdf", "type": "bank_statement", "data": { ... } },
{ "fileName": "feb.pdf", "type": "bank_statement", "data": { ... } },
{ "fileName": "acme-invoice.pdf", "type": "invoice", "data": { ... } }
]
}'
# → { "format":"xlsx", "filename":"smart-merge-2026-06-17.xlsx",
# "encoding":"base64", "content":"UEsDBB...",
# "summary": { "fileCount":3, "transactionRows":842, "sourceTransactionRows":842,
# "schemaGroups":2, "currencies":["USD"], ... }, "billedPages": 9 }curl -X POST https://flowparse.io/api/v1/merge \
-H "Authorization: Bearer pf_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "preview": true, "documents": [ { "type":"bank_statement", "data":{...} }, ... ] }'
# → free. { "summary": {...}, "sheets": [ { "name":"Transactions", "columns":[...],
# "rowCount":842, "sampleRows":[...] } ], "billedPages": 0 }Billed per page summed across all documents; the free preview lets you check the merged schema and row count before you spend pages.
Code examples
Node.js
const res = await fetch("https://flowparse.io/api/v1/export", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.FLOWPARSE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ format: "xero", type: "invoice", data: invoice }),
})
const { content, filename } = await res.json()
require("fs").writeFileSync(filename, content, "utf8")Python
import os, base64, requests
r = requests.post(
"https://flowparse.io/api/v1/export",
headers={"Authorization": f"Bearer {os.environ['FLOWPARSE_API_KEY']}"},
json={"format": "xlsx", "type": "bank_statement", "data": statement},
)
out = r.json()
with open(out["filename"], "wb") as f:
f.write(base64.b64decode(out["content"])) # xlsx is base64Errors
Errors return a JSON body { "error": "message" } with a standard HTTP status.
Bad Request
Malformed body, missing data, unsupported format, or fewer than 2 documents for /merge.
Unauthorized
Missing, invalid or revoked API key.
Unprocessable
No mergeable / reconcilable data in the supplied documents.
Too Many Requests
Page balance exhausted — top up to continue.
Server Error
Unexpected error generating the response.
Rate limits
Throughput is governed by your page balance rather than a fixed request cap. If your top-up pages are exhausted, requests that consume pages return 429 until you top up. Validation of already-extracted JSON is free.
Ready to build? Generate your first key in one click.
Get API key