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

Bank Statement · Quickstart

Upload a BCA statement, get back the parsed ledger.

Time: ~5 minutes.

Prerequisites

Sandbox API key with scopes: analyses:upload, analyses:read, webhook:write.

1. Upload

POST/api/analyses/upload
Auth · API keyScope · analyses:uploadRate limit · 60/10min
curl -X POST https://sandbox.quantumelixir.tech/bank-statement/api/analyses/upload \
  -H "Authorization: Bearer $QE_API_KEY" \
  -F "file=@./bca-may-2026.pdf" \
  -F "bank_hint=BCA" \
  -F "customer_name=Budi Santoso" \
  -F "external_ref=loan-app-2026-05-24-001"

Response (201):

{
  "data": [
    {
      "analysisId": "ana_01HXY...",
      "jobId": "job_01HXY...",
      "filename": "bca-may-2026.pdf"
    }
  ],
  "rejected": 0,
  "consolidationGroup": null
}

Processing is async — even small statements take 1-5 seconds. Don't wait inline.

2. Multi-file upload (loan underwriting)

For an underwriting case you typically want 3–6 months. Upload them all at once and let us auto-group:

curl -X POST .../api/analyses/upload \
  -H "Authorization: Bearer $QE_API_KEY" \
  -F "file=@./bca-jan-2026.pdf" \
  -F "file=@./bca-feb-2026.pdf" \
  -F "file=@./bca-mar-2026.pdf" \
  -F "file=@./bca-apr-2026.pdf" \
  -F "file=@./bca-may-2026.pdf" \
  -F "auto_create_group=true" \
  -F "new_group_name=Budi Santoso — Loan #001" \
  -F "external_ref=loan-app-2026-05-24-001"

Response now includes a consolidationGroup:

{
  "data": [
    { "analysisId": "ana_01HXY1...", "jobId": "job_...", "filename": "bca-jan-2026.pdf" },
    { "analysisId": "ana_01HXY2...", "jobId": "job_...", "filename": "bca-feb-2026.pdf" },
    ...
  ],
  "rejected": 0,
  "consolidationGroup": {
    "id": "cgr_01HXY...",
    "name": "Budi Santoso — Loan #001",
    "created": true
  }
}

3. Wait for completion

The recommended pattern is webhooks (see step 5). For the quickstart, poll:

curl https://sandbox.quantumelixir.tech/bank-statement/api/analyses/ana_01HXY1... \
  -H "Authorization: Bearer $QE_API_KEY"

When status: completed, you're ready to read.

4. Read the parsed ledger

{
  "data": {
    "id": "ana_01HXY...",
    "status": "completed",
    "parseMethod": "bca_native",
    "detectedBank": "BCA",
    "accountHolder": "BUDI SANTOSO",
    "accountNumber": "1234567890",
    "accountNumberMasked": "******7890",
    "statementPeriod": "01 May 2026 - 31 May 2026",
    "openingBalance": 12500000,
    "closingBalance": 18750000,
    "totalInflow": 25000000,
    "totalOutflow": 18750000,
    "netMovement": 6250000,
    "averageBalance": 14375000,
    "currency": "IDR",
    "confidenceScore": 99,
    "confidenceLevel": "high",
    "affordabilityScore": 78,
    "authenticityScore": 96,
    "transactions": [
      {
        "id": "txn_01HXY...",
        "sequenceNo": 1,
        "occurredAt": "2026-05-02T00:00:00Z",
        "rawTxnDate": "02/05",
        "description": "Salary PT XYZ",
        "amount": 12000000,
        "direction": "in",
        "balanceAfter": 24500000,
        "balanceMismatch": false,
        "channel": "transfer",
        "categoryId": "cat_salary",
        "categoryConfidence": 0.98
      },
      ...
    ]
  }
}

5. Get the consolidated view (multi-statement)

When you uploaded 3+ statements in a group, the consolidation endpoint merges them:

curl .../api/consolidations/cgr_01HXY.../consolidated \
  -H "Authorization: Bearer $QE_API_KEY"
{
  "data": {
    "accountsConsolidated": 5,
    "totalInflow": 125000000,
    "totalOutflow": 92000000,
    "netMovement": 33000000,
    "averageMonthlyInflow": 25000000,
    "periodStart": "2026-01-01T00:00:00Z",
    "periodEnd": "2026-05-31T23:59:59Z",
    "transactionCount": 247,
    "anomalyCount": 3,
    "affordabilityScore": 78,
    "monthlyBuckets": [
      { "month": "2026-01", "inflow": 22000000, "outflow": 16500000, "balanceEnd": 8500000 },
      { "month": "2026-02", "inflow": 24500000, "outflow": 17000000, "balanceEnd": 16000000 },
      ...
    ]
  }
}

This is the shape loan underwriting integrations consume.

6. Subscribe to webhooks

curl -X POST .../api/webhooks \
  -H "Authorization: Bearer $QE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.example.com/webhooks/bank-statement",
    "events": ["analysis.completed", "analysis.requires_review", "analysis.failed"]
  }'

Don't poll in production

Even at low volume, webhooks are better — your loan-underwriting service gets a push the moment all statements in a group finish parsing, rather than polling on a fixed cadence. Subscribe to analysis.completed and key your downstream pipeline off the consolidationGroupId field.

Next steps