What a PDF to Excel API gives you
A PDF to Excel API does in code what a converter does in a browser: it takes a PDF and returns a spreadsheet. The reason to want it as an API rather than a web page is repetition. If the same thirty statements arrive on the same day every month, or every customer of your product uploads documents you need as tables, a person clicking Convert is the bottleneck — and the one part of the process that gets skipped when everyone is busy.
FlowParse splits the job into two calls that you can use together or separately. `POST /api/v1/extract` reads the document and returns structured JSON. `POST /api/v1/export` takes that JSON and returns a finished `.xlsx` as base64, along with CSV, XML and accounting formats if you want them instead. Splitting it this way means you can inspect, correct or enrich the data between reading and writing, which a single black-box convert call would never let you do.
What comes back is a real workbook rather than a CSV renamed. Columns are sized to their actual content, numbers are stored as numbers so Excel will sum them, dates are real dates, and every column the source document printed is preserved rather than reduced to a tidy subset somebody assumed you wanted.
PDF in, spreadsheet out
Two calls. Extract the document, then export the result as XLSX. The export response carries the file base64-encoded in `file`, which you write to disk, stream to your user or attach to an email. Create a key at get an API key.
# 1 — read the document
curl -X POST https://flowparse.io/api/v1/extract \
-H "Authorization: Bearer pf_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "file": "JVBERi0xLjcK...", "filename": "statement.pdf" }'
# 2 — turn the result into a workbook
curl -X POST https://flowparse.io/api/v1/export \
-H "Authorization: Bearer pf_live_xxx" \
-d '{ "format": "xlsx", "type": "bank_statement", "data": { ... } }'
# → { "filename": "statement.xlsx", "file": "UEsDBBQABgAI..." }Every output the export endpoint produces
Excel is the common request, but the same endpoint produces the other formats a finance pipeline needs — which matters because the answer to 'can you also give me a QuickBooks file' should not require a second vendor.
| Format | What you get | Typical use |
|---|---|---|
| xlsx | Multi-sheet Excel workbook with sized columns | Analysis, hand-off to a client or accountant |
| csv | Flat comma-separated file | Loading into a database or another tool |
| xml | Structured XML | Legacy system imports |
| qbo / qfx / ofx | Real bank-feed files | Direct import into QuickBooks or Quicken |
| xero / datev / 1c | Accounting-specific layouts | Posting into a ledger without re-keying |
Why PDF tables are hard, and what we do about it
A PDF does not contain a table. It contains characters positioned at coordinates, and the grid you see is an illusion your eye assembles. That is why naive extraction produces garbage: pull the text out in reading order and a two-line description fuses with the row beneath it, a right-aligned amount gets captured by the column to its left, and a table continued across a page break becomes two unrelated fragments.
The engine reconstructs structure from geometry. It uses the position of every text run to work out where columns actually begin and end, keeps a wrapped cell attached to its own row, stitches tables that continue over page breaks, and drops the summary boxes and legal prose that are not part of the table at all. Where a document has no text layer — a scan or a photo — OCR runs first and the same reconstruction is applied to the recognised text.
The result is that the spreadsheet has the columns the document had, in the order the document had them. If the source printed a reference number and a value date you never asked about, they are still there. Nothing is quietly dropped on the assumption that you did not want it.
What makes the output a usable workbook
There is a real difference between a file Excel will open and a file somebody can work in. Numbers are written as numbers, not as text that looks like a number — so SUM works immediately rather than returning zero and sending the recipient hunting for the reason. Dates are real dates, so sorting is chronological rather than alphabetical. Column widths are measured against the actual content, so nothing arrives as a column of `#####` that must be widened by hand.
For bank statements the workbook carries more than the transaction grid: the source table exactly as printed, plus quality and summary information so the recipient can see the extraction was checked rather than take it on faith. That is the same output as bank statement to Excel in the browser — the API does not give you a lesser version of the product.
What you can convert
The extraction step classifies the document, so one integration handles the mix of files that actually arrives rather than requiring you to route by type first. The response `type` tells you what was found, which is also what you pass to the export call.
| Document | What the sheet contains | Dedicated page |
|---|---|---|
| Bank statement | Transactions, balances, account header, raw source table | bank statement API |
| Invoice | Header fields plus a row per line item | invoice parsing API |
| Receipt | Merchant, date, totals and items | receipt OCR API |
| Scanned PDF or photo | Same as above, via OCR | bank statement OCR API |
| XLSX / CSV input | Re-read, validated and re-exported cleanly | PDF to Excel |
Build the whole thing before paying for it
Export supports `preview: true`, which returns the structure of what you would get — sheets, columns, row counts — without producing the billed file. That is deliberately generous, because the part of an integration that takes the longest is not the happy path, it is discovering that your column mapping was wrong after you already spent your budget finding out.
The practical sequence is to extract a handful of representative documents once, keep the JSON as fixtures, and then develop your export mapping entirely against previews and stored responses. Your tests run offline, deterministically and for free, and you switch on billed exports only when the pipeline behaves.
curl -X POST https://flowparse.io/api/v1/export \
-H "Authorization: Bearer pf_live_xxx" \
-d '{ "format": "xlsx", "preview": true, "type": "bank_statement", "data": { ... } }'
# → { "preview": true, "sheets": [ { "name": "Transactions", "columns": [...], "rows": 143 } ] }The shape of a working integration
Ingest
Pick documents up from a mailbox, an upload form, S3 or a cloud folder.
Extract
POST each file to /api/v1/extract and keep the returned JSON.
Validate
Score it with /api/v1/validate; hold anything that fails for review before it becomes a file.
Export
POST the accepted data to /api/v1/export with format xlsx and decode the base64.
Deliver
Write the workbook to storage, email it, or push it into the destination system.
Do not export something you have not checked
The temptation with a conversion API is to pipe extract straight into export and ship the file. Resist it. A spreadsheet is a confident artefact — once a number is in a cell, nobody downstream questions it, and an extraction that dropped four rows looks exactly like one that did not.
`POST /api/v1/validate` is free and takes one call. For bank statements it checks the extraction against the statement's own arithmetic: opening balance plus every transaction must equal the closing balance the bank printed. For invoices it checks line amounts against the subtotal and subtotal plus tax against the total. Gate the export on that result and a broken conversion fails loudly instead of becoming a plausible-looking workbook. The full rule set is on the validation engine.
Twelve statements, one workbook
Converting files one at a time gives you a folder of workbooks, which is rarely what anyone actually wanted. More often the goal is a year of statements as a single sheet you can sort and total, or a month of invoices as one register. `POST /api/v1/merge` does exactly that: send up to 100 extracted documents and get one consolidated Excel back, with columns matched across documents that do not agree on naming.
This is the API side of Smart Merge, and it is deterministic rather than AI-driven, so the same inputs always produce the same workbook. Previews are free here too, so you can check the consolidated column layout before spending anything. For the browser equivalent, combine bank statements into one Excel covers the same job.
Calling it from any language
There is no SDK and no language constraint — JSON over HTTPS, so `requests` in Python, `fetch` in Node, `HttpClient` in .NET or plain curl in a shell script all work identically. The only slightly awkward part is base64: you encode the PDF going in and decode the workbook coming out, which is two lines in every language and avoids the multipart handling that trips up so many file APIs.
In Python that is `base64.b64encode(open(path,'rb').read()).decode()` on the way in and `open(out,'wb').write(base64.b64decode(resp['file']))` on the way out. In Node it is `Buffer.from(buf).toString('base64')` and `Buffer.from(resp.file,'base64')`. Everything else is an ordinary HTTP POST with a bearer token.
Converting hundreds of files
Extract each document as its own request and run them in parallel across a worker pool rather than assembling one enormous call. Per-document requests are independently retryable, one corrupt file cannot fail the batch, and you can back off on a single failure without losing the work already done.
Two guardrails matter at volume. Cap worker concurrency, because an uncapped pool will happily drain a month's page budget in a few minutes if something loops. And make jobs idempotent on a file hash so a retry produces the same workbook rather than a second one — a duplicated conversion is harmless, a duplicated ledger import is not. Log the billed pages per document so cost is attributable rather than a single monthly surprise.
Status codes and how to handle them
The codes are ordinary HTTP and the billing rules are simple: you are never billed for a document that produced nothing. Handle 429 by pausing your queue rather than retrying in a loop — retrying a budget error just burns requests without ever succeeding.
| Code | Meaning | What to do |
|---|---|---|
| 200 | Converted successfully | Decode `file` and write the workbook |
| 400 | Bad request or malformed base64 | Fix the payload; do not retry unchanged |
| 401 | Invalid or missing key | Check Authorization; rotate if leaked |
| 422 | Nothing extractable (not billed) | Send a cleaner scan or the digital original |
| 429 | Page budget exhausted | Pause the queue, top up, resume |
| 503 | Temporarily unavailable | Exponential backoff |
What each call costs
Extraction and produced files bill per page from your page balance. Validation, reconciliation and export previews cost nothing, which is what makes it realistic to build and test the entire pipeline before enabling billed calls. Plans and allowances are on the pricing page; per-key request counts, pages and cost are in the dashboard.
| Call | Endpoint | Billing |
|---|---|---|
| Read the PDF | POST /api/v1/extract | Per page |
| Produce the workbook | POST /api/v1/export | Per page |
| Preview the workbook structure | POST /api/v1/export (preview) | Free |
| Validate before exporting | POST /api/v1/validate | Free |
| Merge many into one | POST /api/v1/merge | Per page (preview free) |
What people automate with it
Accounting practices
Convert every client's monthly statements overnight so the workbooks are waiting in the morning.
Lending & underwriting
Turn applicant statements into analysable sheets the moment an application is submitted.
Vertical SaaS
Let customers upload a PDF inside your product and hand back a spreadsheet without building extraction yourself.
Internal finance ops
Replace the recurring manual convert-and-tidy job that quietly eats a day every month.
Why not just use a PDF library
The honest comparison is against writing it yourself with an open-source PDF library, because that is the real alternative and it is free. For a single, stable, digitally generated layout it is a perfectly reasonable choice — extract the text positions, group them into columns, write a spreadsheet, done in an afternoon.
What it does not survive is variety. A library gives you text and coordinates; deciding which runs form a table, which column an amount belongs to, how to stitch a table across a page break, and what to do when the PDF is a scan with no text layer at all is the actual work, and it grows with every new bank or supplier your users send. The second thing a library cannot give you is a correctness check — nothing in it will tell you the extraction dropped four transactions, whereas a balance check will. Choose a library when the input is narrow and stable; choose an API when it is not, or when being wrong quietly is expensive.
Deciding what ends up in the sheet
By default the export preserves every column the source document contained, because the alternative — guessing which fields matter — is how information quietly disappears. The extracted `raw_table` holds the source exactly as printed, and that is what the workbook mirrors.
When you need a fixed layout instead, do the shaping between the two calls rather than asking the export to guess. Extract, transform the JSON into exactly the columns your destination expects, then export that. Because the two steps are separate endpoints, this is a plain data transformation in your own code with your own rules, testable in isolation — not a configuration screen you have to reverse-engineer.
When a spreadsheet is not the real goal
Quite often Excel is a staging post rather than the destination — the file exists because somebody will retype it into an accounting system. If that is your case, skip the spreadsheet: the same export endpoint produces real bank-feed files (`.qbo`, `.qfx`, `.ofx`) that QuickBooks and Quicken import directly, and ledger-specific layouts for Xero, DATEV and 1С.
That removes the most error-prone step in the chain, which is a human copying numbers between two windows. See PDF to QBO for the QuickBooks path and bank statement to Xero for the Xero one; both describe the same conversion the API performs.
Handling the documents responsibly
Bank statements and invoices are among the most sensitive files a business holds. Requests travel over HTTPS, API keys are stored hashed and can be rotated or revoked per environment, and uploaded files are processed to produce the response rather than retained as downloadable documents. Nothing is used to train models.
The failure mode we see most often is on the integrator's side rather than the API's: documents and extracted JSON ending up in application logs, where they are far less protected than the systems everyone is careful about. Keep both out of logs, store only what your process needs, and give staging its own key so a leak in a test environment never touches production. The security page documents the platform side.
Getting spreadsheets without writing an integration
The whole flow works from an automation platform if you would rather not maintain code. Zapier, Make and n8n can each base64-encode a file, call both endpoints and drop the resulting workbook into Drive, SharePoint or an email — the integration pages walk through the specific modules each platform uses.
For genuinely occasional work, no automation is the right answer at all: PDF to Excel converts in the browser and batch processing handles a folder at a time. An API earns its keep when the same conversion happens on a schedule, not when it happens twice a year.
Knowing your pipeline still works
A conversion pipeline fails quietly. Nobody notices that four transactions went missing from a workbook; they notice a reconciliation that will not balance three weeks later. The cheapest insurance is to log the validation result with every conversion and alert on the rate of failures rather than on individual ones, since a single odd document is normal and a trend is not.
Watch the 422 rate for the same reason — a rising share of unreadable files usually means an upstream change, such as a client switching to photographing statements instead of downloading them. On cost, per-key usage in the dashboard tells you which integration is consuming the budget, which is the question you will actually be asked when the monthly number moves.
How to run this well
Keep extract and export as separate steps even when you do not need anything in between, because the day you do need to correct or enrich a value, the seam is already there. Validate before exporting, always. Store the extraction JSON alongside the produced file so you can regenerate the workbook in a different format later without paying to read the document again.
Operationally: queue rather than converting inline on a web request, cap concurrency, make jobs idempotent on a file hash, pause on 429 and back off on 503, and keep documents out of logs. Prefer digital originals over scans whenever the sender can provide them — a text layer is read exactly, a scan is recognised, and that difference costs nothing to eliminate at the source.
Where to go next
For JSON rather than a file, see the PDF to JSON API. For document-type specifics, the invoice parsing API, the receipt OCR API and the bank statement API each go deeper on their own schema, and the document extraction API covers all of them at once. The complete reference is at /api-docs, and the guide to parsing bank statements with an API walks a full integration end to end.
Convert PDFs to spreadsheets in code
Two calls: read the document, get a finished workbook back — validated, with every source column preserved.
