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/schema

Import 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[];
};
FieldRole
output_formatSchema version. Always openparser@1 on this shape.
document_idStable identifier for the parsed document.
provenanceProvider and model metadata for the canonical graph.
textPlain reading-order text. Every span indexes into this string.
markdownBest-effort Markdown rendering of the graph.
pagesOne-based coordinate spaces with reading order and optional page images.
elementsText, tables, figures, and related semantic payloads.
relationsDirected links (containment, captions, footnotes, reading order).
text_annotationsLanguage and style metadata over UTF-16 spans in text.
assetsPage 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_span per 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 uri or data_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

GoalApproach
Reading-order texttext or markdown
Layout + citationsWalk pages.reading_order, then elements / table cells
HierarchyFollow relations with type: 'contains'
Highlight on page imageMap locations[].bbox using page width / height
Language or font metadatatext_annotations spans into text
Page or figure rasterResolve assets by id from image_asset_id / asset_id
Provider-native JSONRequest 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.

On this page