Skip to main content
On this page

API

Progress and previews

Query processing progress and read text and image previews.

For a background integration that only needs the result, poll GET /transforms/{uuid}. Use observation when your application displays progress or content while processing.

Observation response

GET /transforms/{uuid}/observation?preview_limit=100

json
{  "status": "running",  "progress": {    "queued": false,    "stage": "converting",    "completed_words": 1250,    "total_words": 8000  },  "preview": {    "cursor": "opaque-cursor",    "updated": [      {        "file": "converting/body",        "url": "https://storage.example/body.jsonl?signed",        "range": {"start": 0, "end": 240}      }    ]  }}

The example URLs and offsets illustrate the response shape. Read the exact URL and range returned for your task.

progress may be returned while the task is running. If queued is true, the task is still waiting and a progress percentage is unavailable. Processing stages are preparing, extracting, converting, packaging and uploading.

Page counts use completed_pages and total_pages; source-text counts use completed_words and total_words. These fields may be absent. Do not treat missing values as zero, and only calculate a percentage when the total is greater than zero.

Counts describe the current operation, so totals may change between stages. They do not represent charges.

Completed work can include fallback handling; it does not prove that every word has a translated counterpart. Only status: "succeeded" indicates successful completion.

Read updates and advance the cursor

Keep one cursor per task. Send it unchanged with URLSearchParams on the next observation request. preview.cursor is always present; updated may be absent when there is no new content.

  1. Fetch each updated URL without API credentials and without caching.
  2. For a range, request Range: bytes=start-(end-1). Offsets count UTF-8 bytes; start is inclusive and end exclusive.
  3. Require 206, read the complete byte range, decode UTF-8 and parse complete JSONL records. A metadata update has no range and is a complete JSON document.
  4. Save the new cursor only after all updates have been read and applied. If any step fails, keep the old cursor and retry after a delay. Retries may return the same content; deduplicate by task, stream and byte range to avoid adding it twice.

This function reads JSONL records within the requested byte range:

javascript
async function readPreviewRange(update) {  const { start, end } = update.range;  const response = await fetch(update.url, {    headers: { Range: `bytes=${start}-${end - 1}` },    cache: "no-store",  });  if (response.status !== 206) throw new Error(`Preview HTTP ${response.status}`);  const bytes = await response.arrayBuffer();  if (bytes.byteLength !== end - start) throw new Error("Incomplete preview range");  const text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);  if (!text.endsWith("\n")) throw new Error("Incomplete JSONL record");  return text.slice(0, -1).split("\n").map(line => JSON.parse(line));}

This helper does not manage polling, metadata or your application state. Never attach the API Authorization header to its fetch. Render document content as untrusted input.

Preview limits

preview_limit limits each JSONL stream independently, defaults to 500 and is capped at 500. The initial request returns only the tail. If you fall behind, older records can be skipped: cursor polling is not pagination through the entire document. Download the final result for complete content.

Process any final updates before stopping on a terminal state. Successful observation also includes {get_url, head_url} in download_urls. These use default filenames; request /download-urls?filename=... separately for a custom name. Failed tasks may retain partial preview, which is not a successful output.

Streams and assets

StreamContent
extraction/metadata, converting/metadataComplete {metadata, original?} JSON; replace the previous view rather than merge patches
extraction/body, extraction/footnotesPDF extraction records containing a content tree and optional source regions
converting/body, converting/footnotes for PDFParagraph records with text, optional original, and source regions
converting/body for EPUBPlain-text fragments with original, translated and optional epubcfi

PDF extraction previews can differ from the final chapter structure. EPUB has no extraction or separate footnote stream. Records may contain an optional emitted_at; accept older records without it and ignore unknown additive fields.

Images and formulas in previews are identified by resource hashes. Insert the hash into GET /transforms/{uuid}/preview-assets/{extraction|converting}/{hash}.{png|pdf} to obtain the file URL.

Reading the file does not require an API key. If the link expires, call the endpoint again.