DocsGuides

Async reads

Add async=true and the POST answers 202 as soon as the file is accepted. The result arrives by webhook, or by fetching the document until it is done.

When to use it#

  • A file over 60 pages. Up to 500 pages are read with async. Without it, a longer file returns 413 too_many_pages.
  • A batch. A synchronous request over 4 in flight returns 429. Async requests wait their turn instead.
  • A short request timeout, such as a serverless function or a request from a browser through your backend.

Send it#

Pass async=true as a query parameter, or as a multipart part named async. Everything else about the request is the same.

# Answers 202 at once with the document's id.
curl -X POST "https://statementbear.com/api/v1/documents?async=true" \
  -H "Authorization: Bearer $STATEMENTBEAR_KEY" \
  -H "Content-Type: application/pdf" \
  -H "Idempotency-Key: $(uuidgen)" \
  --data-binary @statement.pdf

# Then fetch it until status is succeeded or failed.
curl https://statementbear.com/api/v1/documents/doc_5f2a9c4b1e77d0a3c8b6e412 \
  -H "Authorization: Bearer $STATEMENTBEAR_KEY"

The 202#

The body is the document with status: "processing" and every read field empty. Location holds its URL. X-Billable-Pages and usage.billablePages say what will be billed if the read succeeds.

202 Accepted
{
  "id": "doc_8c1d40e97a2b5f3e6d0c9a71",
  "object": "document",
  "livemode": true,
  "created": 1785372094,
  "status": "processing",
  "error": null,
  "filename": "hsbc-2025.pdf",
  "pages": 84,
  "metadata": {},
  "collection": null,
  "issuer": null,
  "currency": null,
  "period": null,
  "accounts": [],
  "recurring": [],
  "verification": null,
  "authenticity": null,
  "usage": { "pages": 84, "billablePages": 84 }
}

Everything that can be decided from the file is decided before the 202: authentication, size and type, the password, the page count, and your free pages and monthly cap. Those errors come back on the POST exactly as they do without async.

Get the result#

WayHow
WebhookSubscribe an endpoint to document.succeeded and document.failed. The event carries the whole document. See Webhooks.
PollingGET /api/v1/documents/{id} every five seconds until status is succeeded or failed. Fetching a document is free.

A read takes as long as it would synchronously, 10 to 40 seconds for a typical statement and longer for a long one. It starts as soon as one of your account's read slots is free.

When the read fails#

status becomes failed and error holds the same code and message a synchronous request would have returned, usually not_a_bank_statement or parse_failed. A failed read is not charged and usage.billablePages drops to 0. A read interrupted on our side is restarted; if it still cannot finish it fails with parse_failed.

Rules#

  • format other than json is refused with 400 format_requires_sync. Fetch the finished document as JSON.
  • Send an Idempotency-Key. A repeat returns the same document as it stands: 202 while processing, 200 once finished. See Idempotency and retries.
  • A test key answers 202, then succeeded a couple of seconds later, with the scenario you asked for.
Something wrong or missing on this page? [email protected]