openparser@1 reference
Full reference for the versioned openparser@1 document graph, raw envelope, and consumption patterns.
openparser@1 is the versioned document graph for OCR parse results. Pages
establish coordinate spaces, elements carry semantic payloads, and relations
preserve hierarchy and cross-element meaning without duplicating trees.
@openparser/schema publishes the Zod schemas and TypeScript types for this
graph and for the separate raw envelope. Validate results with
ParsedDocumentSchema, type adapter output with ParsedDocumentWithElementKinds,
and share one canonical graph definition across providers.
Install and import
npm install @openparser/schemaImport from the package root (@openparser/schema):
import {
ParsedDocumentSchema,
RawParseResultSchema,
OcrOutputFormatSchema,
type ParsedDocument,
type RawParseResult,
type ParsedDocumentWithElementKinds,
} from '@openparser/schema';Validate at runtime with ParsedDocumentSchema.parse(json) or narrow adapter output with ParsedDocumentWithElementKinds<'text' | 'table'> when you know which element kinds a converter may emit.
ParsedDocument graph
type ParsedDocument = {
output_format: 'openparser@1';
document_id: string;
provenance: DocumentProvenance;
text: string;
markdown: string;
pages: DocumentPage[];
elements: DocumentElement[];
relations: DocumentRelation[];
text_annotations: TextAnnotation[];
assets: DocumentAsset[];
};| Field | Role |
|---|---|
output_format | Schema version. Always openparser@1 on this shape. |
document_id | Stable identifier for the parsed document. |
provenance | Provider and model metadata for the canonical graph. |
text | Plain reading-order text. Every span indexes into this string. |
markdown | Best-effort Markdown rendering of the graph. |
pages | One-based coordinate spaces with reading order and optional page images. |
elements | Text, tables, figures, and related semantic payloads. |
relations | Directed links (containment, captions, footnotes, reading order). |
text_annotations | Language and style metadata over UTF-16 spans in text. |
assets | Page and figure images by URI or base64 payload. |
Start with elements
Use elements and pages.reading_order for most integrations. Reach for relations when you
need hierarchy, text_annotations for range-based style or language metadata, and assets for
page or figure images.
Pages and reading order
type DocumentPage = {
number: number;
width: number;
height: number;
unit: 'pixel' | 'point' | 'inch' | 'normalized';
element_ids: string[];
reading_order: string[];
/** Optional aggregate recognition/detection confidence for the page. */
confidence?: Confidence;
/** Image/page quality signals (scores, defects, metrics) — distinct from confidence. */
quality?: PageQuality;
image_asset_id?: string;
};reading_order is an ordered subset of that page's element_ids. It lists top-level content — not both a parent and all of its descendants. Page numbers are contiguous and one-based (1 … N). Use pages[].confidence for provider page-level OCR aggregates; reserve pages[].quality for image-quality scores, defects, and related metrics.
Elements
Each element has a stable id, one or more locations, optional confidence, and a discriminated kind:
type DocumentElement =
| TextElement
| TableElement
| FigureElement
| FormulaElement
| KeyValueElement
| QueryAnswerElement
| SectionElement
| SelectionMarkElement
| SignatureElement
| BarcodeElement
| LinkElement
| StampElement
| OtherElement;Text elements carry role (heading, paragraph, line, word, page_header, page_footer, …), inline text, UTF-16 spans into ParsedDocument.text, and locations.
Tables expose row_count, column_count, and cells with row_index, column_index, optional row_span / column_span, per-cell text and spans, and optional html / markdown renderings. Table cell ids share the document's global id namespace — citations can target cells directly.
Figures may reference an asset_id, optional caption with caption_spans, and alt_text.
Key-value and query-answer elements wrap StructuredValue objects (text, spans, element_ids, locations, optional confidence).
Word- and symbol-level text elements appear only when the provider and requested options return that granularity.
Geometry
type Geometry = {
page_number: number;
bbox: BoundingBox;
polygon?: Point[];
rotation_degrees?: number;
};
type BoundingBox = {
left: number;
top: number;
right: number;
bottom: number;
};Bounding boxes use page-local coordinates. right and bottom are exclusive — width is right - left, height is bottom - top. A polygon is optional when the source provides a tighter outline than the axis-aligned box.
UTF-16 spans
type TextSpan = {
start: number;
end: number;
};Spans are half-open UTF-16 code-unit offsets into ParsedDocument.text. JavaScript consumers can slice with text.slice(start, end) without provider-specific indexing. Python and other UTF-16-aware runtimes should use the same code-unit semantics.
Confidence
type Confidence = {
score: number; // normalized to [0, 1]
scope: 'detection' | 'recognition' | 'classification' | 'geometry' | 'answer' | 'quality';
calibrated: boolean; // default false
source_value?: number;
source_scale?: 'zero_to_one' | 'zero_to_hundred' | 'log_probability' | 'unknown';
};calibrated: false means scores from different providers or scopes must not be compared as equivalent probabilities. When present, source_value and source_scale preserve the provider's original scale. Confidence may appear on elements, structured values, text annotations, pages (pages[].confidence for page-level OCR aggregates), and other payloads. Image-quality scores and defects belong on pages[].quality, not pages[].confidence.
Relations and text annotations
type DocumentRelation = {
type: 'contains' | 'precedes' | 'caption_of' | 'footnote_of' | /* ... */;
from_id: string;
to_id: string;
};
type TextAnnotation = {
id: string;
spans: TextSpan[];
languages?: Language[];
style?: TextStyle;
confidence?: Confidence;
};contains points from parent to child. caption_of and footnote_of point from the annotation element to its target. Text annotations require language or style data and attach to spans in text, not duplicate inline element text.
Assets
type DocumentAsset = {
id: string;
kind: 'page_image' | 'figure' | 'embedded_image' | 'other';
uri?: string;
data_base64?: string;
mime_type?: string;
page_number?: number;
width?: number;
height?: number;
sha256?: string;
};Each asset requires uri or data_base64. width and height must be provided together. Pages reference page images through image_asset_id; figures reference crops through asset_id.
Raw envelope
When you request output_format: "raw", the parse API returns the provider-native JSON wrapped in a generic envelope:
type RawParseResult = {
output_format: 'raw';
provider: string;
model: string;
profile: {
name: string;
options: Record<string, unknown>;
};
result: Record<string, unknown>;
};RawParseResultSchema validates this envelope only — it does not schema-check provider payloads inside result. Use raw when you need untouched vendor JSON; use openparser@1 when you want the shared graph.
Invariants
The shipped Zod schemas enforce document consistency:
- Page numbers are contiguous and one-based.
- Element and table-cell ids are unique across the document.
- Spans reference valid UTF-16 ranges in
text. - Locations reference valid page numbers and positive bounding boxes.
- Table cells do not overlap and stay within declared row/column counts.
- Tables whose expanded row coverage (Σ
row_spanper cell) exceeds a structural validation limit are rejected — this bounds overlap checking for very large or pathological grids without capping ordinary OCR-sized tables. - Assets provide
uriordata_base64; width and height appear together. - All object schemas are strict — unknown keys are rejected.
Adapters may emit conservative subsets (for example tables without geometry). The schema describes the full graph; a given parse may omit optional fields or element kinds.
Evolution policy
openparser@1 is strict and frozen for this output_format identifier. Any field addition or shape change that existing ParsedDocumentSchema rejects requires a new output_format revision (for example openparser@2). The API will not silently grow incompatible fields under openparser@1.
Provider adapters version their converters separately (@openparser/adapters@<semver>#<provider>) without bumping the document schema unless the graph shape changes.
Practical consumption
| Goal | Approach |
|---|---|
| Reading-order text | text or markdown |
| Layout + citations | Walk pages.reading_order, then elements / table cells |
| Hierarchy | Follow relations with type: 'contains' |
| Highlight on page image | Map locations[].bbox using page width / height |
| Language or font metadata | text_annotations spans into text |
| Page or figure raster | Resolve assets by id from image_asset_id / asset_id |
| Provider-native JSON | Request output_format: "raw" or read nativeResult from @openparser/adapters clients |
Example
{
"output_format": "openparser@1",
"document_id": "doc_01h2example",
"provenance": {
"provider": "paddle",
"model": "paddleocr-vl-1.6"
},
"text": "# Invoice\n\nTotal due: $1,234.56",
"markdown": "# Invoice\n\nTotal due: $1,234.56\n",
"pages": [
{
"number": 1,
"width": 1700,
"height": 2200,
"unit": "pixel",
"element_ids": ["elem-title", "elem-total"],
"reading_order": ["elem-title", "elem-total"]
}
],
"elements": [
{
"id": "elem-title",
"kind": "text",
"role": "heading",
"text": "# Invoice",
"spans": [{ "start": 0, "end": 9 }],
"locations": [
{
"page_number": 1,
"bbox": { "left": 72, "top": 48, "right": 220, "bottom": 92 }
}
]
}
],
"relations": [],
"text_annotations": [],
"assets": []
}For TypeScript-first validation in your app, use @openparser/schema.
Related
- @openparser/schema overview
- @openparser/adapters — provider converters and cloud clients