# Files you can send

> PDFs, scans, phone photos, CSV, OFX and QIF exports, and password-protected statements: how to send each and how its pages are counted.

Section: Guides
Source: https://statementbear.com/docs/file-types
Product: StatementBear statement parsing API, $0.08 per page, 200 pages free.

---

Send whatever the customer has. The type is read from the file itself, and every type returns the same document object.

| File | Content-Type for a raw body | Pages counted |
| --- | --- | --- |
| A PDF from the bank | `application/pdf` | Its page count. |
| A scanned PDF | `application/pdf` | Its page count. |
| A photo of one page | `image/jpeg` or `image/png` | One. |
| A CSV, OFX or QIF export | `text/csv`, `application/x-ofx`, `application/qif` or `text/plain` | One per 40 rows. |

`application/octet-stream` works for any of them. Other accepted spellings are `application/csv`, `application/vnd.ms-excel`, `application/ofx` and `application/vnd.intu.qbo`. In a multipart request the part's own type does not matter.

A file the API does not read, such as an Excel workbook or a Word document, returns `415 unsupported_media_type` whatever type you declare. Nothing is charged.

## PDFs

The PDF the bank issued, downloaded from online banking or attached to an email, is the best input there is: its amounts are read from its own text. A statement saved through the browser's print dialog is the same. Pages that are pictures inside a text PDF, such as a pasted-in table, are read from their images.

## Scans and photos

- A scanned PDF, or a PDF with no text layer, is read from its page images.
- A JPEG or PNG is one page of a statement. Send one photo per request; for a statement photographed page by page, combine the photos into one PDF first so its accounts and balances are read together.
- Flat, well lit and in focus. A page cut off at the edge loses the rows on it.
- Every document read from images carries the `image_only` [authenticity signal](https://statementbear.com/docs/authenticity).

## Exports

- CSV, OFX and QIF files downloaded from online banking.
- Rows the export marks as pending, declined, failed or cancelled are left out.
- An export whose account column holds several accounts returns one entry per account in `accounts`.
- Most exports print no balances, so there is less to check them against. See [Verification](https://statementbear.com/docs/verification).
- An export has no file history, so `authenticity.producer` and its dates are null.

## Password-protected PDFs

Send the password in a multipart part named `password`, beside the `file` part. A raw body cannot carry one. Without it the response is `422 password_required`; with the wrong one, `422 incorrect_password`. Neither is charged. The password opens that one file and is not kept once the read is done.

cURL:

```bash
curl -X POST https://statementbear.com/api/v1/documents \
  -H "Authorization: Bearer $STATEMENTBEAR_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F file=@statement.pdf \
  -F password=01011990 \
  -F 'metadata={"applicationId":"app_8841"}'
```

Node.js:

```javascript
import { readFile } from "node:fs/promises";
import { randomUUID } from "node:crypto";

const form = new FormData();
form.append("file", new Blob([await readFile("statement.pdf")]), "statement.pdf");
form.append("password", "01011990");
form.append("metadata", JSON.stringify({ applicationId: "app_8841" }));

const res = await fetch("https://statementbear.com/api/v1/documents", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.STATEMENTBEAR_KEY}`,
    "Idempotency-Key": randomUUID(),
  },
  body: form,
});
```

Python:

```python
import json, os, uuid, requests

with open("statement.pdf", "rb") as f:
    res = requests.post(
        "https://statementbear.com/api/v1/documents",
        headers={
            "Authorization": f"Bearer {os.environ['STATEMENTBEAR_KEY']}",
            "Idempotency-Key": str(uuid.uuid4()),
        },
        files={"file": ("statement.pdf", f, "application/pdf")},
        data={
            "password": "01011990",
            "metadata": json.dumps({"applicationId": "app_8841"}),
        },
        timeout=180,
    )
```

Statements uploaded through a [collection's](https://statementbear.com/docs/collections) hosted page cannot carry a password. The page asks the uploader to remove it.

## Filenames and metadata

- The multipart part's filename becomes `filename` on the document. With a raw body, send it in an `X-Filename` header.
- `metadata` is a JSON object of your own strings, sent as a multipart part, or as a `metadata` query parameter with a raw body. It comes back on the document and on its webhooks. Up to 20 keys of 1 to 40 characters, each value up to 500.

---

All documentation: https://statementbear.com/docs/llms.txt
Questions: support@statementbear.com
