# Document Processing API — PDF, OCR & Validated JSON (`scalogik/document-processing-api-pdf-ocr-validated-json`) Actor

Extract schema-validated JSON from PDFs, scans, images, DOCX, XLSX, emails, and text. Includes OCR, field evidence, custom rules, and workflow routing—no model API key required.

- **URL**: https://apify.com/scalogik/document-processing-api-pdf-ocr-validated-json.md
- **Developed by:** [Scalogik LLC](https://apify.com/scalogik) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 document results

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

![Document Processing API — PDF, OCR and validated JSON](https://files.manuscdn.com/user_upload_by_module/session_file/310519663080398616/BkVAFaNcdTLUaseH.png)

## Document Processing API — PDF, OCR & Validated JSON

Turn PDFs, scans, images, DOCX files, spreadsheets, emails, and text documents into **schema-validated JSON**. This AI document processing API extracts exactly the fields in your JSON Schema, returns field-level evidence, applies deterministic validation rules, and routes every document to `accepted`, `review`, or `rejected`.

**No separate model-provider API key is required.** Upload a file or send document URLs, define the JSON you need, and receive workflow-ready results through Apify Console, REST API, Python, JavaScript, schedules, webhooks, or MCP. The Actor uses Apify OpenRouter with the token of the account that starts the run, so managed model-token usage is billed separately by Apify.

> **Built for reliable automation:** constrained JSON output, local schema validation, evidence coverage, safe repair, transparent errors, and no successful-result charge when processing fails.

### What this document processing API does

Most OCR APIs return text. Most PDF-to-JSON tools return a fixed structure. This Actor lets you define a custom Draft 2020-12 JSON Schema and combines extraction with validation and routing in one run.

| Capability | What you receive |
|---|---|
| **Custom document data extraction** | Only the fields and types declared in your JSON Schema |
| **PDF and OCR processing** | Digital PDF text extraction plus visual processing for scans and images |
| **Validated JSON output** | A local schema-validation result and exact violation paths |
| **Evidence-backed extraction** | Source quote, page or section, confidence, and verification state per field |
| **Custom workflow rules** | Declarative checks such as required values, regex, equality, range, and presets |
| **Decision routing** | `accepted`, `review`, or `rejected` for each document |
| **Batch safety** | Per-document errors, fail-fast control, document limits, and spending-limit stop |
| **Managed AI** | Gemini extraction through Apify OpenRouter; no separate provider key, with model-token usage billed by Apify to the run starter |

### Supported document formats

The API accepts PDF, PNG, JPEG, WEBP, DOCX, XLSX, EML, CSV, JSON, HTML, Markdown, and plain text. Digital documents are parsed locally when possible. Scanned PDFs and direct image uploads are normalized into bounded JPEG inputs before managed visual extraction, preventing oversized base64 requests.

| Format group | Examples | Processing path |
|---|---|---|
| PDF | Digital and scanned PDF | Local text extraction or bounded page rendering |
| Images | PNG, JPEG, WEBP | Multimodal visual extraction |
| Office | DOCX, XLSX | Local text and cell extraction |
| Email | EML | Headers and plain/HTML body extraction |
| Structured text | CSV, JSON, HTML, Markdown, TXT | Local normalization before extraction |

### Common use cases

| Workflow | Example JSON fields |
|---|---|
| **Invoice extraction API** | invoice number, dates, supplier, VAT ID, currency, line items, totals |
| **Receipt OCR API** | merchant, transaction date, tax, total, payment method |
| **Purchase-order processing** | PO number, buyer, supplier, SKUs, quantities, delivery date |
| **Certificate-of-Analysis parser** | batch, analyte, method, specification, result, unit, pass/fail |
| **Safety Data Sheet extraction** | product, CAS numbers, hazards, PPE, transport class |
| **Freight document automation** | BOL number, shipper, consignee, freight class, weight, accessorials |
| **Application and onboarding forms** | applicant fields, missing evidence, validation status |
| **Email attachment workflows** | normalized message fields and document-derived business data |

### Quick start: extract an invoice to JSON

Use the prefilled example in Apify Console for a safe first run. For your own document, provide one file and a schema:

```json
{
  "document": "https://example.com/invoice.pdf",
  "outputSchema": {
    "type": "object",
    "properties": {
      "invoiceNumber": { "type": ["string", "null"] },
      "invoiceDate": { "type": ["string", "null"] },
      "supplierName": { "type": ["string", "null"] },
      "currency": { "type": ["string", "null"] },
      "total": { "type": ["number", "null"] }
    },
    "required": ["invoiceNumber", "invoiceDate", "supplierName", "currency", "total"],
    "additionalProperties": false
  },
  "validationRules": [
    {
      "field": "currency",
      "operator": "matchesPreset",
      "preset": "currencyCode",
      "severity": "error"
    },
    {
      "field": "total",
      "operator": "gte",
      "value": 0,
      "severity": "error"
    }
  ],
  "routePolicy": "standard",
  "includeEvidence": true
}
```

The Actor returns one dataset row per document:

```json
{
  "documentId": "330e4f07fb30a813",
  "filename": "invoice.pdf",
  "status": "success",
  "route": "accepted",
  "schemaValid": true,
  "data": {
    "invoiceNumber": "INV-2026-0042",
    "invoiceDate": "2026-09-02",
    "supplierName": "Northwind Components OÜ",
    "currency": "EUR",
    "total": 186.0
  },
  "evidence": {
    "total": [
      {
        "value": "186.00",
        "quote": "Total: 186.00 EUR",
        "page": 1,
        "confidence": 1.0,
        "verified": true
      }
    ]
  },
  "evidenceCoverage": 1.0,
  "violations": [],
  "warnings": [],
  "processing": {
    "model": "google/gemini-2.5-flash",
    "attempts": 1,
    "durationMs": 5178,
    "modelCostUsd": 0.0024
  },
  "error": null
}
```

`modelCostUsd` is the diagnostic managed-model cost observed during processing. It corresponds to the separate Apify OpenRouter model-token usage billed to the account that starts the run; it is not an additional Scalogik Actor event charge.

### Define your validated JSON output

`outputSchema` uses a safe subset of JSON Schema Draft 2020-12.[1] The root must be an object. Supported field types are object, array, string, number, integer, boolean, and null. Nested objects and arrays are supported within launch limits.

Use nullable required fields when a document may omit information:

```json
{
  "type": "object",
  "properties": {
    "policyNumber": { "type": ["string", "null"] },
    "insuredValue": { "type": ["number", "null"] }
  },
  "required": ["policyNumber", "insuredValue"],
  "additionalProperties": false
}
```

This structure forces the model to return predictable keys while preserving an explicit `null` when the source does not contain a value.

### Add deterministic validation rules

AI extracts the fields; deterministic code evaluates your business checks. Rules use dotted field paths such as `supplier.vatId` or `lineItems.0.sku`.

| Operator | Purpose | Example |
|---|---|---|
| `required` / `exists` | Field must contain a value | Invoice number is present |
| `equals` / `notEquals` | Exact value comparison | Currency equals `EUR` |
| `contains` | String or array membership | Description contains a term |
| `regex` | Full-string pattern validation with a short safety timeout | Internal reference format |
| `gt`, `gte`, `lt`, `lte` | Numeric comparison | Total is greater than zero |
| `in` | Value belongs to an allowlist | Document type is permitted |
| `matchesPreset` | Common formats | Email, ISO date, currency code, VAT ID |

Rules have `error` or `warning` severity. The `standard` route policy sends schema or rule errors to `rejected`, warnings or evidence coverage below 60% to `review`, and clean results to `accepted`. The `conservative` policy reviews warnings or coverage below 90%; `strict` also rejects warnings or incomplete evidence; `review_all` sends every schema-valid, rule-clean extraction to review.

### Evidence and review queues

Each populated scalar field can include a verbatim source quote and page or section reference. Evidence from locally extracted text is checked against the source and marked `verified: true` or `false`. Visual-only evidence is marked `verified: null` because there is no independent text layer against which to compare it.

`evidenceCoverage` reports the share of populated scalar fields with evidence. This makes it possible to route incomplete extractions to review without treating model confidence as proof.

### API integration

Apify generates REST, Python, JavaScript, CLI, webhook, schedule, and MCP integration options for every Actor.[2]

#### REST API

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/scalogik~document-processing-api-pdf-ocr-validated-json/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d @input.json
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("scalogik/document-processing-api-pdf-ocr-validated-json").call(
    run_input={
        "document": "https://example.com/invoice.pdf",
        "outputSchema": {
            "type": "object",
            "properties": {
                "invoiceNumber": {"type": ["string", "null"]},
                "total": {"type": ["number", "null"]},
            },
            "required": ["invoiceNumber", "total"],
            "additionalProperties": False,
        },
    }
)
items = list(client.dataset(run["defaultDatasetId"]).iterate_items())
```

#### JavaScript

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

const client = new ApifyClient({ token: '<APIFY_TOKEN>' });
const run = await client.actor('scalogik/document-processing-api-pdf-ocr-validated-json').call({
  document: 'https://example.com/invoice.pdf',
  outputSchema: {
    type: 'object',
    properties: {
      invoiceNumber: { type: ['string', 'null'] },
      total: { type: ['number', 'null'] },
    },
    required: ['invoiceNumber', 'total'],
    additionalProperties: false,
  },
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

#### MCP and AI agents

After publication, add the Actor through Apify’s hosted MCP server. OAuth-capable clients can connect without placing an API token in the MCP configuration.[3]

```text
https://mcp.apify.com/?tools=fetch-actor-details,scalogik/document-processing-api-pdf-ocr-validated-json
```

### Input reference

| Input | Type | Required | Description |
|---|---|---:|---|
| `document` | File/URL string | One source | Single-click upload or HTTPS file URL |
| `documentUrls` | URL array | One source | Batch of public HTTPS documents |
| `inlineDocuments` | Object array | One source | API-supplied text with filename and MIME type |
| `outputSchema` | JSON object | Yes | Required validated output structure |
| `extractionInstructions` | String | No | Field interpretation or workflow context |
| `validationRules` | Object array | No | Up to five deterministic checks |
| `routePolicy` | Enum | No | `standard`, `strict`, or `review_all` |
| `pdfMode` | Enum | No | `auto`, `digital`, or `scanned` |
| `includeEvidence` | Boolean | No | Return source evidence; default `true` |
| `includeRawText` | Boolean | No | Return bounded source text; default `false` |
| `failFast` | Boolean | No | Stop after the first processing error |
| `maxDocuments` | Integer | No | Run limit from 1 to 20 |

You may combine an uploaded `document`, `documentUrls`, and `inlineDocuments` in one run, up to `maxDocuments`. Results retain a stable one-row-per-source order.

### Output reference

| Field | Meaning |
|---|---|
| `status` | `success`, `partial`, or `error` |
| `route` | `accepted`, `review`, or `rejected` |
| `schemaValid` | Whether `data` satisfies the requested schema |
| `data` | Extracted custom JSON object |
| `evidence` | Field-indexed quotes, location, confidence, and verification |
| `evidenceCoverage` | Evidence coverage from 0 to 1 |
| `violations` | Schema and deterministic-rule failures |
| `warnings` | Non-fatal extraction, evidence, or format warnings |
| `document` | MIME type, size, page count, and SHA-256 hash |
| `processing` | Model, parser path, attempts, duration, tokens, and model cost |
| `error` | Stable safe error code, message, and retryability |

### Pricing

The Scalogik Actor price is **$0.02 per successful or partial document result**, plus **$0.00005 per Actor start**. Error results do not receive the `document-processed` charge. The Actor’s own platform usage is included in this event price. The managed extraction call uses `apify/openrouter` with the account token for the user who starts the run; Apify bills that account separately for actual model-token usage. Customers need no separate OpenAI, Gemini, or OpenRouter provider key, but should allow for this additional Apify usage charge.

| Processed documents | Approximate event price |
|---:|---:|
| 1 | $0.02005 |
| 100 | $2.00005 |
| 1,000 | $20.00005 |

These estimates exclude any optional costs created outside this Actor, such as storing a source file on another service.

### Security and privacy

Documents are processed in memory for the run and are not copied into Actor storage. Raw text is excluded from output by default. Stored source URLs omit user information, query strings, and fragments. The downloader rejects non-HTTPS URLs, URL credentials, loopback and private-network destinations, blocked DNS resolutions, unsafe redirects, oversized files, and unsupported content types.

The managed request denies provider data collection where supported. Nevertheless, this service sends document content to a managed model provider for extraction. Do not process documents unless you have the necessary rights, notices, agreements, and retention policy.

### Limits and honest expectations

| Limit | Launch value |
|---|---:|
| Documents per run | 20 |
| File size | 20 MiB |
| PDF pages | 50 total |
| Rendered scanned-PDF pages | 10 |
| JSON Schema properties | 150 |
| Spreadsheet cells | 50,000 |
| Validation rules | 5 |
| Model repair passes | 1 |

No document AI system is perfect. Poor scans, handwriting, complex nested tables, password-protected files, malformed documents, and ambiguous values can produce errors or review results. Use `route`, `violations`, and evidence rather than assuming every extracted value is correct.

### Quality verification

The private release passed **151 automated tests** with **87.99% branch-aware coverage**. A controlled Apify Cloud benchmark extracted **70/70 expected fields** across digital PDF, scanned PDF, PNG, DOCX, XLSX, EML, and text fixtures. All seven latest format results were schema-valid, had full evidence coverage, and routed to `accepted`.

The benchmark is deliberately disclosed as a controlled fixture test; it does not predict accuracy on every real-world document. See the repository QA report for method, costs, runs, and limitations.

### FAQ

#### What is the difference between this API and a basic OCR API?

OCR converts pixels into text. This Actor converts documents into a caller-defined JSON structure, validates the output, attaches evidence, applies rules, and assigns a workflow route.

#### Can I use it as a PDF-to-JSON API?

Yes. Supply a PDF URL or upload and define the JSON Schema. Digital PDFs use local text extraction; scanned PDFs use bounded page-image processing.

#### Can it extract invoices and receipts?

Yes. Invoice and receipt fields are a common schema, but the Actor is not limited to a fixed financial-document template.

#### Do customers need an OpenAI, Gemini, or OpenRouter key?

No separate provider key is needed. The Actor uses Apify OpenRouter with the Apify token of the account that starts the run. Apify bills that account separately for actual model-token usage in addition to the Scalogik Actor event price.

#### Is the returned JSON guaranteed to match my schema?

The Actor validates the result locally. A valid result has `schemaValid: true`; a failed schema remains visible with violations and is routed according to policy. The API does not silently describe invalid JSON as valid.

#### Are failed documents charged?

The custom `document-processed` event is applied only to successful and partial result rows. Error rows are returned without that Scalogik event charge. Any managed-model token use already consumed before an error may still be charged by Apify OpenRouter.

#### Can I batch documents?

Yes. Provide up to 20 document URLs or inline documents in one run. Each input produces an independent result row.

### References

[1]: https://json-schema.org/draft/2020-12 "JSON Schema Draft 2020-12"

[2]: https://docs.apify.com/api/v2 "Apify API v2"

[3]: https://docs.apify.com/platform/integrations/mcp "Apify MCP integration"

# Actor input Schema

## `document` (type: `string`):

Upload one PDF, DOCX, XLSX, PNG, JPEG, WebP, EML, CSV, JSON, Markdown, HTML, or UTF-8 text document. API callers can provide an HTTPS URL.

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

Optional HTTPS URLs for batch processing. Each file may be up to 20 MiB; total documents cannot exceed maxDocuments.

## `inlineDocuments` (type: `array`):

Optional text records for direct API calls. Each object needs filename and text; mimeType is optional.

## `outputSchema` (type: `object`):

Draft 2020-12 JSON Schema for the extracted data object. Use nullable fields when a document may legitimately omit a value.

## `extractionInstructions` (type: `string`):

Optional business context or field interpretation guidance. Instructions inside uploaded documents are ignored.

## `validationRules` (type: `array`):

Optional deterministic checks. Operators: required or exists, equals, notEquals, contains, regex, gt, gte, lt, lte, in, and matchesPreset. Regex rules use full-string matching and a short safety timeout.

## `routePolicy` (type: `string`):

Standard accepts clean results and sends warnings or incomplete evidence to review. Conservative reviews coverage below 90%. Strict rejects warnings. Review all sends every successful extraction to manual review.

## `pdfMode` (type: `string`):

Auto uses selectable text when available and visual extraction for scanned PDFs. Digital requires a text layer. Scanned forces page-image processing.

## `includeEvidence` (type: `boolean`):

Return source quotes, locations, confidence, and local quote-verification status for extracted fields.

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

Off by default for privacy. When enabled, output is truncated to 20,000 characters.

## `failFast` (type: `boolean`):

When false, batch runs return a transparent result record for every valid input document.

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

Maximum number of documents processed in this run.

## Actor input object example

```json
{
  "document": "https://files.manuscdn.com/user_upload_by_module/session_file/310519663080398616/ATUpqEGiovUnQJOt.txt",
  "documentUrls": [],
  "inlineDocuments": [],
  "outputSchema": {
    "type": "object",
    "properties": {
      "invoiceNumber": {
        "type": [
          "string",
          "null"
        ],
        "description": "Invoice identifier exactly as printed"
      },
      "invoiceDate": {
        "type": [
          "string",
          "null"
        ],
        "description": "Invoice date in YYYY-MM-DD format"
      },
      "currency": {
        "type": [
          "string",
          "null"
        ],
        "description": "Three-letter ISO currency code"
      },
      "supplierName": {
        "type": [
          "string",
          "null"
        ]
      },
      "supplierVatId": {
        "type": [
          "string",
          "null"
        ]
      },
      "customerName": {
        "type": [
          "string",
          "null"
        ]
      },
      "subtotal": {
        "type": [
          "number",
          "null"
        ]
      },
      "tax": {
        "type": [
          "number",
          "null"
        ]
      },
      "total": {
        "type": [
          "number",
          "null"
        ]
      },
      "dueDate": {
        "type": [
          "string",
          "null"
        ],
        "description": "Payment due date in YYYY-MM-DD format"
      }
    },
    "required": [
      "invoiceNumber",
      "invoiceDate",
      "currency",
      "supplierName",
      "supplierVatId",
      "customerName",
      "subtotal",
      "tax",
      "total",
      "dueDate"
    ],
    "additionalProperties": false
  },
  "extractionInstructions": "",
  "validationRules": [],
  "routePolicy": "standard",
  "pdfMode": "auto",
  "includeEvidence": true,
  "includeRawText": false,
  "failFast": false,
  "maxDocuments": 20
}
```

# Actor output Schema

## `results` (type: `string`):

One visible result per document with extracted data, evidence, validation, and routing.

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

Processed counts, routes, spending-limit status, model, and token totals.

# 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 = {
    "document": "https://files.manuscdn.com/user_upload_by_module/session_file/310519663080398616/ATUpqEGiovUnQJOt.txt",
    "outputSchema": {
        "type": "object",
        "properties": {
            "invoiceNumber": {
                "type": [
                    "string",
                    "null"
                ],
                "description": "Invoice identifier exactly as printed"
            },
            "invoiceDate": {
                "type": [
                    "string",
                    "null"
                ],
                "description": "Invoice date in YYYY-MM-DD format"
            },
            "currency": {
                "type": [
                    "string",
                    "null"
                ],
                "description": "Three-letter ISO currency code"
            },
            "supplierName": {
                "type": [
                    "string",
                    "null"
                ]
            },
            "supplierVatId": {
                "type": [
                    "string",
                    "null"
                ]
            },
            "customerName": {
                "type": [
                    "string",
                    "null"
                ]
            },
            "subtotal": {
                "type": [
                    "number",
                    "null"
                ]
            },
            "tax": {
                "type": [
                    "number",
                    "null"
                ]
            },
            "total": {
                "type": [
                    "number",
                    "null"
                ]
            },
            "dueDate": {
                "type": [
                    "string",
                    "null"
                ],
                "description": "Payment due date in YYYY-MM-DD format"
            }
        },
        "required": [
            "invoiceNumber",
            "invoiceDate",
            "currency",
            "supplierName",
            "supplierVatId",
            "customerName",
            "subtotal",
            "tax",
            "total",
            "dueDate"
        ],
        "additionalProperties": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scalogik/document-processing-api-pdf-ocr-validated-json").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 = {
    "document": "https://files.manuscdn.com/user_upload_by_module/session_file/310519663080398616/ATUpqEGiovUnQJOt.txt",
    "outputSchema": {
        "type": "object",
        "properties": {
            "invoiceNumber": {
                "type": [
                    "string",
                    "null",
                ],
                "description": "Invoice identifier exactly as printed",
            },
            "invoiceDate": {
                "type": [
                    "string",
                    "null",
                ],
                "description": "Invoice date in YYYY-MM-DD format",
            },
            "currency": {
                "type": [
                    "string",
                    "null",
                ],
                "description": "Three-letter ISO currency code",
            },
            "supplierName": { "type": [
                    "string",
                    "null",
                ] },
            "supplierVatId": { "type": [
                    "string",
                    "null",
                ] },
            "customerName": { "type": [
                    "string",
                    "null",
                ] },
            "subtotal": { "type": [
                    "number",
                    "null",
                ] },
            "tax": { "type": [
                    "number",
                    "null",
                ] },
            "total": { "type": [
                    "number",
                    "null",
                ] },
            "dueDate": {
                "type": [
                    "string",
                    "null",
                ],
                "description": "Payment due date in YYYY-MM-DD format",
            },
        },
        "required": [
            "invoiceNumber",
            "invoiceDate",
            "currency",
            "supplierName",
            "supplierVatId",
            "customerName",
            "subtotal",
            "tax",
            "total",
            "dueDate",
        ],
        "additionalProperties": False,
    },
}

# Run the Actor and wait for it to finish
run = client.actor("scalogik/document-processing-api-pdf-ocr-validated-json").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 '{
  "document": "https://files.manuscdn.com/user_upload_by_module/session_file/310519663080398616/ATUpqEGiovUnQJOt.txt",
  "outputSchema": {
    "type": "object",
    "properties": {
      "invoiceNumber": {
        "type": [
          "string",
          "null"
        ],
        "description": "Invoice identifier exactly as printed"
      },
      "invoiceDate": {
        "type": [
          "string",
          "null"
        ],
        "description": "Invoice date in YYYY-MM-DD format"
      },
      "currency": {
        "type": [
          "string",
          "null"
        ],
        "description": "Three-letter ISO currency code"
      },
      "supplierName": {
        "type": [
          "string",
          "null"
        ]
      },
      "supplierVatId": {
        "type": [
          "string",
          "null"
        ]
      },
      "customerName": {
        "type": [
          "string",
          "null"
        ]
      },
      "subtotal": {
        "type": [
          "number",
          "null"
        ]
      },
      "tax": {
        "type": [
          "number",
          "null"
        ]
      },
      "total": {
        "type": [
          "number",
          "null"
        ]
      },
      "dueDate": {
        "type": [
          "string",
          "null"
        ],
        "description": "Payment due date in YYYY-MM-DD format"
      }
    },
    "required": [
      "invoiceNumber",
      "invoiceDate",
      "currency",
      "supplierName",
      "supplierVatId",
      "customerName",
      "subtotal",
      "tax",
      "total",
      "dueDate"
    ],
    "additionalProperties": false
  }
}' |
apify call scalogik/document-processing-api-pdf-ocr-validated-json --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scalogik/document-processing-api-pdf-ocr-validated-json"
        }
    }
}

```

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/7xiMf3m1Srws9eDlY/builds/UP9dWGeDgVEoREWSH/openapi.json
