Skip to main content
POST
Validate a render request body

Authorizations

x-api-key
string
header
required

API key issued from your Blink PDF account, prefixed bp_. Send it in the x-api-key header on every request. The documentation and health endpoints are exempt.

Query Parameters

preview
enum<string>

Optional preview mode (no PDF bytes). layout runs a dry-run pagination and returns pages; resolved returns the post-cascade effective set per node in resolved.

Available options:
resolved,
layout

Body

application/json

Markdown source plus optional document metadata, font selection, page layout, viewer hints, style overrides, and page furniture. Only markdown is required; everything else falls back to safe defaults. When metadata.title is omitted the title is derived from the first Markdown heading; a document with no heading and no title is rendered without a title (no /Title) and is consequently not PDF/UA-1 conformant. Image references use standard Markdown URLs: data: is inline, http(s):// URLs are fetched by the service under strict security defaults (private-IP rejection always-on), and unsupported schemes are reported as render diagnostics. Local images can also be staged out of band and referenced from Markdown as blink://asset/<sha256>, where the handle is the base64url SHA-256 of the bytes; the bytes are fetched at render time and do not count toward the request input size limit. Staged images can also be laid out as pages — one per page or a grid — via the imageSequence option, without hand-authored Markdown. See components.examples.RenderRequest.Minimal, components.examples.RenderRequest.WithRules, components.examples.RenderRequest.WithImages, components.examples.RenderRequest.WithLocalAssets, components.examples.RenderRequest.WithImageSequence, components.examples.RenderRequest.WithOutline, components.examples.RenderRequest.WithHeadingNumbering, components.examples.RenderRequest.WithPageBackground, and components.examples.RenderRequest.WithFurniture for canonical request shapes.

Markdown source plus optional document metadata, font selection, page layout, viewer hints, style overrides, and page furniture. Only markdown is required; everything else falls back to safe defaults. When metadata.title is omitted the title is derived from the first Markdown heading; a document with no heading and no title is rendered without a title (no /Title) and is consequently not PDF/UA-1 conformant. Image references use standard Markdown URLs: data: is inline, http(s):// URLs are fetched by the service under strict security defaults (private-IP rejection always-on), and unsupported schemes are reported as render diagnostics. Local images can also be staged out of band and referenced from Markdown as blink://asset/<sha256>, where the handle is the base64url SHA-256 of the bytes; the bytes are fetched at render time and do not count toward the request input size limit. Staged images can also be laid out as pages — one per page or a grid — via the imageSequence option, without hand-authored Markdown. See components.examples.RenderRequest.Minimal, components.examples.RenderRequest.WithRules, components.examples.RenderRequest.WithImages, components.examples.RenderRequest.WithLocalAssets, components.examples.RenderRequest.WithImageSequence, components.examples.RenderRequest.WithOutline, components.examples.RenderRequest.WithHeadingNumbering, components.examples.RenderRequest.WithPageBackground, and components.examples.RenderRequest.WithFurniture for canonical request shapes.

markdown
string
required

Markdown source to render to PDF

Maximum string length: 262144
title
string

Convenience alias for metadata.title. When both are present metadata.title wins. Defaults to the first Markdown heading when neither is set

Required string length: 1 - 1024
Pattern: \S
metadata
object

PDF document metadata embedded in the rendered file. These fields are visible to anyone who opens the PDF — never include PHI, secrets, or other sensitive data.

fontStack
enum<string>[]

Ordered list of hosted font families; earlier families take precedence, later ones provide fallback coverage. Every family is available on every plan. When googleFontsUrl or googleFontsUrls is set, the Google family takes the body/heading slot and any weighted family in the stack is ignored (the stack then supplies only the emoji and code roles). Emoji families are appended automatically when omitted

Required array length: 1 - 4 elements
Available options:
inter,
lora,
source-serif-4,
noto-emoji-mono,
twemoji-mozilla,
jetbrains-mono
typography
object

Unified font selection: pool declaration/overrides, custom named roles, hosted heading variant policy, and per-family static weight maps for the four-variant PDF model. Body, heading, and per-depth heading families are assigned with rules (select + set.family); positional URL defaults apply otherwise

glyphFallback

A text family: a hosted weighted key, a declared Google Fonts display name, or a typography.named role reference

Allowed value: "inter"
googleFontsUrl
string

