# AI PDF to JSON & Invoice OCR: Receipt, Bank Statement Parser (`rs-automation-labs/ai-document-extractor`) Actor

AI PDF to JSON and invoice OCR parser. Turn invoices, receipts, bank statements, POs and scanned PDFs, photos or DOCX into validated JSON, CSV and Excel. Line items, math checks, per-field confidence, your own fields. No API key. $0.01/doc, failed docs free.

- **URL**: https://apify.com/rs-automation-labs/ai-document-extractor.md
- **Developed by:** [RS Automation Labs](https://apify.com/rs-automation-labs) (community)
- **Categories:** AI, Automation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## AI PDF to JSON & Invoice OCR: Receipts, Bank Statements & Any Document

Convert **PDFs, scanned documents, photos, DOCX and HTML to clean, validated JSON**, plus CSV you can open in Excel or Google Sheets. Use it as an **invoice OCR and parser**, a **receipt OCR API**, a **bank statement to CSV/Excel converter** with balance reconciliation, or a general **document parser** with your own fields. Every document comes back with typed values, line items, **per-field confidence scores** and **math checks**: line items vs subtotal, subtotal + tax = total, and running balances.

**No API keys needed.** The AI runs through Apify's official OpenRouter proxy and is billed at cost to your Apify account. You can also bring your own OpenRouter key. **You pay $0.01 per successfully extracted document (up to 5 pages included). Failed documents are free.**

### What does this PDF to JSON extractor do?

- **Reads any document:** text PDFs, scanned PDFs, JPG / PNG / WebP / TIFF / GIF photos, DOCX, HTML and TXT. Files can come from URLs (including Google Drive and Dropbox share links), file uploads, an Apify key-value store, or a dataset from another Actor.
- **Uses the cheapest method that works:** if a page has a text layer, that text is used, which is cheap and exact. The vision model only reads pages that are scans or photos.
- **Extracts structured data:** 9 ready-made presets with line-item tables, auto-detection of the document type, or your own fields and JSON Schema.
- **Normalizes values:** ISO 8601 dates, ISO 4217 currency codes and real numbers. It handles `1.234,56`, `1,23,456.00`, `(120.00)` and `Rs. 450/-`, and checks IBANs and container numbers.
- **Validates the result:** quantity × unit price, line items vs subtotal, subtotal + tax = total, tax breakdown, amount due, bank statement balance reconciliation, running balances, due date ≥ invoice date and required fields.
- **Tells you what to trust:** each field gets a confidence score. It is lowered automatically when a value cannot be found in the document text or when a check fails. Any document that needs a human look gets `needsReview: true` with reasons.
- **Exports to spreadsheets:** `RESULTS.csv` has one row per document, and `TABLE-lineItems.csv` (or transactions, etc.) has one row per line. Both open cleanly in Excel and Google Sheets.

### Use cases: invoice OCR, receipt OCR, bank statements to CSV/Excel and more

- **Invoice and receipt OCR for accounts payable and bookkeeping:** batch-process supplier invoices and receipts into your ERP, Xero, QuickBooks, Tally or a spreadsheet.
- **Bank statement to CSV / Excel for fintech, lending and bookkeeping:** turn bank and card statements into transactions, with balance reconciliation so you can see missing or misread rows.
- **Operations and logistics:** purchase orders, bills of lading and shipping documents.
- **HR and recruiting:** parse resumes into structured profiles.
- **Developers and automation builders:** a single API call (or Make / Zapier / n8n step) that turns any file into JSON you define.

### Supported documents and presets

| Preset | Typical fields |
|---|---|
| Auto-detect | Picks the best preset below for each document |
| Invoice / bill | Number, dates, PO, vendor, customer, line items, subtotal, tax breakdown, total, amount due, bank details |
| Receipt | Merchant, date, items, tax, tip, total, payment method |
| Bank / card statement | Account, period, opening and closing balance, transactions (reconciled) |
| Purchase order | PO number, buyer, supplier, line items, totals, delivery details |
| Resume / CV | Contact details, experience, education, skills |
| Business card | Name, title, company, phones, emails, address |
| Generic form / any document | Key-value pairs and tables |
| Contract key terms | Parties, dates, term, renewal, payment terms, governing law |
| Bill of lading / shipping document | Shipper, consignee, ports, containers (number check), goods, weights |
| Custom schema only | Only the fields you define |

You can add your own fields to any preset.

### Why this Actor?

- **Your schema, not ours.** Add fields to a preset, or describe the whole output with a simple field list or a JSON Schema. Most extractors on the Store only return raw text.
- **Validated, not just extracted.** Math and format checks catch the classic AI mistakes, such as a dropped line, a misread total or a swapped day/month.
- **Confidence you can act on.** Use `needsReview` to send only uncertain documents to a human.
- **Cheap by design.** Text-first processing and a small default model (`google/gemini-2.5-flash-lite`) cost about **$0.0002–$0.001 of AI per document**. Switch to the accurate model for hard scans.
- **Reliable.** Retries, automatic fallback to a second model, chunking for long documents, and failed documents are free.
- **Private by default.** Nothing is stored outside your Apify storage, and the model is told to ignore any instructions written inside documents. Government ID documents (passports, ID cards, driver's licenses) are refused and not charged.

### How to use it

1. Add documents under **Document URLs**, **upload files**, or point to a **key-value store / dataset**.
2. Choose a **Document type**: *Auto-detect*, a preset, or *Custom fields only*.
3. Optional: add **Custom fields**, for example `vatNumber (string): Seller VAT ID` or `totalAmount* (number)`.
4. Click **Start**. Each document becomes one dataset row. Download it as JSON, CSV or Excel, or use the CSV files in the key-value store.

You can call it from the API, schedule it, or chain it after another Actor that collects file URLs (use **Dataset ID** + **URL field**).

### Input example

```json
{
  "documentUrls": [
    { "url": "https://api.apify.com/v2/key-value-stores/xBqlN4kRAyAIWZpIU/records/sample-invoice.pdf" },
    { "url": "https://api.apify.com/v2/key-value-stores/xBqlN4kRAyAIWZpIU/records/sample-receipt-scan.jpg" }
  ],
  "documentType": "auto",
  "customFields": ["costCenter (string): internal cost center if printed"],
  "model": "fast",
  "saveCsvFiles": true
}
```

Custom-only example (a utility bill, no preset):

```json
{
  "documentUrls": [{ "url": "https://api.apify.com/v2/key-value-stores/xBqlN4kRAyAIWZpIU/records/sample-utility-bill.pdf" }],
  "documentType": "custom",
  "customFields": [
    "accountNumber*: utility account number",
    "provider*: utility company name",
    "billingPeriodStart (date)",
    "billingPeriodEnd (date)",
    "usageKwh (number): electricity used in kWh",
    "amountDue* (number)",
    "currency (currency)",
    "dueDate* (date)"
  ]
}
```

That run returned `{"accountNumber": "7731-0042-19", "provider": "Lakeside Power & Light", "billingPeriodStart": "2026-09-01", "billingPeriodEnd": "2026-09-30", "usageKwh": 632, "amountDue": 125.78, "currency": "USD", "dueDate": "2026-10-25"}` for $0.000166 of AI.

Field-list syntax: `name* (type): description`. `*` marks a required field. Types are `string`, `number`, `integer`, `boolean`, `date`, `currency`, `email`, `phone`, `url`, `percent`, `array`, and lists such as `date[]`. For nested objects and tables, use **Custom JSON schema**.

### Output example

A real row from a cloud run (2-page text invoice, default model; long arrays shortened):

```json
{
  "documentId": "e5746a62b850",
  "sourceUrl": "kvs://xBqlN4kRAyAIWZpIU/sample-invoice.pdf",
  "sourceType": "key-value-store",
  "documentType": "invoice",
  "documentTypeTitle": "Invoice",
  "detectedDocumentKind": "Invoice",
  "status": "ok",
  "needsReview": false,
  "reviewReasons": [],
  "overallConfidence": 1,
  "validationPassed": true,
  "data": {
    "invoiceNumber": "NWC/2026-27/0457",
    "invoiceDate": "2026-10-14",
    "dueDate": "2026-11-13",
    "purchaseOrderNumber": "PO-88213",
    "currency": "INR",
    "vendor": {
      "name": "Northwind Cloud Services Pvt. Ltd.",
      "address": "4th Floor, Example Tech Park, Outer Ring Road Bengaluru, Karnataka 560103, India",
      "taxId": "29AAACN1234F1Z5",
      "email": "billing@northwind-cloud.example",
      "phone": "+91 80 4000 1234"
    },
    "customer": {
      "name": "Acme Retail Solutions LLP",
      "address": "22 MG Road, Pune, Maharashtra 411001",
      "taxId": "27AAFFA9876K1Z2",
      "email": null,
      "phone": null
    },
    "shipTo": null,
    "lineItems": [
      {
        "description": "Cloud VM hosting - 8 vCPU / 32 GB (monthly)",
        "sku": "998315",
        "quantity": 3,
        "unit": "pcs",
        "unitPrice": 12500,
        "taxRate": null,
        "amount": 37500
      },
      {
        "description": "Managed PostgreSQL database (monthly)",
        "sku": "998315",
        "quantity": 1,
        "unit": "pcs",
        "unitPrice": 8750,
        "taxRate": null,
        "amount": 8750
      },
      "... 2 more line items"
    ],
    "subtotal": 63650,
    "discount": null,
    "taxAmount": 11457,
    "taxBreakdown": [
      {
        "name": "CGST",
        "rate": 9,
        "amount": 5728.5
      },
      {
        "name": "SGST",
        "rate": 9,
        "amount": 5728.5
      }
    ],
    "shipping": null,
    "total": 75107,
    "amountPaid": 0,
    "amountDue": 75107,
    "paymentTerms": "Net 30 days from invoice date.",
    "bankDetails": {
      "bankName": "Example Bank Ltd., Koramangala Branch",
      "accountName": "Northwind Cloud Services Pvt. Ltd.",
      "accountNumber": "50200012345678",
      "iban": null,
      "swiftBic": null,
      "ifsc": "EXMP0001234",
      "routingNumber": null
    },
    "notes": "Late payments attract interest at 1.5% per month.\nAll disputes are subject to Bengaluru jurisdiction.\nThis is a computer-generated invoice."
  },
  "confidence": {
    "invoiceNumber": 1,
    "invoiceDate": 1,
    "dueDate": 1,
    "purchaseOrderNumber": 1,
    "currency": 1,
    "...": "one score per field"
  },
  "lowConfidenceFields": [],
  "ungroundedFields": [],
  "validation": {
    "passed": true,
    "checksRun": 10,
    "checksFailed": 0,
    "checks": [
      {
        "check": "lineItems.lineMath",
        "passed": true,
        "message": "quantity x unit price = amount on 4/4 lines",
        "fields": [
          "lineItems"
        ]
      },
      {
        "check": "lineItems.sumMatchesSubtotal",
        "passed": true,
        "message": "Sum of 4 lineItems amount values (63,650.00) matches subtotal (63,650.00)",
        "fields": [
          "lineItems",
          "subtotal"
        ],
        "expected": 63650,
        "actual": 63650
      },
      {
        "check": "totalsAddUp",
        "passed": true,
        "message": "subtotal + taxAmount = 75,107.00; total is 75,107.00",
        "fields": [
          "subtotal",
          "total",
          "taxAmount"
        ],
        "expected": 75107,
        "actual": 75107
      },
      "... 7 more checks"
    ]
  },
  "coercionIssues": [],
  "warnings": [],
  "fileName": "sample-invoice.pdf",
  "fileType": "pdf",
  "fileSizeBytes": 4113,
  "fileSha256": "fb9cf7c42da1b10abd918cef369b1a7c8f6815c2d0d07a8102e89f8075638681",
  "pageCount": 2,
  "pagesProcessed": 2,
  "pagesTextLayer": 2,
  "pagesVision": 0,
  "extractionMethod": "text",
  "language": "en",
  "chunks": 1,
  "model": "google/gemini-2.5-flash-lite",
  "modelsUsed": [
    "google/gemini-2.5-flash-lite"
  ],
  "fallbackUsed": false,
  "route": "apify-openrouter-proxy",
  "classification": {
    "documentType": "invoice",
    "confidence": 1
  },
  "aiCostUsd": 0.000684,
  "promptTokens": 2355,
  "completionTokens": 1122,
  "llmCalls": 2,
  "attempts": 2,
  "durationMs": 3765,
  "error": null,
  "extractedAt": "2026-10-22T11:29:42Z"
}
```

#### Main fields

| Field | Meaning |
|---|---|
| `status` | `ok`, `error`, `refused` (government ID) or `skipped` |
| `documentType` / `detectedDocumentKind` | Preset used, and what the model says the document is |
| `data` | The extracted JSON. Fields always exist (`null` when not present) and values are typed |
| `confidence` | 0–1 per top-level field, lowered when ungrounded or failing validation |
| `needsReview` / `reviewReasons` | `true` if confidence < threshold, a check failed, or required fields are missing |
| `validation` | Every check with expected vs actual values |
| `ungroundedFields` | Values the model returned that could not be found in the document text |
| `extractionMethod` | `text`, `vision` or `mixed` (per page) |
| `pageCount` / `pagesProcessed` | Pages in the file and pages read |
| `aiCostUsd` | Real AI cost of this document as reported by OpenRouter, before any plan multiplier |
| `model` / `modelsUsed` / `fallbackUsed` | Which model produced the result |
| `flatData` | `data` flattened to `vendor.name`-style columns, which power the CSV / Excel view |
| `error` | `{code, message}` when the document failed |

#### Dataset views

- **Overview:** one line per document with type, status, review flag, confidence and cost.
- **Extracted data:** the JSON.
- **Flat (spreadsheet):** one column per field. This is the best view for CSV / Excel export.
- **Validation:** checks and review reasons.
- **Errors:** failed and refused documents.

#### Key-value store

- `RESULTS.csv`: one row per extracted document (UTF-8 with BOM, opens correctly in Excel).
- `TABLE-<name>.csv`: one row per line item / transaction / table row, for example `TABLE-lineItems.csv` and `TABLE-transactions.csv`.
- `OUTPUT`: run summary with totals, review counts, AI cost, errors and CSV links.
- An optional **webhook** gets the summary as JSON when the run finishes.

#### Error codes

| Code | Meaning |
|---|---|
| `DOWNLOAD_FAILED` / `DOWNLOAD_TIMEOUT` | The URL could not be downloaded (404, timeout, login required) |
| `INVALID_URL` / `BLOCKED_URL` | Not a valid public http(s) URL (private network addresses are blocked) |
| `FILE_TOO_LARGE` / `EMPTY_FILE` | Above **Max file size**, or 0 bytes |
| `UNSUPPORTED_FORMAT` | Not a PDF, image, DOCX, HTML or text file (for example XLSX, PPTX, old .doc, HEIC) |
| `PDF_PASSWORD_PROTECTED` / `INVALID_PDF` / `INVALID_IMAGE` | The file cannot be opened |
| `NO_PAGES` / `NO_TEXT` | Nothing readable in the document |
| `PROXY_NOT_AVAILABLE` | Apify's OpenRouter proxy refused the request. Add your own OpenRouter key |
| `INSUFFICIENT_CREDITS` / `AUTH_ERROR` | The AI account has no credit or the key is wrong |
| `RATE_LIMITED` / `UPSTREAM_ERROR` / `MODEL_UNAVAILABLE` / `TIMEOUT` | AI provider problems that remained after retries and the fallback model |
| `BAD_JSON` / `EMPTY_ANSWER` | The model returned unusable output after a retry |

Government ID documents get `status: "refused"`, error code `GOVERNMENT_ID_NOT_SUPPORTED` and no data.
Failed documents are never charged.

### Export to Excel / Google Sheets

- `RESULTS.csv` in the key-value store has one row per document, and `TABLE-lineItems.csv` / `TABLE-transactions.csv` have one row per line. They're UTF-8 with BOM, so they open cleanly in Excel.
- The dataset's **Flat (spreadsheet)** view can be downloaded as Excel (XLSX), CSV or JSON from the Apify Console or API.
- Use Apify's Google Sheets integration, Make, Zapier or n8n to push results into your sheet or accounting tool.

### How much does document OCR cost?

You pay two things:

1. **This Actor's fee: $0.01 per successfully extracted document** ($10 per 1,000; *document-extracted* event), including up to 5 pages. Longer documents add **$0.001 per extra page** (*extra-page* event). Failed, refused and skipped documents are free, and Apify platform compute is included.
2. **The real AI cost**, at cost:
   - **No key (default):** billed to your Apify account through Apify's official OpenRouter proxy, at the OpenRouter price on paid plans and at **10× on the Apify FREE plan**.
   - **Your own OpenRouter key:** billed by OpenRouter directly.

Example: **1,000 invoices of up to 5 pages = $10 in Actor fees**, plus roughly $0.20–$1 of AI on the default model (paid plans).

Measured AI cost per document (real cloud runs, October 2026, before any plan multiplier):

| Document | Model | AI cost |
|---|---|---|
| 2-page text invoice, 4 line items | `google/gemini-2.5-flash-lite` (default) | $0.0007 – $0.0008 |
| Scanned receipt (photo / image PDF) | `google/gemini-2.5-flash-lite` | $0.0003 – $0.0007 |
| 1-page utility bill, custom fields | `google/gemini-2.5-flash-lite` | $0.0002 |
| Same documents, accurate model | `google/gemini-2.5-flash` | roughly 3–6× the above (estimate) |

*Auto-detect* adds one tiny classification call. Choose a preset to skip it. Each document used about 60–80 MB of memory and a few seconds of compute at 256 MB.

**Tip for the Apify FREE plan:** add your own OpenRouter API key to avoid the 10× proxy multiplier.

### Using your own API key (optional)

Add **OpenRouter API key** to send AI requests to OpenRouter with your key. You can then also use any OpenRouter model with *Model → Custom*. The key is a secret input: it is encrypted by Apify and never logged or written to output.

### FAQ

**How accurate is it?** On clean text PDFs, the default model returned every field correctly in our tests, and all math checks passed. For poor scans, handwriting or dense tables, use *Accurate* and rely on `needsReview` plus the validation checks.

**Does it OCR scanned PDFs?** Yes. Pages without a usable text layer are rendered to images and read by a vision model. Use *Image resolution* to trade detail against cost.

**Does it work with phone photos of receipts?**
Yes. JPG, PNG, WebP, TIFF and GIF photos are read by the vision model. Sharp, well-lit photos work best. Blurry ones get lower confidence and `needsReview`.

**Does it work with bank statements from any bank?**
It uses a general AI model rather than per-bank templates, so it works with most layouts. Opening balance + transactions is reconciled against the closing balance, and running balances are checked. Statements that don't add up are flagged with `needsReview` so you can check them.

**Long documents?** Up to 200 pages (default 30). Long text is split into chunks and the results are merged. Tables are concatenated.

**Can it make up values?** It is told to return `null` for anything not on the page, and every value is compared against the document text. Values that cannot be found are listed in `ungroundedFields` and their confidence is capped.

**Dates like 03/04/2026?** Use **Date format** (DMY / MDY) or let the model decide from context such as the country or currency. Ambiguous dates are flagged.

**Excel, PowerPoint or HEIC files?**
Not yet. XLSX, PPTX, old `.doc` and HEIC files are rejected as free `UNSUPPORTED_FORMAT` rows. Convert them to PDF or JPG first.

**Passports or ID cards?**
No. Government ID documents are deliberately refused and not charged.

**Can I call it from an AI agent or MCP client?**
Yes. Like every Apify Actor, it can be called through Apify's MCP server or the API.

**Is my data stored?** Only in your own Apify storages. Documents are sent to the AI model (via OpenRouter) for extraction. Don't process documents you are not allowed to share with an AI provider.

### Limitations

- Handwriting and very low-resolution photos may be misread. Check `needsReview`.
- XLSX, PPTX, old `.doc` and HEIC files are not supported in v1. Convert them to PDF or JPG first.
- Password-protected PDFs cannot be opened.
- Government ID documents are deliberately not supported.
- On the Apify FREE plan, the OpenRouter proxy costs 10× the provider price.

### Support

Found a document it gets wrong? Open an issue on the Actor's **Issues** tab with a sample (remove personal data first). We fix extraction problems quickly.

# Changelog

This Actor's version history is a separate document: https://apify.com/rs-automation-labs/ai-document-extractor/changelog.md

# Actor input Schema

## `documentUrls` (type: `array`):

Links to PDF, JPG/PNG/WebP/TIFF, DOCX, HTML or TXT/CSV files. Google Drive and Dropbox share links work. Apify key-value store records: kvs://<storeId>/<key>.

## `uploadedFiles` (type: `array`):

Upload documents from your computer. They are stored in a key-value store and processed like URLs.

## `documentType` (type: `string`):

Pick a preset (fields, validation rules and line-item tables are built in), 'Auto-detect' to classify each document first, or 'Custom schema only' to extract just your own fields. Government ID documents are not supported (privacy).

## `customFields` (type: `array`):

One field per line: 'name (type): description'. Types: string, number, integer, boolean, date, currency, email, phone, url, percent, array, or 'date\[]' etc. for lists. Add \* after the name to make it required, e.g. 'totalAmount\* (number): Grand total'. Added to the preset's fields, or used alone with 'Custom schema only'.

## `customSchema` (type: `object`):

A JSON Schema ({"type": "object", "properties": {...}, "required": \[...]}) or a simple map {"fieldName": "description"}. Nested objects and arrays of objects (tables) are supported, up to 4 levels and 150 fields.

## `instructions` (type: `string`):

E.g. 'Amounts are in thousands', 'Use the ship-to address as customer address', 'Translate item descriptions to English'.

## `model` (type: `string`):

Fast is cheap and good for clean PDFs and receipts. Accurate handles dense tables, handwriting and poor scans better (about 3-6x the AI cost). Or enter any OpenRouter model id with vision, e.g. 'openai/gpt-4.1-mini'.

## `customModel` (type: `string`):

Used when 'AI model' is 'Custom'. Any OpenRouter model id that accepts images, e.g. 'google/gemini-3-flash-preview'.

## `fallbackModel` (type: `string`):

Used automatically when the main model errors, times out or returns invalid JSON. Leave empty for the default (openai/gpt-4.1-mini); 'none' disables it.

## `openRouterApiKey` (type: `string`):

Pay OpenRouter directly instead of through your Apify account. Recommended on the Apify FREE plan.

## `keyValueStoreId` (type: `string`):

Process files stored in one of your key-value stores (ID or username~store-name).

## `keyValueStoreKeys` (type: `array`):

Record keys in that store. Wildcards allowed (e.g. 'invoice-\*'). Leave empty for all records.

## `datasetId` (type: `string`):

A dataset whose items contain document URLs, e.g. the output of a scraper.

## `datasetUrlField` (type: `string`):

Field holding the document URL (dot notation for nested fields; arrays of URLs are supported).

## `processingMode` (type: `string`):

Auto uses the PDF text layer when it exists and sends only scanned/image pages to the vision model (cheapest, most precise). 'Always vision' sends every page as an image (best for complex layouts). 'Text only' never sends images.

## `dateFormat` (type: `string`):

How to read dates like 03/04/2026. Auto infers it from the document (country, other dates).

## `defaultCurrency` (type: `string`):

ISO code used when a document shows only '$' or no currency, e.g. USD, CAD, INR.

## `confidenceThreshold` (type: `number`):

Fields below this confidence (0-1) are listed in 'lowConfidenceFields' and the document gets 'needsReview: true'.

## `maxDocuments` (type: `integer`):

Upper limit of documents per run (protects your budget).

## `maxPagesPerDocument` (type: `integer`):

Only the first N pages are read. Long documents are split into parts automatically.

## `maxFileSizeMb` (type: `integer`):

Files larger than this are skipped with a free FILE_TOO_LARGE error.

## `imageResolution` (type: `integer`):

Longest side of page images sent to the vision model. Higher reads small print better but costs more AI tokens.

## `includeFlatData` (type: `boolean`):

Adds a one-level 'flatData' object (vendor.name, total, lineItems.count ...) that exports cleanly to CSV/Excel/Sheets.

## `saveCsvFiles` (type: `boolean`):

Saves RESULTS.csv (one row per document) and TABLE-<name>.csv (one row per line item / transaction) to the key-value store.

## `includeRawText` (type: `boolean`):

Adds the extracted text layer ('rawText', up to 100k characters) to each record.

## `webhookUrl` (type: `string`):

Receives a POST with the run summary and extracted data when the run finishes (Zapier, Make, n8n, Slack-compatible 'text').

## `concurrency` (type: `integer`):

How many documents are processed in parallel. 3 is safe for 256 MB memory.

## `maxRetries` (type: `integer`):

Retries for rate limits, timeouts and upstream errors before the fallback model is tried.

## `requestTimeoutSecs` (type: `integer`):

Timeout for one AI request. Large scanned documents may need longer.

## `maxOutputTokens` (type: `integer`):

Raise for documents with hundreds of line items. Parts that hit the limit are split and retried automatically.

## Actor input object example

```json
{
  "documentUrls": [
    {
      "url": "https://api.apify.com/v2/key-value-stores/xBqlN4kRAyAIWZpIU/records/sample-invoice.pdf"
    }
  ],
  "documentType": "invoice",
  "model": "fast",
  "datasetUrlField": "url",
  "processingMode": "auto",
  "dateFormat": "auto",
  "confidenceThreshold": 0.7,
  "maxDocuments": 100,
  "maxPagesPerDocument": 30,
  "maxFileSizeMb": 25,
  "imageResolution": 1600,
  "includeFlatData": true,
  "saveCsvFiles": true,
  "includeRawText": false,
  "concurrency": 3,
  "maxRetries": 2,
  "requestTimeoutSecs": 180,
  "maxOutputTokens": 12000
}
```

# Actor output Schema

## `overview` (type: `string`):

One row per document: type, confidence, validation, needs review.

## `data` (type: `string`):

Full extracted JSON per document.

## `csv` (type: `string`):

Flattened fields of every extracted document.

## `files` (type: `string`):

CSV files, run summary and state in the key-value store.

## `summary` (type: `string`):

Totals, review counts, AI cost, errors and CSV links.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "documentUrls": [
        {
            "url": "https://api.apify.com/v2/key-value-stores/xBqlN4kRAyAIWZpIU/records/sample-invoice.pdf"
        }
    ],
    "documentType": "invoice"
};

// Run the Actor and wait for it to finish
const run = await client.actor("rs-automation-labs/ai-document-extractor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "documentUrls": [{ "url": "https://api.apify.com/v2/key-value-stores/xBqlN4kRAyAIWZpIU/records/sample-invoice.pdf" }],
    "documentType": "invoice",
}

# Run the Actor and wait for it to finish
run = client.actor("rs-automation-labs/ai-document-extractor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "documentUrls": [
    {
      "url": "https://api.apify.com/v2/key-value-stores/xBqlN4kRAyAIWZpIU/records/sample-invoice.pdf"
    }
  ],
  "documentType": "invoice"
}' |
apify call rs-automation-labs/ai-document-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,rs-automation-labs/ai-document-extractor"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/HaUTwQQqFUeTZGXce/builds/MMJUtdC1bBF5EhkaG/openapi.json
