WellMarked Docs
Guides

Output formats

markdown, json, chunks, html, and links — what each returns, which plans can use it, and how chunk offsets line up with the full document.

/extract, /bulk, /crawl, and /search all accept a format parameter. It changes only which field carries the content — metadata, errors, and job shapes are identical across formats. The default is markdown, so responses are byte-identical for callers who never set it.

formatResponse fieldShapePlans
markdownmarkdownstring — clean prose (the default)all
jsonblocks[{ type, text, level }] — heading / paragraph / list / codePro+
chunkschunks[{ text, start_token, end_token }] — 500-token windowsPro+
htmlhtmlstring — the raw fetched HTML, before extractionall
linkslinks[string] — every http(s) link, absolute and dedupedall

Exactly one content field is populated per result; the others are null.

Gated formats do not burn quota

json and chunks require Pro, Growth, or Enterprise. A Free key gets 403 plan_not_supported with an upgrade_url, and the request is not charged against quota. markdown, html, and links work on every plan.

json

level is 1–6 for headings and null for every other block type. The YAML front matter that markdown carries is omitted — those fields are already on metadata.

chunks

Offsets index into the document's token stream (tiktoken o200k_base) and are contiguous:

chunks[i].end_token === chunks[i + 1].start_token

Joining every text reproduces exactly what format="markdown" returns, so a chunk can be located in the full document without re-tokenizing.

Windows are 500 tokens, except where that would bisect a multi-byte character (emoji, CJK) — in which case they run a token or two longer rather than corrupting the seam.

Both skip main-content extraction entirely. That makes them faster, and it means they still succeed on a page that markdown would reject as no_content.

title, author, and date are null for both: no article was parsed.

Token metrics

Every successful extraction carries a metrics object:

{
  "content_bytes": 84213,
  "input_tokens": 21050,
  "output_tokens": 1204,
  "tokens_saved": 19846,
  "reduction_pct": 94.3
}

tokens_saved is input_tokens - output_tokens — what you did not have to send a model versus feeding it the raw HTML.

Treat it as an upper bound. Nobody actually feeds raw HTML to an LLM, but it prices the extraction in the currency you pay in.

Every token field is null if the tokenizer is unavailable. The extraction itself still succeeds.