Multipart request. Returns 200 with a completed Job for small files, or 202 with a queued Job to poll. Maximum 20 files per request, 25 MB each.
Field
Type
Required
Description
files
file[]
required
Repeatable PDF part. One entry per statement.
password
string
optional
Password for encrypted PDFs. Applies to every file in the request.
GET/jobs/{job_id}
Fetch job state.
Poll until status is completed, failed or needs_password. Documents appear in the array as they finish, so partial results are readable while the rest are still parsing.
Field
Type
Required
Description
job_id
string
required
Identifier returned by POST /convert.
POST/jobs/{job_id}/unlock
Supply the password for an encrypted document.
Retries the locked documents of an existing job in place. The job id and every document id are preserved, so edits already made to other files in the batch survive. 200 if anything unlocked, 401 if the password was wrong (the document stays needs_password and is retryable), 409 if nothing is locked.
Field
Type
Required
Description
password
string
required
The PDF password to try.
document_id
string
optional
Unlock one document. Omit to try the password on every locked document — a batch may carry files with different passwords.
GET/jobs/{job_id}/documents/{doc_id}/download
Stream the converted file as parsed.
Responds with the file body and Content-Disposition: attachment. Use this when the client has made no edits.
Field
Type
Required
Description
format
enum
required
One of csv, xlsx, json, ofx. Query parameter.
columns
string
optional
Comma-separated field list, in order — for example date,description,debit,credit,balance. Omit for the statement’s own layout.
GET/jobs/{job_id}/download
Download every statement in the job at once.
mode=combined merges the batch into one file carrying Source and Account columns — and, for XLSX, a Summary sheet with each statement’s totals and balance check. mode=zip returns an archive of the individual files instead.
Field
Type
Required
Description
format
enum
required
One of csv, xlsx, json, ofx.
mode
enum
optional
combined (default) or zip.
columns
string
optional
Comma-separated field list, as on the single download.
POST/jobs/{job_id}/documents/{doc_id}/export
Re-export using client-edited rows.
Send the corrected transaction array back and the file is rendered from those rows instead of the original extraction. Streams the file the same way download does.
Field
Type
Required
Description
format
enum
required
One of csv, xlsx, json, ofx.
transactions
Transaction[]
optional
The full, edited row set to render. Omit to re-export the stored rows — which is how a pure column re-map avoids resending every row.
columns
Column[]
optional
Column layout as { field, header? } objects, in order. Unlike the query-string form, this carries renamed headings.
GET/quota
Remaining allowance for the caller.
Anonymous callers are identified by IP. Metered in pages, not files, on a rolling window. Returns used, limit, remaining and resets_at — an ISO timestamp. A 429 also carries a Retry-After header in seconds.
GET/health
Liveness probe.
Returns status and the deployed version string.
Polling a job
A job is terminal once its status is completed, failed or needs_password. Poll about once a
second; documents populate incrementally.
JavaScript
const created = await fetch(`${BASE}/convert`, {
method: 'POST',
body: form
}).then((r) => r.json());
let job = created;
while (!['completed', 'failed', 'needs_password'].includes(job.status)) {
await new Promise((r) => setTimeout(r, 1200));
job = await fetch(`${BASE}/jobs/${job.job_id}`).then((r) => r.json());
}
const doc = job.documents[0];
const file = await fetch(
`${BASE}/jobs/${job.job_id}/documents/${doc.id}/download?format=csv`
).then((r) => r.blob());
Column layouts
A statement has one natural shape, but the file you need depends on what you are
importing into. Rather than guess, name the columns you want. The most consequential
choice is between one signed amount column and a debit/credit pair, which splits that one signed figure into two positive-magnitude columns.
Field
Meaning
date
Transaction date, YYYY-MM-DD.
value_date
Value date, where the statement prints one.
description
Narrative as printed.
amount
Signed: negative is money out.
debit
Money out, as a positive figure. Blank on credits.
credit
Money in, as a positive figure. Blank on debits.
balance
Running balance, where the statement prints one.
currency
ISO code for the account.
account
Masked account number.
source
The uploaded file the row came from.
page
Page of the PDF the row was read from.
confidence
Extraction confidence, 0–1.
cURL
# Two positive columns, what accounting imports expect
curl "${BASE}/jobs/${jobId}/documents/${docId}/download\
?format=csv&columns=date,description,debit,credit,balance"
# Renamed headings need the POST form
curl -X POST "${BASE}/jobs/${jobId}/documents/${docId}/export" \
-H 'Content-Type: application/json' \
-d '{"format":"csv","columns":[{"field":"date","header":"Posted"},{"field":"debit"}]}'
# The whole batch, merged into one workbook
curl "${BASE}/jobs/${jobId}/download?format=xlsx&mode=combined"
Objects
Job
status is one of queued, processing, completed, failed or needs_password.
amount is signed — negative is
money out. balance is null when the
statement has no balance column. summary.balance_check is passed, failed or unavailable.