API Reference
Bank statement analysis over HTTPS
Submit a PDF, receive structured revenue, fraud, and debt analysis via signed webhook. Generate credentials at app.clearstaq.com.
New to the API? Start with the conceptual guide: API & Webhooks overview.
Overview
Submit a bank-statement PDF to https://app.clearstaq.com/api/v1/analyses. The endpoint returns 202 Accepted with an analysis id; the full analysis result is delivered asynchronously to your callback_url as a signed webhook.
API access is available on StaqCore and above. Free-tier orgs cannot generate API keys.
Authentication
Every request must include a bearer token issued from your Integrations settings page. Keep both the cg_live_* key and the whsec_* webhook secret out of version control.
Authorization: Bearer cg_live_YOUR_KEY_HERE
Submit a statement
Multipart upload. Maximum size 25 MB. Only application/pdf is accepted.
ClearStaqAI Fraud Detection (Gemini visual second-pass) is opt-in. Pass clearstaq_ai_enabled=true on a submission to enable it for that request. Defaults to off; the deterministic metadata fraud score always runs.
curl -X POST https://app.clearstaq.com/api/v1/analyses \
-H "Authorization: Bearer cg_live_YOUR_KEY_HERE" \
-F "file=@./statement.pdf" \
-F "callback_url=https://your-app.example.com/hooks/clearstaq" \
-F "client_ref=customer-123" \
-F 'metadata={"loan_id":"LN-999"}' \
# Opt in to the ClearStaqAI visual fraud second-pass (default off):
# -F "clearstaq_ai_enabled=true"Receive the result
When the analysis completes, ClearStaq POSTs a signed JSON envelope to your callback_url. Respond with any 2xx status within 10s to acknowledge. Non-2xx responses are retried up to 5 times with exponential backoff (1m, 5m, 30m, 2h, 12h).
POST /hooks/clearstaq HTTP/1.1
Content-Type: application/json
X-ClearStaq-Event: analysis.completed
X-ClearStaq-Delivery: 2f8b0...
X-ClearStaq-Signature: sha256=<hex hmac>
{
"id": "cb_...",
"event": "analysis.completed",
"client_ref": "customer-123",
"status": "completed",
"result": { "bank_name": "Chase", "true_revenue": 84250.12, ... }
}Verify the signature
Compute HMAC-SHA256 over the raw request body using your webhook signing secret and compare (timing-safe) to the X-ClearStaq-Signature header.
import crypto from "node:crypto"
// In your webhook handler:
export default function handler(req, res) {
const signature = req.headers["x-clearstaq-signature"]
const raw = req.rawBody // the exact JSON bytes ClearStaq sent
const expected =
"sha256=" + crypto.createHmac("sha256", process.env.CLEARSTAQ_WEBHOOK_SECRET).update(raw).digest("hex")
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature ?? ""))
if (!ok) return res.status(400).send("bad signature")
// req.body is the WebhookEnvelope — act on it, then respond 2xx.
res.status(200).send("ok")
}Client profiles (multiple statements)
To analyze a client across several statements at once, POST 1–25 PDFs to https://app.clearstaq.com/api/v1/clients. This creates a ClearStaq client in your org (visible in your webapp), parses every statement, and computes an aggregated profile over the valid statements. Incomplete or non-bank statements are excluded from the profile and listed with a failure reason. Billing is per document (same credits as a single analysis), scaled by file count.
Repeat the file field for each PDF (or use files). Max 25 MB per file. client_name is optional — when omitted, the client is named from the dominant account holder once parsed. clearstaq_ai_enabled is opt-in, same as a single submission.
curl -X POST https://app.clearstaq.com/api/v1/clients \ -H "Authorization: Bearer cg_live_YOUR_KEY_HERE" \ -F "file=@./statement-jan.pdf" \ -F "file=@./statement-feb.pdf" \ -F "client_name=Acme LLC" \ # Optional: opt in to the ClearStaqAI visual fraud second-pass (default off): # -F "clearstaq_ai_enabled=true"
The endpoint returns 202 Accepted with a client_id, a batch_id, and per-document queue state.
{
"client_id": "8f1c...",
"batch_id": "2a4d...",
"documents": [
{ "id": "d1...", "filename": "statement-jan.pdf", "status": "queued" },
{ "id": "d2...", "filename": "statement-feb.pdf", "status": "queued" }
]
}Poll a client profile
Fetch https://app.clearstaq.com/api/v1/clients/{id} to read the aggregated profile and per-document statuses. Poll until counts.completed + counts.failed === counts.total and profile is non-null — the profile is computed asynchronously shortly after the documents finish parsing.
curl https://app.clearstaq.com/api/v1/clients/<client_id> \ -H "Authorization: Bearer cg_live_YOUR_KEY_HERE" # Poll until counts.completed + counts.failed === counts.total # AND profile is non-null (the profile is computed asynchronously # shortly after the documents finish parsing).
{
"id": "8f1c...",
"name": "Acme LLC",
"status": "completed",
"profile": { "true_revenue": 168500.24, "fraud_score": 12, ... },
"documents": [
{
"id": "d1...",
"filename": "statement-jan.pdf",
"status": "completed",
"bank_name": "Chase",
"period_start": "2025-01-01",
"period_end": "2025-01-31",
"fraud_score": 8,
"failure_reason": null,
"pages_present": 6,
"pages_expected": 6,
"detected_bank": "Chase"
},
{
"id": "d2...",
"filename": "statement-feb.pdf",
"status": "failed",
"failure_reason": "missing_pages",
"pages_present": 3,
"pages_expected": 6
}
],
"counts": { "total": 2, "completed": 1, "failed": 1 }
}failure_reason values include missing_pages, not_a_bank_statement:<type>, or another reason string; null when the document parsed successfully.
Prefer webhooks? Subscribe to the batch.completed event (via POST /api/v1/webhooks) and ClearStaq POSTs the computed profile to your endpoint once per submission — same HMAC X-ClearStaq-Signature scheme and 5-step retry backoff as analysis.completed. The payload is { event, batch_id, client_id, org_id, counts, profile, created_at }.
Error codes
| HTTP | Code | Meaning |
|---|---|---|
| 401 | unauthorized | Missing or unrecognised API key. |
| 402 | plan_excluded | Org is on the Free plan. |
| 402 | insufficient_credits | No credits remaining and auto top-up is off. |
| 413 | file_too_large | PDF exceeds 25 MB. |
| 415 | unsupported_media_type | Non-PDF upload. |
| 422 | invalid_callback_url | callback_url is invalid. |
| 502 | parser_unavailable | Analysis service could not accept the job. |
OpenAPI spec
Download the machine-readable spec to generate SDKs or import into Postman/Insomnia. openapi.yaml