blinkpdf-io · Schema

Template.sandwich-document.Body

Sandwich document: a first-page header (logo, professional identity, subject and document context), a Markdown body, and a last-page footer (optional signature, divider, professional name). Image assets (logo, signature) are `https://` URLs, `data:image/` URLs, or staged `blink://asset/` handles, read as the images of the Markdown body are. Page-1 body clearance uses a flow offset for the header band. The bottom margin of every page reserves the repeating page-footer band; the signature band is reserved on the last page only, below the end of the body, and when it does not fit there the fewest closing lines of the body move with it to a new page.

PDFDocumentProcessingAPISaaSAutomation

Properties

Name Type Description
markdown string Markdown source rendered as the body between header and footer
metadata object
header object First-page header band content
footer object Last-page footer band content
fontStack object
googleFontsUrls object
typography object
glyphFallback object
pinRemoteImages boolean When true, each `https://` image of the request (its image fields and its Markdown body) is fetched once and its bytes are pinned to the calling credential and reused on later renders for up to 24 hou
page object Page geometry and appearance for the output PDF, including optional full-sheet background. The sandwich-document template supplies defaults of size "Letter" and 2 cm margin when these fields (or the w
View JSON Schema on GitHub

JSON Schema

blinkpdf-io-template-sandwich-document-body-schema.json Raw ↑
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/blinkpdf-io/json-schema/blinkpdf-io-template-sandwich-document-body-schema.json",
  "title": "Template.sandwich-document.Body",
  "description": "Sandwich document: a first-page header (logo, professional identity, subject and document context), a Markdown body, and a last-page footer (optional signature, divider, professional name). Image assets (logo, signature) are `https://` URLs, `data:image/` URLs, or staged `blink://asset/<id>` handles, read as the images of the Markdown body are. Page-1 body clearance uses a flow offset for the header band. The bottom margin of every page reserves the repeating page-footer band; the signature band is reserved on the last page only, below the end of the body, and when it does not fit there the fewest closing lines of the body move with it to a new page.",
  "x-generated": "2026-10-30",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/blinkpdf-io-openapi.json#/components/schemas/Template.sandwich-document.Body",
  "additionalProperties": false,
  "type": "object",
  "required": [
    "markdown",
    "metadata",
    "header",
    "footer"
  ],
  "properties": {
    "markdown": {
      "minLength": 0,
      "maxLength": 262144,
      "description": "Markdown source rendered as the body between header and footer",
      "type": "string"
    },
    "metadata": {
      "$ref": "#/$defs/Template.layout-document.Body.metadata"
    },
    "header": {
      "additionalProperties": false,
      "type": "object",
      "required": [
        "professional",
        "subject",
        "context"
      ],
      "properties": {
        "professional": {
          "additionalProperties": false,
          "type": "object",
          "required": [
            "name",
            "logo"
          ],
          "properties": {
            "prefix": {
              "anyOf": [
                {
                  "minLength": 0,
                  "maxLength": 1024,
                  "description": "Plain text rendered with the theme defaults; may be empty",
                  "type": "string"
                },
                {
                  "$ref": "#/$defs/Template.sandwich-document.Body.header.professional.prefix.anyOf1"
                }
              ],
              "description": "Honorific or title shown before the name, e.g. `Dr.`"
            },
            "name": {
              "anyOf": [
                {
                  "minLength": 0,
                  "maxLength": 1024,
                  "description": "Plain text rendered with the theme defaults; may be empty",
                  "type": "string"
                },
                {
                  "$ref": "#/$defs/Template.sandwich-document.Body.header.professional.prefix.anyOf1"
                }
              ],
              "description": "Professional first or given name"
            },
            "lastName": {
              "anyOf": [
                {
                  "minLength": 0,
                  "maxLength": 1024,
                  "description": "Plain text rendered with the theme defaults; may be empty",
                  "type": "string"
                },
                {
                  "$ref": "#/$defs/Template.sandwich-document.Body.header.professional.prefix.anyOf1"
                }
              ],
              "description": "Professional family or last name"
            },
            "logo": {
              "maxLength": 4194304,
              "pattern": "^(https://|data:image/|[Bb][Ll][Ii][Nn][Kk]://[Aa][Ss][Ss][Ee][Tt]/)",
              "description": "Logo image shown in the header. Image as an `https://` URL fetched under the fixed image policy of every render, a `data:image/` URL (`data:image/<mime>;base64,...`), or the `blink://asset/<id>` handle the MCP `complete_upload` returned for an image, read as a Markdown image of the same source is: png, jpeg, gif, tiff, webp, or svg+xml. A source that cannot be fetched (`image-fetch-failed`, a private address or an `http://` redirect included), whose fetch times out (`image-fetch-timeout`) or is over the per-image size (`image-fetch-too-large`), that holds no image (`image-data-malformed`, `image-unsupported-mime`), or whose bytes do not paint (`image-decode-failed`, `image-codec-unavailable`) is refused at this field with the code and cause a Markdown image of the same source reports; a handle that names no asset id, or that the caller did not stage or that expired, is refused at this field. With `pinRemoteImages`, an `https://` image paints the bytes pinned to the calling credential.",
              "type": "string"
            },
            "credentials": {
              "minItems": 0,
              "maxItems": 16,
              "description": "Credentials rendered as a compact identity line under the name",
              "type": "array",
              "items": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "title",
                  "institution",
                  "identifier"
                ],
                "properties": {
                  "title": {
                    "anyOf": [
                      {
                        "minLength": 0,
                        "maxLength": 1024,
                        "description": "Plain text rendered with the theme defaults; may be empty",
                        "type": "string"
                      },
                      {
                        "$ref": "#/$defs/Template.sandwich-document.Body.header.professional.prefix.anyOf1"
                      }
                    ],
                    "description": "Qualification or credential title"
                  },
                  "institution": {
                    "anyOf": [
                      {
                        "minLength": 0,
                        "maxLength": 1024,
                        "description": "Plain text rendered with the theme defaults; may be empty",
                        "type": "string"
                      },
                      {
                        "$ref": "#/$defs/Template.sandwich-document.Body.header.professional.prefix.anyOf1"
                      }
                    ],
                    "description": "Issuing institution"
                  },
                  "identifier": {
                    "anyOf": [
                      {
                        "minLength": 0,
                        "maxLength": 1024,
                        "description": "Plain text rendered with the theme defaults; may be empty",
                        "type": "string"
                      },
                      {
                        "$ref": "#/$defs/Template.sandwich-document.Body.header.professional.prefix.anyOf1"
                      }
                    ],
                    "description": "License, registration, or credential identifier"
                  }
                }
              }
            },
            "registrations": {
              "minItems": 0,
              "maxItems": 16,
              "description": "Registry entries rendered alongside the credentials",
              "type": "array",
              "items": {
                "additionalProperties": false,
                "type": "object",
                "required": [
                  "label",
                  "value"
                ],
                "properties": {
                  "label": {
                    "anyOf": [
                      {
                        "minLength": 0,
                        "maxLength": 1024,
                        "description": "Plain text rendered with the theme defaults; may be empty",
                        "type": "string"
                      },
                      {
                        "$ref": "#/$defs/Template.sandwich-document.Body.header.professional.prefix.anyOf1"
                      }
                    ],
                    "description": "Registry name or identifier label"
                  },
                  "value": {
                    "anyOf": [
                      {
                        "minLength": 0,
                        "maxLength": 1024,
                        "description": "Plain text rendered with the theme defaults; may be empty",
                        "type": "string"
                      },
                      {
                        "$ref": "#/$defs/Template.sandwich-document.Body.header.professional.prefix.anyOf1"
                      }
                    ],
                    "description": "Registry number or value"
                  }
                }
              }
            }
          },
          "description": "Professional identity shown at the top of the first page"
        },
        "subject": {
          "additionalProperties": false,
          "type": "object",
          "required": [
            "items"
          ],
          "properties": {
            "sectionTitle": {
              "$ref": "#/$defs/Template.sandwich-document.Body.header.subject.sectionTitle"
            },
            "items": {
              "$ref": "#/$defs/Template.sandwich-document.Body.header.subject.items"
            }
          },
          "description": "Subject profile section rendered as a label/value grid (client, party, patient, etc.)"
        },
        "context": {
          "additionalProperties": false,
          "type": "object",
          "required": [
            "items"
          ],
          "properties": {
            "sectionTitle": {
              "$ref": "#/$defs/Template.sandwich-document.Body.header.subject.sectionTitle"
            },
            "items": {
              "$ref": "#/$defs/Template.sandwich-document.Body.header.subject.items"
            }
          },
          "description": "Document context section rendered as a label/value grid"
        },
        "highlights": {
          "additionalProperties": false,
          "type": "object",
          "required": [
            "items"
          ],
          "properties": {
            "sectionTitle": {
              "$ref": "#/$defs/Template.sandwich-document.Body.header.subject.sectionTitle"
            },
            "items": {
              "$ref": "#/$defs/Template.sandwich-document.Body.header.subject.items"
            }
          },
          "description": "Optional highlighted facts rendered as a compact horizontal line"
        }
      },
      "description": "First-page header band content"
    },
    "footer": {
      "additionalProperties": false,
      "type": "object",
      "required": [
        "professionalName"
      ],
      "properties": {
        "signature": {
          "maxLength": 4194304,
          "pattern": "^(https://|data:image/|[Bb][Ll][Ii][Nn][Kk]://[Aa][Ss][Ss][Ee][Tt]/)",
          "description": "Optional signature image shown in the last-page footer. Image as an `https://` URL fetched under the fixed image policy of every render, a `data:image/` URL (`data:image/<mime>;base64,...`), or the `blink://asset/<id>` handle the MCP `complete_upload` returned for an image, read as a Markdown image of the same source is: png, jpeg, gif, tiff, webp, or svg+xml. A source that cannot be fetched (`image-fetch-failed`, a private address or an `http://` redirect included), whose fetch times out (`image-fetch-timeout`) or is over the per-image size (`image-fetch-too-large`), that holds no image (`image-data-malformed`, `image-unsupported-mime`), or whose bytes do not paint (`image-decode-failed`, `image-codec-unavailable`) is refused at this field with the code and cause a Markdown image of the same source reports; a handle that names no asset id, or that the caller did not stage or that expired, is refused at this field. With `pinRemoteImages`, an `https://` image paints the bytes pinned to the calling credential.",
          "type": "string"
        },
        "professionalName": {
          "anyOf": [
            {
              "minLength": 1,
              "maxLength": 1024,
              "pattern": "\\S",
              "description": "Plain text rendered with the theme defaults; must contain a non-whitespace character",
              "type": "string"
            },
            {
              "additionalProperties": false,
              "type": "object",
              "required": [
                "text"
              ],
              "properties": {
                "text": {
                  "minLength": 1,
                  "maxLength": 1024,
                  "pattern": "\\S",
                  "description": "Text content to render; must contain a non-whitespace character",
                  "type": "string"
                },
                "fontRole": {
                  "description": "Font weight and style to apply to this text within the active font stack",
                  "type": "string",
                  "enum": [
                    "regular",
                    "bold",
                    "italic",
                    "boldItalic"
                  ]
                },
                "fontSize": {
                  "minimum": 1,
                  "maximum": 999,
                  "description": "Font size in PDF points; defaults to the theme value",
                  "type": "number"
                },
                "color": {
                  "pattern": "^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$",
                  "description": "Color as a 3- or 6-digit hex code, e.g. `#1a73e8`",
                  "type": "string"
                }
              }
            }
          ],
          "description": "Professional name shown beneath the signature"
        },
        "professionalCredentials": {
          "anyOf": [
            {
              "minLength": 0,
              "maxLength": 1024,
              "description": "Plain text rendered with the theme defaults; may be empty",
              "type": "string"
            },
            {
              "$ref": "#/$defs/Template.sandwich-document.Body.header.professional.prefix.anyOf1"
            }
          ],
          "description": "Optional credential line shown below the professional name"
        },
        "organization": {
          "additionalProperties": false,
          "type": "object",
          "properties": {
            "phone": {
              "anyOf": [
                {
                  "minLength": 0,
                  "maxLength": 1024,
                  "description": "Plain text rendered with the theme defaults; may be empty",
                  "type": "string"
                },
                {
                  "$ref": "#/$defs/Template.sandwich-document.Body.header.professional.prefix.anyOf1"
                }
              ],
              "description": "Organization phone number"
            },
            "address": {
              "anyOf": [
                {
                  "minLength": 0,
                  "maxLength": 1024,
                  "description": "Plain text rendered with the theme defaults; may be empty",
                  "type": "string"
                },
                {
                  "$ref": "#/$defs/Template.sandwich-document.Body.header.professional.prefix.anyOf1"
                }
              ],
              "description": "Organization postal address"
            },
            "email": {
              "anyOf": [
                {
                  "minLength": 0,
                  "maxLength": 1024,
                  "description": "Plain text rendered with the theme defaults; may be empty",
                  "type": "string"
                },
                {
                  "$ref": "#/$defs/Template.sandwich-document.Body.header.professional.prefix.anyOf1"
                }
              ],
              "description": "Organization email address"
            }
          },
          "description": "Optional organization contact details shown in the footer"
        }
      },
      "description": "Last-page footer band content"
    },
    "fontStack": {
      "$ref": "#/$defs/Render.Body.fontStack"
    },
    "googleFontsUrls": {
      "$ref": "#/$defs/Render.Body.googleFontsUrls"
    },
    "typography": {
      "$ref": "#/$defs/Render.Body.typography"
    },
    "glyphFallback": {
      "$ref": "#/$defs/Render.Body.glyphFallback"
    },
    "pinRemoteImages": {
      "title": "Pin each remote image to the calling credential for 24 hours, so later renders paint the same bytes",
      "description": "When true, each `https://` image of the request (its image fields and its Markdown body) is fetched once and its bytes are pinned to the calling credential and reused on later renders for up to 24 hours, so repeated renders produce the same PDF even if the origin changes; the pins are the ones every render reads and writes for the same URL. An image served through a pin reports `image-source-pinned`; without the flag a remote image reports `image-source-remote`. A body whose bytes are no image is never pinned. When pinning is unavailable (an anonymous caller included) the request fails with `service_unavailable` instead of fetching live. Defaults to false.",
      "type": "boolean"
    },
    "page": {
      "additionalProperties": false,
      "description": "Page geometry and appearance for the output PDF, including optional full-sheet background. The sandwich-document template supplies defaults of size \"Letter\" and 2 cm margin when these fields (or the whole page object) are omitted; explicit values override the defaults for their respective fields.",
      "type": "object",
      "properties": {
        "size": {
          "description": "Page size; defaults to Letter when omitted",
          "anyOf": [
            {
              "const": "A3",
              "type": "string"
            },
            {
              "const": "A4",
              "type": "string"
            },
            {
              "const": "A5",
              "type": "string"
            },
            {
              "const": "B4",
              "type": "string"
            },
            {
              "const": "B5",
              "type": "string"
            },
            {
              "const": "Letter",
              "type": "string"
            },
            {
              "const": "Legal",
              "type": "string"
            },
            {
              "const": "Tabloid",
              "type": "string"
            },
            {
              "const": "HalfLetter",
              "type": "string"
            },
            {
              "$ref": "#/$defs/Render.Body.page.size.anyOf9"
            }
          ]
        },
        "orientation": {
          "description": "Page orientation; defaults to portrait when omitted",
          "type": "string",
          "enum": [
            "portrait",
            "landscape"
          ]
        },
        "margin": {
          "anyOf": [
            {
              "minimum": 0,
              "maximum": 2880,
              "description": "Uniform page margin in PDF points applied to all four sides",
              "type": "number"
            },
            {
              "additionalProperties": false,
              "type": "object",
              "required": [
                "top",
                "right",
                "bottom",
                "left"
              ],
              "properties": {
                "top": {
                  "minimum": 0,
                  "maximum": 2880,
                  "description": "Top margin in PDF points",
                  "type": "number"
                },
                "right": {
                  "minimum": 0,
                  "maximum": 2880,
                  "description": "Right margin in PDF points",
                  "type": "number"
                },
                "bottom": {
                  "minimum": 0,
                  "maximum": 2880,
                  "description": "Bottom margin in PDF points",
                  "type": "number"
                },
                "left": {
                  "minimum": 0,
                  "maximum": 2880,
                  "description": "Left margin in PDF points",
                  "type": "number"
                }
              }
            }
          ],
          "description": "Page margins in PDF points; defaults to a uniform 2 cm (≈56.69 pt) when omitted"
        },
        "background": {
          "description": "Full-page sheet background, or `null` to suppress an explicit fill",
          "additionalProperties": false,
          "type": [
            "object",
            "null"
          ],
          "required": [
            "color"
          ],
          "properties": {
            "color": {
              "pattern": "^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$",
              "description": "Color as a 3- or 6-digit hex code, e.g. `#1a73e8`",
              "type": "string"
            },
            "opacity": {
              "minimum": 0,
              "maximum": 1,
              "description": "Fill opacity from 0 to 1",
              "type": "number"
            }
          }
        }
      }
    }
  },
  "$defs": {
    "Render.Body.fontStack": {
      "minItems": 1,
      "maxItems": 4,
      "title": "Hosted font cascade",
      "description": "Hosted families of the document cascade: exactly one weighted family (`inter`, `lora`, or `source-serif-4`) sets body and heading text, and emoji and code families add their roles; a stack with no weighted family or with two is refused with a 400 here. Every hosted family is available on every plan and by name without this list: text in another weighted family names it in a `family` field or a `typography` binding. When `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",
      "type": "array",
      "items": {
        "type": "string",
        "enum": [
          "inter",
          "lora",
          "source-serif-4",
          "noto-emoji-mono",
          "twemoji-mozilla",
          "jetbrains-mono"
        ]
      }
    },
    "Render.Body.glyphFallback": {
      "title": "Fallback family for missing characters",
      "description": "The family a character paints in when the run's own font lacks it, tried before the emoji fonts. It takes any family a `typography` role binds, or a `typography.named` role. Omitted, `inter`.",
      "anyOf": [
        {
          "const": "inter",
          "type": "string"
        },
        {
          "const": "lora",
          "type": "string"
        },
        {
          "const": "source-serif-4",
          "type": "string"
        },
        {
          "pattern": "^[A-Za-z][A-Za-z0-9 ]{0,63}$",
          "description": "Google Fonts display name from the declared pool (e.g. `Playfair Display`)",
          "type": "string"
        },
        {
          "pattern": "^[a-z][a-z0-9-]{0,15}$",
          "description": "Reference to a custom role declared in `typography.named` (e.g. `display`)",
          "type": "string"
        },
        {
          "pattern": "^[Bb][Ll][Ii][Nn][Kk]://[Aa][Ss][Ss][Ee][Tt]/[A-Za-z0-9_-]{43}(?![A-Za-z0-9_-])",
          "description": "Handle `blink://asset/<sha256>` of a TrueType or OpenType CFF font uploaded through the MCP (`prepare_upload` with `kind: \"font\"`, then `complete_upload`) under the calling credential. The handle names one face, and that face is the whole family: its weight (OS/2 weight class) and italic style are read from the font, and a `weight`, `italic`, or `<role>.<variant>` request for any other cut is rejected at validate",
          "type": "string"
        }
      ]
    },
    "Render.Body.googleFontsUrls": {
      "minItems": 1,
      "maxItems": 2,
      "title": "Google Fonts URL list",
      "description": "One to 2 Google Fonts URLs whose families, at most 4 in all, form one pool. The first family of the first URL paints body text, and the first family of the second URL (or else the second family of the first) paints headings, unless `typography` binds those roles.",
      "type": "array",
      "items": {
        "pattern": "^https?://(fonts\\.(googleapis|google|gstatic)\\.com|www\\.google\\.com/fonts)/\\S+$",
        "maxLength": 2048,
        "title": "Google Fonts URL",
        "description": "A Google Fonts URL in one of these forms: the CSS API (`https://fonts.googleapis.com/css2?family=…`), a family page as the browser shows it (`https://fonts.google.com/specimen/<Family>`, also under `/noto/specimen/` or `https://www.google.com/fonts/specimen/<Family>`, with any tab, query, or anchor), a download link (`https://fonts.google.com/download?family=<Family>`), or a share or selection link (`https://fonts.google.com/share?selection.family=…`). A search page or a `fonts.gstatic.com` font file names no family and is refused with the family page to use, and an `http://` link with its `https://` form. Weight axes list the CSS cuts fetched (100–900, at most 9 per family). BlinkPDF fetches the wght, ital, and opsz axes on every load of that family (body, heading, display, and any other role, including a `typography.pool` override). A declared opsz range that covers 32 uses that optical size; a range that misses it uses the nearer endpoint; a single positive opsz token is kept. Any other axis (for example wdth) is ignored. A family whose URL does not declare opsz, such as Playfair Display, is fetched without an optical size. Up to 4 families per URL, and at most 4 in the merged pool across all URLs (more URLs do not raise the total)",
        "type": "string"
      }
    },
    "Render.Body.page.size.anyOf9": {
      "type": "array",
      "items": {
        "minimum": 1,
        "maximum": 14400,
        "type": "number"
      },
      "minItems": 2,
      "maxItems": 2
    },
    "Render.Body.typography": {
      "additionalProperties": false,
      "title": "Font role selection",
      "description": "The family each text role paints in: `body`, `heading`, and up to 2 `named` roles each bind a hosted weighted key, a declared Google Fonts display name, or the `blink://asset/<sha256>` handle of a font uploaded with prepare_upload; `pool` and `variantMap` choose which Google Fonts weights load and paint.",
      "type": "object",
      "properties": {
        "body": {
          "$ref": "#/$defs/Render.Body.typography.body"
        },
        "heading": {
          "$ref": "#/$defs/Render.Body.typography.body"
        },
        "pool": {
          "minItems": 1,
          "maxItems": 4,
          "description": "Optional override of families parsed from `googleFontsUrls` (max 4 distinct names)",
          "type": "array",
          "items": {
            "additionalProperties": false,
            "description": "Optional override of a family parsed from `googleFontsUrls` (weights and italic flag)",
            "type": "object",
            "required": [
              "name"
            ],
            "properties": {
              "name": {
                "pattern": "^[A-Za-z][A-Za-z0-9 ]{0,63}$",
                "description": "Google Fonts family display name",
                "type": "string"
              },
              "weights": {
                "minItems": 1,
                "maxItems": 9,
                "description": "Explicit upright weights to declare for this family (sorted ascending, unique)",
                "type": "array",
                "items": {
                  "minimum": 100,
                  "maximum": 900,
                  "multipleOf": 100,
                  "description": "Font weight on the CSS scale in steps of 100: one of 100, 200, 300, 400, 500, 600, 700, 800, 900 (intermediate values like 450 are not valid weights)",
                  "type": "integer"
                }
              },
              "italic": {
                "description": "Whether to fetch italic cuts alongside the requested CSS weights",
                "type": "boolean"
              }
            }
          }
        },
        "named": {
          "minItems": 1,
          "maxItems": 2,
          "description": "Up to 2 custom roles binding a pool family, a hosted key, or an uploaded font handle to a name, referenced by a rule `set.font` (`<role>.<variant>`) and by `variantMap.role`",
          "type": "array",
          "items": {
            "additionalProperties": false,
            "description": "Binds a custom role name to a hosted key, a pool display name, or an uploaded font handle",
            "type": "object",
            "required": [
              "role",
              "family"
            ],
            "properties": {
              "role": {
                "pattern": "^[a-z][a-z0-9-]{0,15}$",
                "description": "Custom role identifier referenced by a `FontKey` and by rule `set.family`. Lowercase kebab-case (a leading letter, then lowercase letters, digits, or hyphens, max 16 chars), e.g. `accent`, `code-emphasis` — not camelCase or snake_case, so it can appear in a `<role>.<variant>` font key",
                "type": "string"
              },
              "family": {
                "$ref": "#/$defs/Render.Body.typography.body"
              }
            }
          }
        },
        "headingVariant": {
          "description": "Hosted heading ladder policy. Applies only when the heading family is a hosted weighted key. Omit or `bold` loads the registry heading cuts (Inter: SemiBold base H1–H6, Bold via strong). `regular` forces body-symmetric heading slots (same faces as body). A Google Fonts or uploaded-font heading ignores this field",
          "type": "string",
          "enum": [
            "regular",
            "bold"
          ]
        },
        "variantMap": {
          "minItems": 1,
          "maxItems": 16,
          "description": "Per-family variant-to-weight mapping. Each entry optionally narrows by `role` (body/heading/named) and, for headings, by `depth`. Resolution is by specificity: depth > role > family. Up to 16 entries to allow multiple (role, depth) slots per family.",
          "type": "array",
          "items": {
            "additionalProperties": false,
            "type": "object",
            "required": [
              "family"
            ],
            "properties": {
              "family": {
                "pattern": "^[A-Za-z][A-Za-z0-9 ]{0,63}$",
                "description": "Google Fonts family the variant map applies to",
                "type": "string"
              },
              "role": {
                "description": "Semantic role the weights apply to. Omitted = family-wide (current behavior). `depth` further narrows `role: \"heading\"`.",
                "anyOf": [
                  {
                    "const": "body",
                    "type": "string"
                  },
                  {
                    "const": "heading",
                    "type": "string"
                  },
                  {
                    "pattern": "^[a-z][a-z0-9-]{0,15}$",
                    "description": "Custom role declared in `typography.named` (e.g. `display`)",
                    "type": "string"
                  }
                ]
              },
              "depth": {
                "description": "Heading depth(s) the weights apply to (1–6). Only valid with `role: \"heading\"`. A single int or an array (OR). An entry with `depth` wins over a role-only entry, which wins over a family-only entry.",
                "anyOf": [
                  {
                    "minimum": 1,
                    "maximum": 6,
                    "type": "integer"
                  },
                  {
                    "minItems": 1,
                    "maxItems": 6,
                    "type": "array",
                    "items": {
                      "minimum": 1,
                      "maximum": 6,
                      "type": "integer"
                    }
                  }
                ]
              },
              "regular": {
                "minimum": 100,
                "maximum": 900,
                "multipleOf": 100,
                "description": "Font weight on the CSS scale in steps of 100: one of 100, 200, 300, 400, 500, 600, 700, 800, 900 (intermediate values like 450 are not valid weights)",
                "type": "integer"
              },
              "italic": {
                "minimum": 100,
                "maximum": 900,
                "multipleOf": 100,
                "description": "Font weight on the CSS scale in ste

# --- truncated at 32 KB (39 KB total) ---
# Full source: https://artifacts.apis.io/blinkpdf-io/json-schema/blinkpdf-io-template-sandwich-document-body-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.
All 92 tools →

Call it yourself

curl for this page
This JSON Schema
curl "https://apis.io/api/v1/json-schemas/blinkpdf-io-template-sandwich-document-body"
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.