Properties
| Name | Type | Description |
|---|---|---|
| results | array | One row per request item, in request order. A single-item batch (`items` of length 1) still returns an array of one row. |
| account | string | Opaque owning account id when the caller is authenticated. |
| tier | string | The caller's enforcement billing tier (`free`/`pro`/`business`) when authenticated. Absent for an unauthenticated (db-less/auth-disabled) validate. |
JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://artifacts.apis.io/blinkpdf-io/json-schema/blinkpdf-io-compose-validate-ok-schema.json",
"title": "Compose.ValidateOk",
"x-generated": "2026-10-30",
"x-method": "derived",
"x-generator": "derive-json-schema.py",
"x-source": "openapi/blinkpdf-io-openapi.json#/components/schemas/Compose.ValidateOk",
"type": "object",
"required": [
"results"
],
"properties": {
"results": {
"description": "One row per request item, in request order. A single-item batch (`items` of length 1) still returns an array of one row.",
"type": "array",
"items": {
"anyOf": [
{
"type": "object",
"required": [
"ok",
"index",
"composeWarnings",
"composeWarningsOmitted",
"resolvedPages",
"layout",
"impact",
"diagnostics"
],
"properties": {
"ok": {
"description": "This item passed TypeBox validation and semantic checks.",
"const": true,
"type": "boolean"
},
"index": {
"description": "Zero-based position of this item in the request `items` array.",
"type": "number"
},
"clientItemId": {
"description": "Echoed back when the request item supplied one.",
"type": "string"
},
"contentDigest": {
"description": "Canonical per-account compose digest when the caller is authenticated and the body has no `security` (an encrypted PDF is never cached or digested); returned again as the x-blinkpdf-content-digest response header on a later compose. For compositions referencing `blink://asset/<id>` handles, or that set `pinRemoteImages`, the digest additionally varies by the calling credential. It is a digest of the request/config, NOT a hash of the output PDF bytes.",
"type": "string"
},
"typography": {
"type": "object",
"required": [
"declared",
"active",
"assignments",
"unused"
],
"properties": {
"declared": {
"$ref": "#/$defs/Problem.validation_failed.errors.item.allowedKeys"
},
"active": {
"description": "The body/heading families this request configures (its intent).",
"type": "object",
"required": [
"body",
"heading"
],
"properties": {
"body": {
"description": "The configured body family (request intent).",
"type": "string"
},
"heading": {
"description": "The configured heading family (request intent).",
"type": "string"
}
}
},
"assignments": {
"$ref": "#/$defs/Render.ValidateOk.results.item.anyOf0.typography.assignments"
},
"unused": {
"$ref": "#/$defs/Problem.validation_failed.errors.item.allowedKeys"
}
}
},
"typographyNotes": {
"$ref": "#/$defs/Render.ValidateOk.results.item.anyOf0.typographyNotes"
},
"composeWarnings": {
"description": "Fail-open compose advisories about what paints as authored, in document order: for each section, a page-size override and a blank page, then its ops (a full-circle rotation when that op is visited, then empty text of an op or a text-row slot, including text inside a clip or rotation), then its flow (an empty text-row slot, table cell, or list item). An empty attribution paints its dash and is not an advisory. At most 10 of each code are listed; `composeWarningsOmitted` counts the rest. A field compose cannot paint as authored is never one of these: it is refused with a 400 or reported in `diagnostics` with an `impact` other than `none`. Always present on a successful validate; never invalidates the request.",
"type": "array",
"items": {
"type": "object",
"required": [
"sectionIndex",
"code",
"hint"
],
"properties": {
"sectionIndex": {
"description": "Index of the section in the request `sections` array.",
"type": "number"
},
"code": {
"description": "Fail-open compose advisory kind; each paints as authored.",
"type": "string",
"enum": [
"empty-page",
"rotation-full-circle",
"empty-content-omitted",
"page-size-mismatch"
]
},
"hint": {
"description": "Actionable fix for the author.",
"type": "string"
},
"opIndex": {
"description": "Index of the root op in the section when the warning targets that op or a slot under it.",
"type": "number"
},
"flowIndex": {
"description": "Index of the root flow node in the section when the warning targets that node or a slot under it.",
"type": "number"
}
}
}
},
"composeWarningsOmitted": {
"minimum": 0,
"description": "Present with `composeWarnings`: how many advisories lie past the first 10 of their code, counted exactly; `0` when it lists them all.",
"type": "integer"
},
"resolvedPages": {
"description": "Per-section authored geometry after document⊗section merge and theme, so an agent can see A4 vs Letter before spending quota.",
"type": "array",
"items": {
"type": "object",
"required": [
"sectionIndex",
"size",
"orientation",
"dimensions"
],
"properties": {
"sectionIndex": {
"description": "Zero-based index into the request `sections` array (authored section geometry, not painted PDF page index).",
"type": "number"
},
"size": {
"description": "Merged named size or custom [width, height] tuple.",
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "number"
}
}
]
},
"orientation": {
"description": "Merged orientation after document⊗page inheritance.",
"type": "string",
"enum": [
"portrait",
"landscape"
]
},
"dimensions": {
"type": "object",
"required": [
"width",
"height"
],
"properties": {
"width": {
"description": "MediaBox width in PDF points.",
"type": "number"
},
"height": {
"description": "MediaBox height in PDF points.",
"type": "number"
}
}
},
"background": {
"type": [
"object",
"null"
],
"required": [
"color"
],
"properties": {
"color": {
"description": "Sheet fill as `#RGB`/`#RRGGBB`.",
"type": "string"
},
"opacity": {
"description": "Sheet fill opacity from 0 to 1.",
"type": "number"
}
}
}
}
}
},
"layout": {
"$ref": "#/$defs/Layout.Report"
},
"impact": {
"description": "The grade of the whole PDF: the worst `impact` among the `diagnostics` and `typographyNotes` entries; the value `POST /v1/compose` writes as `X-Render-Impact` for the same body, from the same grade, so a dry run tells lost content from a look change without a table of codes, every occurrence counted, listed or not (`content` over `appearance` over `none`). `none` is a PDF made as requested; `appearance` one that holds everything asked, readable, with a look or navigation that differs; `content` one that misses part of what was asked.",
"type": "string",
"enum": [
"none",
"appearance",
"content"
]
},
"diagnostics": {
"description": "The list `POST /v1/compose` writes to `X-Render-Diagnostics` for this body, computed render-free by the same builder: same entries, same shape, same order (severity first, errors before warns before infos, then document position). Covers every class — image sourcing/decode, element layout warnings addressed by node pointer in `resource` (a canvas `text` op whose wrapped lines paint over another op of its canvas is `canvas-text-wrap-overlap` at the pointer of that op; header or footer furniture that paints over a canvas op is `furniture-canvas-overlap` at the pointer of that slot or rule), a header or footer slot or rule whose color you did not set that lies on an image decoration, whose color BlinkPDF cannot read, is `ink-unverified` at the pointer of that slot or rule, a text whose color you set (a canvas `text` or `textRow` op or one of its spans, a flow text, text row, list item span, or `math` node, a flow table cell or one of its spans, a chip label, or a header or footer slot) whose color has, at full opacity, less than 3:1 contrast against the solid color painted behind it (the sheet, the page background, a quote background, the fills under a canvas op, a table cell's `background` or the header or stripe band it sits on, or its chip) is `text-low-contrast` at the pointer of that op, node, or slot (impact `content`; text over an image, a gradient, or a fill it only partly lies on is not judged), text in a script BlinkPDF does not shape yet (`script-not-shaped` at the pointer of each node that holds it), and document-level notes such as `title-omitted` or `glyph-component-dropped`. At most 10 occurrences of each code and severity are listed; the rest of that code and severity are counted by one entry carrying `omitted` (the count) right after its last listed occurrence, and still count toward `X-Render-Status` and `X-Render-Impact`, so the list grows with the codes a document reports, not with its size. Not capped by the header budget: when render cannot fit the list in `X-Render-Diagnostics` (`X-Render-Diagnostics-Truncated`), that bounded header may leave codes out (`X-Render-Diagnostics-Summary` names them all), while this array still lists every entry. Always present on a successful validate; an empty array means render reports no diagnostics.",
"type": "array",
"items": {
"$ref": "#/$defs/Render.Diagnostic"
}
}
}
},
{
"anyOf": [
{
"$ref": "#/$defs/Row.validation_failed.compose"
},
{
"$ref": "#/$defs/Row.content_not_paginable"
},
{
"$ref": "#/$defs/Row.image_too_large"
},
{
"$ref": "#/$defs/Row.invalid_google_fonts_url"
},
{
"$ref": "#/$defs/Row.google_font_not_found"
},
{
"$ref": "#/$defs/Row.google_font_weight_unavailable"
},
{
"$ref": "#/$defs/Row.asset_kind_mismatch"
},
{
"$ref": "#/$defs/Row.font_embedding_prohibited"
},
{
"$ref": "#/$defs/Row.font_malformed"
},
{
"$ref": "#/$defs/Row.font_source_unavailable"
},
{
"$ref": "#/$defs/Row.memory_budget_exceeded"
},
{
"$ref": "#/$defs/Row.server_busy"
},
{
"$ref": "#/$defs/Row.memory_share_exceeded"
},
{
"$ref": "#/$defs/Row.text_row_overflow"
},
{
"$ref": "#/$defs/Row.column_widths_overflow"
},
{
"$ref": "#/$defs/Row.table_occupancy"
},
{
"$ref": "#/$defs/Row.qr_not_scannable"
},
{
"$ref": "#/$defs/Row.barcode_not_scannable"
},
{
"$ref": "#/$defs/Row.service_unavailable"
}
]
}
]
}
},
"account": {
"description": "Opaque owning account id when the caller is authenticated.",
"type": "string"
},
"tier": {
"description": "The caller's enforcement billing tier (`free`/`pro`/`business`) when authenticated. Absent for an unauthenticated (db-less/auth-disabled) validate.",
"type": "string"
}
},
"$defs": {
"Error.font_malformed.fontFault": {
"additionalProperties": false,
"description": "Cause and tables of a `font_malformed` refusal. Same value on every surface that reads the font",
"type": "object",
"required": [
"cause",
"tables"
],
"properties": {
"cause": {
"description": "Why the font was refused: `parseBudget` (a table needs more parse work than the safety budget), `outOfBounds` (truncated, or an offset outside the font data), `unsupportedFormat` (not an sfnt font, or a table format or version the engine does not read), `invalidStructure` (a structural rule of the OpenType specification is broken), or `outOfFaceReferences` (tables reference glyph ids past the face)",
"type": "string",
"enum": [
"parseBudget",
"outOfBounds",
"unsupportedFormat",
"invalidStructure",
"outOfFaceReferences"
]
},
"tables": {
"minItems": 1,
"description": "sfnt tables the fault is in (`CFF` for the `CFF ` table), or `sfnt` for the font file as a whole, `WOFF` or `WOFF2` for the web font container it was uploaded in; every referencing table on `outOfFaceReferences`",
"type": "array",
"items": {
"minLength": 1,
"type": "string"
}
}
}
},
"Error.google_font_not_found.didYouMean": {
"description": "Present when a missing family name is a typo of a sibling family declared in the same request; each entry carries that family as `value`",
"type": "array",
"items": {
"$ref": "#/$defs/Error.google_font_not_found.didYouMean.item"
}
},
"Error.google_font_not_found.didYouMean.item": {
"type": "object",
"properties": {
"key": {
"type": "string"
},
"value": {
"type": "string"
},
"index": {
"type": "integer"
}
}
},
"Error.google_font_not_found.families": {
"description": "The declared family names that do not exist on Google Fonts",
"type": "array",
"items": {
"type": "string"
}
},
"Layout.Report": {
"additionalProperties": false,
"description": "Pagination without bytes: per-page occupancy, anchor to page, node placement, and what could not be honored. The same report a serialized render produces for the same body, because both come from the same layout pass. Page numbers in the layout report are 1-based: the number a viewer shows and a painted table-of-contents entry prints. Indices into an authored array stay 0-based and are named `*Index`. Each list shows at most 256 entries, the first in document order (`diagnostics`: the first 10 of each code), and `omitted` counts the rest exactly, so the report grows with the pages it counts and not with the blocks, anchors, or images the document holds.",
"type": "object",
"required": [
"pageCount",
"pages",
"anchors",
"nodes",
"diagnostics",
"omitted"
],
"properties": {
"pageCount": {
"description": "Total PDF pages after pagination, listed or omitted: `pages.length` plus `omitted.pages`",
"type": "number"
},
"pages": {
"description": "Per-page occupancy of the first pages, ascending by `page`, no gaps; at most 256",
"type": "array",
"items": {
"additionalProperties": false,
"description": "Occupancy of one paginated sheet",
"type": "object",
"required": [
"page",
"dimensions",
"bodyEndY",
"remainingY",
"overflow"
],
"properties": {
"page": {
"description": "Page numbers in the layout report are 1-based: the number a viewer shows and a painted table-of-contents entry prints. Indices into an authored array stay 0-based and are named `*Index`.",
"type": "number"
},
"sectionIndex": {
"description": "0-based index into the authored `sections` array that produced this sheet. Absent when no authored section did: every Markdown page, and any sheet layout inserts on its own.",
"type": "number"
},
"dimensions": {
"additionalProperties": false,
"description": "MediaBox of the page, read from the sheet that was laid out",
"type": "object",
"required": [
"width",
"height"
],
"properties": {
"width": {
"description": "MediaBox width in PDF points",
"type": "number"
},
"height": {
"description": "MediaBox height in PDF points",
"type": "number"
}
}
},
"bodyEndY": {
"description": "Body content cursor Y after layout, in PDF points from the page top — the value a furniture renderer first observes as `page.y` on this page",
"type": "number"
},
"remainingY": {
"description": "Unused content height between `bodyEndY` and the bottom content edge, in PDF points. Never negative; `0` when the page holds no more content.",
"type": "number"
},
"overflow": {
"description": "True when the page has no remaining content height",
"type": "boolean"
}
}
}
},
"anchors": {
"description": "The first addressable anchors with the page each landed on, in document order. Empty when the document declares none.",
"type": "array",
"items": {
"additionalProperties": false,
"description": "Where a named anchor landed",
"type": "object",
"required": [
"name",
"page"
],
"properties": {
"name": {
"description": "Addressable anchor identity: the authored anchor name for compose, the GitHub-style heading slug for Markdown — what an author writes to point at this place",
"type": "string"
},
"page": {
"description": "Page numbers in the layout report are 1-based: the number a viewer shows and a painted table-of-contents entry prints. Indices into an authored array stay 0-based and are named `*Index`.",
"type": "number"
}
}
}
},
"nodes": {
"description": "Placement of the first nodes the caller can address by id, in document order",
"type": "array",
"items": {
"additionalProperties": false,
"description": "Where one addressable node landed, and how it got there",
"type": "object",
"required": [
"id",
"fragments"
],
"properties": {
"id": {
"description": "Node identity: the authored `id` for compose flow nodes at any depth, `<label>@<line>:<column>` for Markdown top-level blocks — the same ids as `rules[].nodes`. A table appears once under its whole-table id and its cells inherit that page.",
"type": "string"
},
"pointer": {
"description": "RFC 6901 fragment pointer (`#/sections/…`) of the authored compose node, top-level or nested in an `indented`, `columns`, `atomic` or `blockquote` scope — the form validate `errors[].pointer` uses. Absent for Markdown blocks, which are addressed by `id` alone.",
"type": "string"
},
"fragments": {
"description": "One box per page the node paints on, in page order, from the same pagination pass that paints: a node split across pages has one fragment per page, and a node that paints nothing, such as a `pageBreak`, has none.",
"type": "array",
"items": {
"additionalProperties": false,
"description": "Box in PDF points in the space of compose ops: origin at the top-left corner of the page, x to the right, y down. It is the union of the boxes of the operations the node paints on that page (full line boxes for text; its own box for an image, chart, or rule), not the exact ink of its glyphs. A blockquote or table reports the band it lays out on that page, its padding included, with the ink of its own strokes and caption, so the gap to the next box is the margin the page paints; the content inside it never widens it.",
"type": "object",
"required": [
"page",
"x",
"y",
"width",
"height"
],
"properties": {
"page": {
"description": "Page numbers in the layout report are 1-based: the number a viewer shows and a painted table-of-contents entry prints. Indices into an authored array stay 0-based and are named `*Index`.",
"type": "number"
},
"x": {
"description": "Left edge in PDF points from the left edge of the page",
"type": "number"
},
"y": {
"description": "Top edge in PDF points from the top edge of the page",
"type": "number"
},
"width": {
"description": "Width in PDF points",
"type": "number"
},
"height": {
"description": "Height in PDF points",
"type": "number"
}
}
}
},
"splitAt": {
"description": "1-based source line index at which the node’s text first crosses a page break",
"type": "number"
},
"widowRisk": {
"description": "Present when a node with severed keep (`keepWithNext: false`) lands at the bottom of its page and the following content starts on a later page. Advisory of the severed keep; the node is not relocated.",
"const": true,
"type": "boolean"
},
"softFitReclaimPt": {
"description": "Total soft-fit reclaim applied while placing this node, in PDF points (present only when greater than zero). Engine-applied observation; does not change placement when read.",
"type": "number"
},
"clubWidowCut": {
"description": "Present when a mid-block page cut ran under the default club/widow band policy (engine-applied)",
"const": true,
"type": "boolean"
},
"keepWithNextJump": {
"description": "Present when a whole-unit page jump ran with a non-zero keep-with-next probe (engine-applied)",
"const": true,
"type": "boolean"
},
"blankGuardAllowedJump": {
"description": "Present when a whole-unit or preferred atomic jump ran after blank-guard consultation allowed it (engine-applied)",
"const": true,
"type": "boolean"
},
"blankGuardDeniedJump": {
"description": "Present when blank policy blocked a geometric whole-unit or preferred atomic jump (engine-applied)",
"const": true,
"type": "boolean"
},
"keepBondDropped": {
"description": "Present when blank policy dropped keep-with-next last-line extra mid-band so the bond did not force an earlier cut (engine-applied; not a whole-unit jump denial)",
"const": true,
"type": "boolean"
},
"residualRoom": {
"description": "Content residual room at the whole-unit keep decision, in PDF points (engine-applied; present only when residual packing telemetry ran)",
"type": "number"
},
"residualUsableHeight": {
"description": "Full usable content height at the residual packing decision, in PDF points (engine-applied)",
"type": "number"
},
"residualFullUnitHeight": {
"description": "Full keep-unit height (anchor lines plus keep probe) at the residual packing decision, in PDF points (engine-applied)",
"type": "number"
},
"residualMinProgressHeight": {
"description": "Minimum-progress start height used for residual packing, in PDF points (engine-applied)",
"type": "number"
},
"residualJumped": {
"description": "Present when place jumped before painting after residual packing resolution (engine-applied)",
"const": true,
"type": "boolean"
},
"residualAdmitAction": {
"description": "Which residual packing action the layout took at this node: `stay-full` and `stay-degraded` keep the node on the page, the `jump-*` values move it to a fresh one, `geometry-no-jump` means geometry alone decided, `stay-guard-yield` keeps a keep-with-next chain on the page because moving it would leave more of the page blank than the blank guard allows, so the chain breaks after a list it holds whole or after a block whose keep the theme set, `stay-start-floor-yield` keeps the whole chain on the page for the same reason and its last block opens with the default two lines instead of the longer start floor its theme asks for, `stay-chain-over-page` keeps a keep-with-next member on the page because the rest of its chain is taller than a page body, so moving it would only move the break and leave the page blank, and the remaining labels name a keep or blank outcome (engine-applied).",
"type": "string",
"enum": [
"stay-full",
"stay-degraded",
"jump-blank-ok",
"jump-keep-joint",
"jump-residual-abandoned",
"geometry-no-jump",
"atomic-keep-joint-no-degrade",
"no-keep-blank",
"stay-guard-yield",
"stay-start-floor-yield",
"stay-chain-over-page"
]
}
}
}
},
"diagnostics": {
"description": "What pagination could not honor, addressed by page, authored section, request array index, or request JSON pointer. Empty when everything was honored.",
"type": "array",
"items": {
"anyOf": [
{
"additionalProperties": false,
"description": "A canvas section whose flow needed more than its own sheet",
"type": "object",
"required": [
"code",
"impact",
"sectionIndex"
],
"properties": {
"code": {
"description": "Discriminator for a canvas section that needed extra sheets",
"const": "canvas-flow-overflow",
"type": "string"
},
"impact": {
"description": "What the entry changed in the PDF, on the scale of `Render.Diagnostic`: the `impact` the render diagnostic of the same code carries at the same node; `none` for an entry render does not report (`canvas-flow-overflow`, `page-override-unmatched`).",
"type": "string",
"enum": [
"none",
"appearance",
"content"
]
},
"sectionIndex": {
"description": "0-based index into the authored `sections` array whose canvas flow spilled past its opening sheet; its continuation sheets carry the same `sectionIndex` in `pages`. Cover ops stay on the first sheet of that section.",
"type": "number"
}
}
},
{
"additionalProperties": false,
"description": "A page override that applies to nothing",
"type": "object",
"required": [
"code",
"impact",
"index",
"reason"
],
"properties": {
"code": {
"description": "Discriminator for a page override that matched no page",
"const": "page-override-unmatched",
"type": "string"
},
"impact": {
"description": "What the entry changed in the PDF, on the scale of `Render.Diagnostic`: the `impact` the render diagnostic of the same code carries at the same node; `none` for an entry render does not report (`c
# --- truncated at 32 KB (130 KB total) ---
# Full source: https://artifacts.apis.io/blinkpdf-io/json-schema/blinkpdf-io-compose-validate-ok-schema.json
Work with this as data
Every JSON Schema here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for schemas
4 MCP tools reach this
find_json_schemasBrowse and filter every JSON Schema in the catalog.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.
Call it yourself
curl for this page
This JSON Schema
curl "https://apis.io/api/v1/json-schemas/blinkpdf-io-compose-validate-ok"
All schemas
curl "https://apis.io/api/v1/json-schemas?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.