📘 Public beta · Endpoints are stable; OpenAPI specs and SDKs ship monthly. See changelog →
Products
Bank Statement
Upload PDF

Upload PDF

POST/api/analyses/upload
Auth · API keyScope · analyses:uploadRate limit · 60 per 10 min per caller

multipart/form-data. One or more files per request.

Form fields

filebinaryRequired
PDF only. Image scans → wrap in PDF first. Repeating field for multiple files.
bank_hintstring
Bank code (BCA · MANDIRI · BRI · BNI · PERMATA · DANAMON · BTN · OCBC). Skips bank detection.
customer_namestring
Auto-create the customer if new.
customer_idstring
Link to existing customer.
external_refstring
Your loan/case ID, propagated to webhook payloads.
consolidation_group_idstring
Attach all uploaded files to an existing group.
auto_create_groupboolean
Create a new group for the uploaded set. Useful for "3 months of statements".
new_group_namestring
Used with auto_create_group=true. Default: customer name + date.
upload_batch_idstring
Your batch tracking ID; appears on the analysis row for ops.

Response

{
  "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 the rejected_files extension field in non-curl SDK clients.
  • consolidationGroup: present only when auto_create_group=true or consolidation_group_id was passed.

File constraints

ConstraintDefault
FormatPDF only
Max files per request10
Max file size50 MB (enterprise tier 100 MB)
Max pages per PDF200
Min pages1

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:

POST/api/analyses/{id}/password
Auth · API keyScope · analyses:uploadRate limit · 10 per 5 min
{ "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 parentAnalysisId pointing 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

POST/api/analyses/{id}/retry
Auth · API keyScope · analyses:upload

Use 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.