Skip to main content
This guide walks through running a document (PDF) through the VLM Run Gateway, from picking a model to handling the response. Document requests fan out one page at a time and default to ocr for pp-ocrv6. For a quick copy-paste example, see Quickstart. For the cost/latency/accuracy rationale behind picking a model, method, and DPI, see Why the Gateway.

1. Pick a model

Start with paddleocr/pp-ocrv6 for general-purpose PDF OCR. See Models for the full catalog and Methods if you need a specific operation like text detection (detect) instead of full OCR. zai-org/glm-ocr serves markdown. rednote-hilab/dots.mocr adds layout parsing via parse_layout and parse_layout_only, plus ocr and markdown. For layout without text recognition, use paddlepaddle/pp-doclayoutv3: it returns ordered layout regions (labels, boxes, reading order) per page and no transcribed text, which makes it the layout stage of a layout-then-OCR pipeline. detect is its only method and its default, so you can omit method entirely. markdown is the default on zai-org/glm-ocr and rednote-hilab/dots.mocr. paddleocr/pp-ocrv6 defaults to ocr and offers text for its plain string form.

2. Send the document

Pass the PDF as a document_url content part. Prefer a hosted URL over a base64 data URI. See Multimodal Inputs for size limits and Method Parameters for document_dpi and other knobs.

Request knobs

Document rasterization

When the request includes a document_url part, document_dpi controls the rasterization DPI for each page before OCR. Set it at the top level or inside method_params (either location works; if both are present, method_params wins). Start at the default and only raise document_dpi if you see missed text on dense or small-font pages. Page count and file-size limits are documented under Multimodal Inputs.

3. Streaming vs non-streaming

In text mode, stream: true is honored for every chat request, and the streamed result is byte-identical to the non-streaming one. Document requests emit one SSE chunk per completed page block, in ascending page order. Other chat requests (regular chat, single-image OCR) buffer the full reply and re-chunk it into the same OpenAI SSE contract (no time-to-first-token benefit yet). A JSON response_format is always served non-streamed, since a single JSON object cannot be assembled from per-page deltas. Set stream: true to receive each page over SSE as it completes, in ascending page order, instead of waiting for the entire document:
Each delta.content value is one component of the document structure: the <document> open tag, then one <page> block per page, then the close tag. Each <page> carries its own format attribute, so a streamed page is self-describing before the client has buffered the header.

4. Parse the response

response_format picks text mode or JSON mode, and method picks each page’s payload kind. Both modes carry the same per-page content; JSON mode is easiest to consume programmatically. See Methods & Response Format for the full contract.

Text mode (default)

Every document method returns the same wrapper: one <document> element per input PDF, carrying its metadata as attributes, wrapping one <page> block per rasterized page. method decides only the page body, and each page declares it in format: markdown for a Markdown body (markdown, text, and dots.mocr’s ocr) and json for a region payload (detect, parse_layout, parse_layout_only).
  • A failed page is self-closing, with status="error" and no body, so page numbering stays intact.
  • A single image (not a PDF) returns the payload block alone, with no wrapper.
  • Several images return one <image> block each.

JSON mode

JSON mode is the same for every method. Add response_format={"type":"json_object"} to get one object, naming what produced it. data holds one document entry per input PDF; each entry lists its pages, and a failed page carries "status": "error" with no content:
Every page’s content is document.page.blocks, whatever method read it. A whole-page method (markdown, text, dots.mocr’s ocr) fills it with one block that carries text and no geometry:
A region method (ocr, detect, parse_layout, parse_layout_only) fills it with one block per region, each with bbox_xywh and, where the method reads the region, text. items is [] when nothing is found, and it is never a bare array. See The document block record for every key, and the per-model pages on Models for exact examples.
This is the only JSON shape the Gateway returns, so you cannot extract a custom document schema here. For schema-driven extraction, use the VLM Run API’s structured responses and custom schemas.

Multiple documents in one request

When a request includes more than one document_url (or file_url) content part, each PDF gets its own entry: they are never merged. In text mode that is one <document> block per input, concatenated in request order; in JSON mode data is a list of document entries in the same order.
Page indices restart at 0 for each document, in both modes.

Element attributes

The JSON-mode keys carry the same names, so the two modes map key for key.

Consuming each shape

Non-streaming: the blocks are concatenated in order inside choices[0].message.content. Streaming: the VLM Run Gateway emits OpenAI-style SSE chunks in document order, byte-identical to the non-streaming reply: the <document> open tag, one chunk per <page> block, then the matching </document> close tag. The next document follows after. To consume text mode, split on the <document> / <page> open and close tags, then read each page body according to its format. To skip parsing entirely, ask for JSON mode.

5. Track cost and handle errors

Non-streaming: read response.usage.cost for per-request metering during the alpha. Streaming: pass stream_options={"include_usage": true} so the terminal SSE event carries usage (including usage.cost) on the chunk instead of delta.content. Check for it before treating every chunk as page content:
For both modes:
  • Retry 429/500 with backoff; do not retry 400 capability violations. See Error Codes.
  • Keep the x-request-id response header if you need to contact support.

Multimodal Inputs

Content part types, document limits, and URL vs base64 tradeoffs.

Methods

Per-model method and method_params reference.

Error Codes

Status codes, error bodies, and retry guidance.

Models

Document and image OCR model catalog.