Documents and media
PDF to JSON with Your Own Schema: Invoices, Forms, Quotes
Pass document URLs and a JSON Schema describing the object you want (invoice number, line items, totals, form fields, dates) and get back one JSON object per document in exactly that shape, with a confidence score per field and a list of fields that were not found.
PDF & Document to JSON Extractor (AI) — Invoices, Forms. Pay per result; see the Store page for current pricing.
The source and its limits
Documents are read from public URLs, your own key-value stores (kvs://) or data: URLs: PDF with a text layer, DOCX, HTML, Markdown and plain text. They go through a layout engine first (headings, tables, lists and page markers), so table rows stay rows and labels stay next to their values.
The schema input is a JSON Schema (draft-07 subset): type: object at the top, field types string, number, integer, boolean, array and object, with description, format (date, date-time, email, uri) and enum. Nested objects and arrays of objects work; $ref, oneOf and anyOf do not.
Three extractors
rules: no language model. It collects label/value pairs, tables, numbered form fields, dates, amounts, emails, phone numbers and URLs and matches them to your field names and descriptions, coercing types. Every value is verbatim from the document.byok: Claude fills the schema with the Anthropic API key you supply, on afast,balancedorbesttier. Items record tokens used.hosted: Claude on the Actor's own key. This is what an emptyextractormeans when the Actor's model key is configured. If the model cannot be reached, the document gets the rules extraction instead, markedrules-fallback.
In model modes, document text is sent to the Anthropic API only to produce the extraction. Each mode is priced differently; see the Store page.
Limits worth knowing
- Scanned PDFs without a text layer return a
NO_TEXTerror item. Convert them first with the PDF to Markdown Actor with OCR on, save the Markdown to a key-value store, and pass thekvs://reference. - Schemas can be up to 6 levels deep and 200 fields. Model modes cut documents at
maxInputTokens(at most 40,000, about 60 pages) and cap output at 4,000 tokens per document, so very long line-item tables may be cut. - The rules extractor's date and amount parsing is tuned to English-language business documents.
- URLs that resolve to private or local network addresses are rejected.
Fields you get
| Field | What it holds |
|---|---|
data | The filled object, in the shape of your schema; fields not found are null |
confidence, overallConfidence | A score per field and for the whole document |
filledFields, totalFields, missingFields | What was and was not found |
extractionMethod, extractionNotes | rules, byok, hosted or rules-fallback, and where each value came from |
lowConfidenceFields | Model modes: fields the model was unsure about |
url, filename, mimeType, pages, title, author | The source document |
textPreview, markdown | A 1,000-character preview; the full text with includeMarkdown |
needsOcrPages, warnings | Pages without text and conversion notes |
Example output
IRS Form W-9 extracted with the rules extractor and the quick-start schema (from the Actor's README; shortened):
{
"recordType": "document",
"url": "https://www.irs.gov/pub/irs-pdf/fw9.pdf",
"filename": "fw9.pdf",
"pages": 6,
"extractionMethod": "rules",
"data": {
"title": "Form W-9 (Rev. March 2024)",
"formNumber": "W-9",
"revisionDate": "2024-03",
"issuer": "Department of the Treasury",
"fields": [
{
"label": "Name of entity/individual",
"description": "An entry is required. …"
},
{
"label": "Business name/disregarded entity name, if different from above",
"description": null
},
{
"label": "City, state, and ZIP code",
"description": null
}
]
},
"confidence": {
"title": 0.8,
"formNumber": 0.6,
"revisionDate": 0.6,
"issuer": 0.4,
"fields": 0.5
},
"overallConfidence": 0.58,
"filledFields": 5,
"totalFields": 5,
"missingFields": [],
"fetchedAt": "2026-10-17T10:22:02.464Z"
}
Use cases
Invoices to line items
Describe vendor, invoice number, dates, totals and a lineItems array once, then send every invoice through the same schema. Field descriptions guide both the rules matcher and the model.
Batch form fields
Run several government forms through one schema to get each form's number, revision date, issuer and numbered fields as JSON.
Supplier quotes and specifications
The Actor's task examples turn a supplier quote into line items and a roofing specification PDF into a takeoff of the roof system and materials.
How to run it
You need an Apify account and its API token (Console → Settings → API & Integrations). Each run is billed per result to your account; set a maximum total charge for the run to cap spend.
With curl
The sync endpoint starts a run, waits up to 300 seconds and returns the dataset items. Two IRS form PDFs through one small schema with the rules extractor (no model):
export APIFY_TOKEN=<your Apify API token>
curl -sS -X POST \
"https://api.apify.com/v2/acts/owlabee~pdf-to-json/run-sync-get-dataset-items" \
-H "Authorization: Bearer ${APIFY_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"urls": [
"https://www.irs.gov/pub/irs-pdf/fw9.pdf",
"https://www.irs.gov/pub/irs-pdf/fw4.pdf"
],
"schema": {
"type": "object",
"properties": {
"title": {
"type": "string",
"description": "Title of the form"
},
"formNumber": {
"type": "string",
"description": "The form number, e.g. W-9 or 1040"
},
"revisionDate": {
"type": "string",
"format": "date",
"description": "Revision date of the form"
},
"issuer": {
"type": "string",
"description": "Agency or organization that issues the form"
}
}
},
"extractor": "rules",
"includeMarkdown": false
}'
From an AI agent (MCP)
Apify hosts an MCP server. This config exposes only this Actor to the agent:
{
"mcpServers": {
"owlabee-pdf-to-json": {
"url": "https://mcp.apify.com/?tools=owlabee/pdf-to-json",
"headers": {
"Authorization": "Bearer ${APIFY_TOKEN}"
}
}
}
}
Then ask, for example: Extract the invoice number, invoice date, vendor, total and line items from these three PDF invoices as JSON.
Python, Node.js and more examples
Runnable curl.sh, python.py, node.mjs and mcp.json files for this Actor are in examples/pdf-to-json on GitHub.
FAQ
Which extractor should I use?
Use rules for well-labeled documents with a known layout, bulk first passes, and data that must not go to a model. Use a model mode for fields that need reading comprehension or long, messy documents.
How do I write the schema?
As ordinary JSON Schema. Descriptions matter in every mode: the rules extractor matches them against labels, and the model reads them as instructions. Use format: "date" for ISO dates and enum for fixed choices.
Is my Anthropic key safe in byok mode?
It is stored as an encrypted secret input, sent only to api.anthropic.com, and never logged or written to the dataset.
What happens if the model fails?
The document gets the rules extraction, marked rules-fallback with the reason, so a run does not fail because of the model.
Does it work on scanned documents?
Not directly. Run them through the PDF to Markdown Actor with OCR first, then pass the saved Markdown by kvs:// reference.