DocsGet started

Quickstart

From signing up to parsed JSON in about five minutes.

1. Create a key#

Sign in and open the developer console. Creating an organisation issues your first key in the same step. No payment method is needed. The key is shown once, so copy it into your secret store now.

2. Send a statement#

POST the PDF as a raw body with Content-Type: application/pdf, or as multipart/form-data with a part named file. Up to 20MB. A parse takes 10 to 40 seconds, so set a client timeout of at least 180 seconds.

curl -X POST https://statementbear.com/api/v1/documents \
  -H "Authorization: Bearer $STATEMENTBEAR_KEY" \
  -H "Content-Type: application/pdf" \
  -H "Idempotency-Key: $(uuidgen)" \
  --data-binary @statement.pdf

3. Read the response#

A success is a document object. Every account on the PDF is in accounts, with its rows inside it. amount is always positive and direction carries the sign.

200 OK
{
  "id": "doc_5f2a9c4b1e77d0a3c8b6e412",
  "object": "document",
  "created": 1785372094,
  "issuer": { "name": "Monzo", "domain": "monzo.com" },
  "currency": "GBP",
  "period": { "year": 2026, "month": 3 },
  "accounts": [
    {
      "type": "bank",
      "last4": "4412",
      "name": null,
      "period": { "year": 2026, "month": 3 },
      "primary": true,
      "totals": { "credits": 3240.00, "debits": 2841.55 },
      "statedTotals": { "credits": 3240.00, "debits": 2841.55 },
      "openingBalance": 1204.11,
      "closingBalance": 1602.56,
      "transactions": [
        {
          "date": "2026-03-04",
          "description": "TESCO STORES 3412",
          "amount": 42.10,
          "direction": "debit",
          "category": "groceries"
        }
      ]
    }
  ],
  "verification": { "reconciled": true, "issues": [] },
  "usage": { "documents": 1 }
}

4. Check the response#

  1. Only count credits as income on `type: "bank"` accounts. A credit card's credits are the monthly repayment and merchant refunds. See Amounts and directions.
  2. Check `verification.reconciled`. When it is false, send the document to manual review instead of using the totals. See Verification.
// Credit card credits are repayments and refunds. Only count
// credits on bank accounts.
const income = doc.accounts
  .filter((a) => a.type === "bank")
  .reduce((sum, a) => sum + a.totals.credits, 0);

// Send anything that did not reconcile to manual review.
if (!doc.verification.reconciled) {
  await queueForManualReview(doc.id, doc.verification.issues);
}

5. Make retries safe#

Send an Idempotency-Key with every request: one unique string per document, reused by every attempt at that document. A repeat of a successful call returns the stored response instead of parsing again. See Idempotency and retries.

Next#

Something wrong or missing on this page? [email protected]