Structured JSON output for document layout

Async Mdkit jobs also produce a structured JSON document — fetch it with format=json when you need layout and structure, not just text.

Last updated

Availability Async lane only — GET /v1/convert/jobs/{id}/result?format=json
Extra cost None — one job produces both Markdown and JSON

Markdown is the right output for LLM prompts, but some pipelines need structure: what was a table, what was a heading, which page a paragraph came from. Async conversion jobs produce both outputs from one conversion — Markdown for text, JSON for structure — and you choose per fetch.

The JSON is the high-fidelity engine's own document model: a schema_name and version at the top, then arrays of texts, tables, pictures and pages beneath, with each item carrying its label (section header, paragraph, list item, caption …) and its provenance — the page number and bounding box it was found at.

Fetch both formats

curl -H "X-API-Key: $MDKIT_API_KEY" \
  "https://api.mdkit.online/v1/convert/jobs/$JOB_ID/result?format=markdown" -o doc.md
curl -H "X-API-Key: $MDKIT_API_KEY" \
  "https://api.mdkit.online/v1/convert/jobs/$JOB_ID/result?format=json" -o doc.json

Python — walk the structure

import httpx

BASE = "https://api.mdkit.online"
HEADERS = {"X-API-Key": "YOUR_KEY"}
job_id = "YOUR_JOB_ID"

doc = httpx.get(
    f"{BASE}/v1/convert/jobs/{job_id}/result",
    params={"format": "json"},
    headers=HEADERS,
    timeout=60,
).json()

print(doc["schema_name"], doc["version"])

for item in doc.get("texts", []):
    if item.get("label") == "section_header":
        print("heading:", item["text"])

for table in doc.get("tables", []):
    data = table.get("data", {})
    pages = [prov["page_no"] for prov in table.get("prov", [])]
    print(f"table {data.get('num_rows')}x{data.get('num_cols')} on page(s) {pages}")

When JSON earns its weight

  • Structure-aware chunking — cut on element boundaries so a table is never sliced in half, then embed the Markdown of each chunk.
  • Page-accurate citations — every item's provenance carries a page number, so an answer can say page 14 instead of somewhere in this document.
  • Selective extraction — pull only the tables, or only the captions, without writing a Markdown parser.

Stay on Markdown when the destination is a prompt: the JSON is faithful, not compact, and paying tokens for bounding boxes helps nobody.

Rules of the road

  • JSON is an async-lane feature. POST /v1/convert returns Markdown only; submit through POST /v1/convert/jobs to get both.
  • One job, both outputs, no extra credits — the job's 10 credits cover the conversion and you may fetch either format as often as you like.
  • The result endpoint answers 409 until the job has succeeded, and a job id that is not yours is a plain 404 — job ids stay unenumerable.

Try it

Sign in with a magic link for an API key, submit one document through the async lane, and diff the two outputs.

FAQ

How do I get structured JSON instead of Markdown?
Fetch an async job's result with format=json. JSON output is an async-lane feature — the synchronous /v1/convert endpoint returns Markdown only.
What is in the JSON document?
The high-fidelity engine's full structured representation of the input: a schema name and version, then arrays of texts, tables, pictures and pages, each item labelled and carrying the page it came from. Use it when you need structure rather than prompt-ready text.
Can I get both Markdown and JSON from one job?
Yes. A single async job produces both; you choose per fetch by changing the format parameter, at no extra credit cost.
Does the JSON say which page something came from?
Yes. Items carry a provenance entry with the page number and the bounding box on that page, which is what makes page-accurate citations possible in a RAG answer.