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

Consolidations

A consolidation group is a collection of analyses — typically 3–6 months of statements from the same customer — merged into a single ledger with cross-statement metrics.

This is the canonical shape for loan-underwriting integrations.

Why consolidate?

A single monthly statement is a snapshot. A loan decision needs the trend: 3-month average inflow, monthly volatility, peak-vs-trough balance, repeat-counterparty patterns. Consolidations give you all of that at the group level rather than reconstructing across individual analyses.

Create a group

POST/api/consolidations
Auth · API keyScope · write
{
  "name": "Budi Santoso — Loan #001",
  "description": "5-month underwriting submission",
  "externalRef": "loan-app-2026-05-24-001",
  "customerId": "cus_01HXY..."
}

Or auto-create at upload time with auto_create_group=true (see Upload PDF).

Add analyses to a group

If you've already uploaded analyses and want to group them after the fact, link them:

curl -X PATCH ".../api/analyses/ana_01HXY..." \
  -H "Authorization: Bearer $QE_API_KEY" \
  -d '{ "consolidationGroupId": "cgr_01HXY..." }'

(Note: PATCH /api/analyses/{id} is implicit in the platform — exposed via the dashboard if not yet via API.)

Read the consolidated view

GET/api/consolidations/{id}/consolidated
Auth · API keyScope · read
{
  "data": {
    "accountsConsolidated": 5,
    "totalInflow": 125000000,
    "totalOutflow": 92000000,
    "netMovement": 33000000,
    "averageMonthlyInflow": 25000000,
    "averageMonthlyOutflow": 18400000,
    "periodStart": "2026-01-01T00:00:00Z",
    "periodEnd": "2026-05-31T23:59:59Z",
    "transactionCount": 247,
    "anomalyCount": 3,
    "anomalies": [
      {
        "transactionId": "txn_01HXY...",
        "type": "balance_mismatch | sudden_burst | doctored_row | suspicious_round",
        "severity": "low | medium | high",
        "description": "Balance after IDR 24.5M doesn't reconcile with prior + amount"
      }
    ],
    "affordabilityScore": 78,
    "authenticityScore": 92,
    "monthlyBuckets": [
      {
        "month": "2026-01",
        "inflow": 22000000,
        "outflow": 16500000,
        "netMovement": 5500000,
        "balanceEnd": 8500000,
        "averageBalance": 7200000,
        "transactionCount": 48
      },
      ...
    ],
    "categoryBreakdown": {
      "salary":           { "credits": 75000000, "debits": 0,         "count": 5 },
      "transfer_external":{ "credits": 28000000, "debits": 12000000,  "count": 87 },
      "ecommerce":        { "credits": 0,        "debits": 18500000,  "count": 42 },
      "loan_repayment":   { "credits": 0,        "debits": 24000000,  "count": 12 },
      ...
    },
    "topCounterparties": [
      { "name": "PT XYZ", "count": 5, "totalAmount": 75000000, "direction": "in" },
      { "name": "Tokopedia", "count": 35, "totalAmount": 15500000, "direction": "out" }
    ]
  }
}

Key metrics for underwriting

MetricWhy it matters
averageMonthlyInflowRepayment-capacity baseline. Loan tenor × monthly repayment should fit comfortably under this.
affordabilityScorePre-computed: 78 means "78th percentile across our customer base."
authenticityScoreWatch for < 80 — possible doctored statement. Cross-check anomalies.
categoryBreakdown.loan_repaymentExisting debt load. Tells you what they're already paying.
monthlyBuckets consistencyHigh variance = unstable income, treat with care.
topCounterpartiesAre inflows mostly salary (good) or single-source from one entity (concentrated)?

List analyses in a group

GET/api/consolidations/{id}/analyses
Auth · API keyScope · read

Returns each member analysis with its summary fields. Use this when you want per-statement detail rather than the merged view.

Update / delete a group

PATCH/api/consolidations/{id}
Auth · API keyScope · write

Update name, description, externalRef, customerId.

DELETE/api/consolidations/{id}
Auth · API keyScope · write

Deletes the group. Does not delete the member analyses — they just become orphaned (no group). To delete the analyses too, pass ?cascade=true.

Webhook on group completion

Subscribe to consolidation.completed — fires when the last queued analysis in a group transitions to completed. Most underwriting pipelines key off this rather than tracking per-analysis state.