Nine OCR models, source citations per field

Document extraction API
with source citations.

Extract schema-validated JSON from PDFs and images. Request field grounding to trace values to source pages and elements, then review the evidence before using the data.

Citations per fieldocr_model and llm_model separateSync, async, or batch
1
2
3
b1 title
PAYMENT AUTHORIZATION
b2 field
Account
4021-8837
b3 field
Date
May 2025
b4 table
ItemAmount
Consulting$4,636.40
Adjustment-$318.20
Total$4,318.20
b5 checkbox
PaidPending
b6 signature
readingpaddleocr-vl-1.6
analyzing
0/6 elements
[ example ]

Extract an amount and inspect its source citation

This example reuses a completed parse job and fills a JSON schema. Set grounding to field and choose a model that supports grounding to receive source citations.

Request: POST /extract
curl https://api.openparser.dev/extract \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F 'request={"parse_job_id":"7f9f2f3d-0f8a-4f0a-9a2b-2f6f0a7d2c11","llm_model":"openai/gpt-5.6-terra","schema":{"type":"object","properties":{"total":{"type":"number"}},"required":["total"],"additionalProperties":false},"grounding":"field"};type=application/json'
Abbreviated extraction response
{
  "output": {
    "total": 4318.2
  },
  "parsed_document": {
    "output_format": "openparser@1",
    "document_id": "doc_3f9a2c",
    "provenance": {
      "provider": "paddle",
      "model": "paddleocr-vl-1.6"
    },
    "text": "Total due: $4,318.20",
    "markdown": "Total due: $4,318.20\n",
    "pages": [
      {
        "number": 1,
        "width": 1700,
        "height": 2200,
        "unit": "pixel",
        "element_ids": [
          "elem-total"
        ],
        "reading_order": [
          "elem-total"
        ]
      }
    ],
    "elements": [
      {
        "id": "elem-total",
        "kind": "text",
        "role": "paragraph",
        "text": "Total due: $4,318.20",
        "spans": [
          {
            "start": 0,
            "end": 20
          }
        ],
        "locations": [
          {
            "page_number": 1,
            "bbox": {
              "left": 14,
              "top": 53,
              "right": 146,
              "bottom": 123
            }
          }
        ],
        "confidence": {
          "score": 0.98,
          "scope": "recognition",
          "calibrated": false
        }
      }
    ],
    "relations": [],
    "text_annotations": [],
    "assets": []
  },
  "llm_model": "openai/gpt-5.6-terra",
  "grounding": {
    "mode": "field",
    "fields": [
      {
        "path": "total",
        "citations": [
          {
            "element_id": "elem-total",
            "page_number": 1,
            "bbox": {
              "left": 14,
              "top": 53,
              "right": 146,
              "bottom": 123
            },
            "source_type": "text",
            "granularity": "element",
            "confidence": {
              "score": 0.98,
              "scope": "recognition",
              "calibrated": false
            }
          }
        ]
      }
    ]
  },
  "attempts": [
    {
      "attempt": 1,
      "status": "succeeded",
      "llm_model": "openai/gpt-5.6-terra"
    }
  ]
}

Use the citation element_id and page location to find the source in parsed_document. OCR confidence describes recognition quality; it is not a probability that the extracted value is correct.

[ api ]

Extract returns schema JSON with source citations

Call /extract after /parse, or queue extract jobs async and in batch. Poll /jobs for status and results.

endpointsapi.openparser.dev
  • Full API reference
POST/extractrequest
curl https://api.openparser.dev/extract \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F 'request={"parse_job_id":"7f9f2f3d-0f8a-4f0a-9a2b-2f6f0a7d2c11","llm_model":"openai/gpt-5.6-terra","schema":{"type":"object","properties":{"total":{"type":"number"}},"required":["total"],"additionalProperties":false},"grounding":"field"};type=application/json'
response200 · 2.3s
{
  "output": {
    "total": 4318.2
  },
  "parsed_document": {
    "output_format": "openparser@1",
    "document_id": "doc_3f9a2c",
    "provenance": {
      "provider": "paddle",
      "model": "paddleocr-vl-1.6"
    },
    "text": "Total due: $4,318.20",
    "markdown": "Total due: $4,318.20\n",
    "pages": [
      {
        "number": 1,
        "width": 1700,
        "height": 2200,
        "unit": "pixel",
        "element_ids": [
          "elem-total"
        ],
        "reading_order": [
          "elem-total"
        ]
      }
    ],
    "elements": [
      {
        "id": "elem-total",
        "kind": "text",
        "role": "paragraph",
        "text": "Total due: $4,318.20",
        "spans": [
          {
            "start": 0,
            "end": 20
          }
        ],
        "locations": [
          {
            "page_number": 1,
            "bbox": {
              "left": 14,
              "top": 53,
              "right": 146,
              "bottom": 123
            }
          }
        ],
        "confidence": {
          "score": 0.98,
          "scope": "recognition",
          "calibrated": false
        }
      }
    ],
    "relations": [],
    "text_annotations": [],
    "assets": []
  },
  "llm_model": "openai/gpt-5.6-terra",
  "grounding": {
    "mode": "field",
    "fields": [
      {
        "path": "total",
        "citations": [
          {
            "element_id": "elem-total",
            "page_number": 1,
            "bbox": {
              "left": 14,
              "top": 53,
              "right": 146,
              "bottom": 123
            },
            "source_type": "text",
            "granularity": "element",
            "confidence": {
              "score": 0.98,
              "scope": "recognition",
              "calibrated": false
            }
          }
        ]
      }
    ]
  },
  "attempts": [
    {
      "attempt": 1,
      "status": "succeeded",
      "llm_model": "openai/gpt-5.6-terra"
    }
  ]
}
[ console ]

