Upload PDF
/api/analyses/uploadmultipart/form-data. One or more files per request.
Form fields
filebinaryRequiredbank_hintstringcustomer_namestringcustomer_idstringexternal_refstringconsolidation_group_idstringauto_create_groupbooleannew_group_namestringupload_batch_idstringResponse
{
"data": [
{
"analysisId": "ana_01HXY...",
"jobId": "job_01HXY...",
"filename": "bca-may-2026.pdf"
}
],
"rejected": 0,
"consolidationGroup": {
"id": "cgr_01HXY...",
"name": "Budi Santoso — 2026-05-24",
"created": true
}
}rejected: count of files that failed pre-flight (not a PDF, > size limit, etc.). Inspect via Web Inspector or therejected_filesextension field in non-curl SDK clients.consolidationGroup: present only whenauto_create_group=trueorconsolidation_group_idwas passed.
File constraints
| Constraint | Default |
|---|---|
| Format | PDF only |
| Max files per request | 10 |
| Max file size | 50 MB (enterprise tier 100 MB) |
| Max pages per PDF | 200 |
| Min pages | 1 |
For image-only scans (no embedded text), wrap them in a PDF — every common image-to-PDF tool works. We don't accept JPEG/PNG uploads directly here because parsing accuracy on raw images is meaningfully worse than the same image inside a PDF wrapper.
Async processing
The upload returns immediately. Each file enters the job queue:
queued → parsing → completed (default success)
→ requires_review (low confidence; analyst review needed)
→ failed (hard error: corrupt PDF, unsupported format, parser error)
→ password_required (encrypted, no/wrong password)Subscribe to analysis.completed / .requires_review / .failed webhooks, or poll GET /api/analyses/{id}.
Password-protected PDFs
If the PDF is encrypted, the analysis lands in password_required. Submit the password via:
/api/analyses/{id}/password{ "password": "birth-date-or-similar" }We decrypt in-memory only; the password is never persisted. If wrong, the analysis stays in password_required; up to 5 attempts before the analysis is locked.
Multi-account PDFs
Some banks (Permata, OCBC, Mandiri corporate) ship a single PDF with multiple accounts. We auto-split:
- One root analysis is created on upload.
- During parsing, if multiple accounts are detected, additional sibling analyses are created with
parentAnalysisIdpointing to the root. - Each sibling has its own status, transactions, and webhook events.
Your loan-underwriting code should iterate parentAnalysisId to find siblings if you don't know up-front whether the PDF is single- or multi-account.
Re-running
/api/analyses/{id}/retryUse when:
- Parsing failed transiently.
- A native parser was updated since the original parse.
- You corrected a password and want a fresh try.
Returns the new job ID. Same analysis row is reused — extractions are appended, not replaced.
Idempotency / dedupe
We hash the file at upload. Identical files (same SHA-256) within the same org are deduped to a single analysis. Re-uploading the same file is safe — the existing analysis is returned.
To force a fresh parse on a duplicate, use /retry.
Storage retention
By default, the raw PDF is sealed-at-rest for 90 days then purged; transactions stay forever. Extend retention from the dashboard's Data Retention page if your audit policy requires longer source-file retention.