A single Google Fonts URL (alias of googleFontsUrls[0]). Do not pass together with googleFontsUrls. Accepted forms: CSS API (https://fonts.googleapis.com/css2?family=…), specimen (https://fonts.google.com/specimen/<Family>), or share (https://fonts.google.com/share?selection.family=…). Weight axes set the min/max endpoint weights fetched for the four-variant model. Up to 4 families per URL, and at most 4 in the merged pool across both URLs (two URLs do not raise the total)

Maximum string length: 2048
Pattern: ^https://fonts\.(googleapis|google)\.com/\S+$
googleFontsUrls
string[]

One or two Google Fonts URLs merged into a single family pool (max 4 distinct families). Default: first family of the first URL → body; first family of the second URL (or second family of the first URL) → heading. Use a rule set.family (or reorder URLs) to override

Required array length: 1 - 2 elements

A single Google Fonts URL (alias of googleFontsUrls[0]). Do not pass together with googleFontsUrls. Accepted forms: CSS API (https://fonts.googleapis.com/css2?family=…), specimen (https://fonts.google.com/specimen/<Family>), or share (https://fonts.google.com/share?selection.family=…). Weight axes set the min/max endpoint weights fetched for the four-variant model. Up to 4 families per URL, and at most 4 in the merged pool across both URLs (two URLs do not raise the total)

Maximum string length: 2048
Pattern: ^https://fonts\.(googleapis|google)\.com/\S+$
page
object

Page geometry and appearance: size (named preset or [width, height] in points), orientation, margins, and optional full-sheet background

viewer
object

PDF viewer hints — document language, page layout, page mode, and viewer preferences (toolbar/menubar visibility, fit-to-window, duplex, print scaling)

rules
object[]

Surgical presentation rules over standard Markdown nodes.

Maximum array length: 256
imageOverrides
object[]

Ergonomic per-image style overrides by position or exact URL, without authoring a full rules selector entry. For document-order indexing (true reading order across interleaved block and inline images), or for matching by anything other than an exact URL, use rules with select.nth/select.url and type: 'image' instead.

Maximum array length: 256
theme
string

Design preset resolved server-side to a fixed bundle of typography/page/furniture/numbering/rules, then merged under your own typography/page/furniture/rules (your values win per field; your rules win on conflicting cascade leaves). Picking a theme never lets the server read your Markdown — the bundle is deterministic, so the same source plus the same theme yields the same PDF. An unknown or malformed slug resolves to report-clean and never fails the request; the fallback is reported by resolvedTheme on /v1/render/validate and the x-render-theme-fallback response header on /v1/render. One of: report-clean, report-executive, report-data, blog-modern, blog-dark, blog-editorial, academic-classic, academic-modern, thesis, docs-light, docs-dark, api-reference, corporate, proposal, invoice.

Maximum string length: 64
Examples:

"report-clean"

"report-executive"

"report-data"

"blog-modern"

"blog-dark"

"blog-editorial"

"academic-classic"

"academic-modern"

"thesis"

"docs-light"

"docs-dark"

"api-reference"

"corporate"

"proposal"

"invoice"

numbering
object

Auto-numbering policy. Opt-in via enabled: true. Counters reset on the next deeper-depth heading and propagate across the document. Passing any of all, byDepth, depthRange, or trailingSeparator together with enabled: false returns 400 — those fields configure an active numbering policy, so they require enabled: true.

furniture
object

Page furniture (running headers and footers). slots applies to every page; set omitFirstPage: true to suppress furniture on the cover page, or pass firstPage to override the first page only. Set omitLastPage: true to suppress furniture on the closing page, or pass lastPage to override the final page only (when totalPages > 1). Optional pageOverrides supplies arbitrary per-page exceptions (later matches win per field). Optional watermark draws faint text behind body content. Optional decorations draws band rules such as masthead hairlines

outline
object

PDF outline (bookmarks). When omitted, an outline is emitted with the default depth range [1, 6] for any document containing headings. Pass depthRange alone to constrain depths. Set enabled: false to suppress the outline entirely. Passing depthRange together with enabled: false returns 400 — choose one intent.

imageSequence
object

Lay out staged images as pages without hand-authored Markdown: one per page or tiled in a grid, fit contain/cover, orientation: auto matching each page to its image. Defaults: fit is contain for one_per_page and cover for grid; orientation is auto; size is A4; padding is 0 (full-bleed). The sequence renders after the Markdown body; with empty markdown the document is the sequence alone. Each image still decodes against the per-render megapixel cap, so downscale very large folders or split them across renders. See components.examples.RenderRequest.WithImageSequence

pinRemoteImages
boolean

When true, each remote http(s):// image is fetched once and its bytes are reused on later renders of the same request, so repeated renders produce a byte-identical PDF even if the origin changes; reuse lasts up to 24 hours, after which the image is fetched again. Defaults to false, fetching every remote image fresh on each render.

Response

The body is valid for rendering. No PDF bytes are returned. The response carries imageDiagnostics — the render-time image and layout diagnostics (decode/fetch failures, rejected schemes, oversize, forced layout changes) computed render-free, at parity with the render X-Render-Diagnostics header.

valid
boolean
required

The request body passed TypeBox validation and semantic checks

resolvedTheme
object
required

Which design theme this request resolved to. Always present on a successful validate (report-clean with fellBack: false when no theme was requested), so an agent can confirm the bundle the render will use.

contentDigest
string

Canonical per-account render digest when the caller is authenticated; used by MCP delivery deduplication and returned again as the x-blinkpdf-content-digest response header on a later render. For renders whose Markdown references blink://asset/<id> handles, the digest additionally varies by the calling credential, so two API keys of one account never share an asset-resolved render or its cached signed link; renders without asset handles stay per-account. It is a digest of the request/config, NOT a hash of the output PDF bytes — an inert change (a rule that matches nothing) shifts the digest without changing the rendered bytes, so compare the file bytes to detect a visual change.

account
string

Opaque owning account id when the caller is authenticated.

tier
string

The caller's enforcement billing tier (free/pro/business) when authenticated, so a client can report the per-tier request-body limit without a second call. Absent for an unauthenticated (db-less/auth-disabled) validate.

typography
object
rules
object[]

Per-rule match preview: how many nodes each rules[] entry touched and where, so an agent can iterate without spending a render. A matched: 0 entry is a likely typo in the selector.

pages
number

Total page count from a dry-run pagination, present only when ?preview=layout is requested. No PDF bytes are produced.

layout
object[]

Per-node page assignment from the dry-run pagination, present only when ?preview=layout is requested. Cross-reference node with rules[].nodes/resolved; split marks nodes that cross a page boundary. A figure caption@… node appears after its image@….

unmatchedPageOverrides
object[]

furniture.pageOverrides whose pageNumber/pageIndex selector matches no page in the paginated document (a silently-inert override), each as { index, reason }. Present only with ?preview=layout, and only when at least one override is unmatched. A sectionStarts override is content-dependent and not reported here.

resolvedImages
object[]

Per-image resolved geometry from the dry-run layout, present only when ?preview=layout is requested, in public top-left PDF points (origin at the page top-left, Y growing downward). One entry per drawn image in document order — empty for a document with no images — so a caller can assert resolved boxes without inspecting the PDF.

resolved
object

Present (an object) whenever ?preview=resolved is requested — {} when no rule matched any node, so "checked, nothing applied" is distinguishable from "not checked". The rule-contributed set per matched node (the post-cascade merge of every rule that targeted it), keyed by node id (<label>@<line>:<column>, the same ids as rules[].nodes; a matched table cell is keyed cell@<line>:<column>, distinct from its whole-table table@… id). Every id in rules[].nodes appears here so the two reconcile deterministically — a node a rule matched but whose props were all inapplicable or fully shadowed maps to {}. It is a cascade delta, not the full effective style: a node no rule matched is absent, and theme defaults for properties no rule sets are applied at render time and are not echoed here. Effective body/heading families and per-depth weights are in typography.active / typography.resolvedWeights.

glyphs
object[]

Present only when ?preview=glyphs is requested. Codepoints in the document with no covering glyph in the resolved font cascade (the tofu render would otherwise produce), predicted render-free without fetching images. Empty array means full coverage.

numbering
object[]

Present when numbering.enabled is true and at least one heading is numbered: the render-free resolved counter string per numbered heading, in document order, honoring numbering format/prefix/depthRange and any per-heading set.numbering skip/reset. Lets a caller confirm 1. vs Chapter 1. without a render. A heading skipped or outside the depth range is absent.

typographyNotes
object[]

Informational typography notes: variant_collapsed when a variantMap flattens bold onto regular, weight_not_in_fetch when a mapped weight is not fetched. Never invalidates the request.

staticWarnings
object[]

Cheap render-free diagnostics from the resolved rule sets, e.g. a circle mask on a non-square image box. Always present on a successful validate (an empty array when there are no warnings or no rules), so an empty list means "checked, no warnings" rather than "not checked". Never invalidates the request.

imageDiagnostics
object[]

Render-time image and layout diagnostics computed render-free — decode failures, remote fetch/SSRF rejections, oversize, unsupported MIME, rule overlay/mask asset failures, and layout warnings such as a wrap image placed as a block because it is taller than the page, or a table row forced to split — in source order where available, each object byte-identical to the entry render serializes into X-Render-Diagnostics. Always present on a successful validate (an empty array when nothing fires), so an empty list means "checked, nothing to report" rather than "not checked". This closes the dry-run gap where a malformed image or a forced layout change rendered as degraded but validate reported valid: true with no signal. Glyph, typography, and rule advisories stay in their own fields (glyphs, typographyNotes, ruleWarnings).

ruleWarnings
object[]

Non-blocking advisories for rules that pass schema validation but are semantically inert (§5.3): a set property not valid for the selected node category, a selector axis not valid for the selected type, a heading depth outside 1–6, or a selector that combines more than one position axis (first/last/nth). A rule that matched zero nodes is reported here as a rule_no_match advisory (and also inline as rules[].warning for convenience), matching the render X-Render-Rule-Warnings header so the same condition reads identically on validate and render. Never invalidates the request.