Test /extract with your schema in the playground

Upload a document, define fields, and inspect schema-filled JSON with source citations before calling /extract from production.

openparser.dev/playgroundsigned in
playgroundno code
statement.pdf1 page · 48 KB
parsePaddleOCR-VLMistral OCRAzure DITextract9 models
extractClaudeGPT-4oLlamalocalany LLM
Run{ total: "$4,318.20" } b4
[ output ]

Schema JSON with element_id citations

Typed elements carry ids. Extraction references element_id instead of inventing coordinates, so a bad citation fails lookup.

Schema you control

You define the JSON shape. The API fills vendor_name, line_items, totals, or any fields your pipeline expects.

b1
0.99
b4
0.98
b6
0.70

Validation-friendly

Typed output and per-field citations give you concrete checks for schema validation and human review.

Parser and LLM split

ocr_model handles layout and OCR. llm_model handles extraction. Change either without rewriting the other step.

schema {
total
}
{
total: "$4,318"
}

Choose the extraction LLM

Point a schema at a parse and fill it with Claude, GPT, or a model you host. Parsing does not lock the extract model.

b4

Citation-backed output

grounding.fields[] ties each value to element_id and bbox from the parse. You audit values against the elements they cite.

b2b4b6
x, y, w, h

No invented geometry

Citations reference element_id values from the parsed document. A missing id fails your lookup instead of pointing at empty space.

[ pricing ]

Parse bills by page; extract bills by token

New accounts get $10 in credits at signup (about 10,000 pages at $1/1,000 on open-weight hosted models). Extraction adds the token cost of whichever llm_model you set on /extract.

parse
$1/ 1,000 pages
$10 credits at signup
+
extract
Per token
billed by llm_model
  • Per-page parse pricing
  • Per-token extraction
  • Sync, async, batch
  • Source citations
  • API keys in console
Create an API key
[ questions ]

Extraction API FAQ

Schema input, citations, models, and billing for structured document extraction.

What do I send to the extraction endpoint?

You send a parse job id (or parse a file first), a JSON schema, an llm_model, and a grounding mode. The API fills your schema from the parsed elements and returns citations per field.

How do I request extraction with source citations?

Set grounding to field and choose an llm_model that supports field grounding. The response includes grounding metadata and, when it fits the result size limit, a lineage derivation graph. Inspect citations in the returned parsed_document to review the evidence for each field.

How do source citations work?

Each extracted field can list one or more citations with element_id, page_number, bbox, source_type, and confidence. You map element_id back to the parsed document to highlight the source region.

Can I pick the parser and extraction model separately?

Yes. Parsing uses ocr_model across nine hosted engines (Paddle, Mistral, Azure, Google, AWS Textract, and others). Extraction uses llm_model, which you set independently on the extract request.

Does extraction cost the same as parsing?

No. Open-weight hosted parsing starts at $1 per 1,000 pages; other OCR models have their own rates. Extraction adds language-model token costs. Reusing a completed parse job avoids another OCR page charge. New accounts get $10 in free credits.

Can I run extraction sync, async, or in batch?

Yes. /extract, /extract/async, and /extract/batch mirror the parse endpoints. Poll /jobs/{id} for async and batch results.

How do I review extraction evidence?

Use each citation to locate its element and page region in parsed_document. Compare the quoted source with the extracted value. Source citations support review; they do not guarantee that every value is correct.

Test /extract with your schema

Upload a PDF and run /extract in Studio

Define your JSON schema, inspect schema-filled output, and verify element_id citations before you call /extract from production.