Status: the v1 schema is implemented and live behind both
/generate and the playground. It’s pre-1.0 and may still grow (additively); it isn’t frozen as a versioned public contract yet.{{path}} substitution — compute values in your code) and nodes mirror layout, not meaning (column, row, text, … — not invoice, lineItem). See Template basics.
Request envelope
200 application/pdf. Failures are Problem Details.
page
Nodes
Every node has a"type" discriminator. There are seven types.
column
Vertical stack. → guide: Layoutrow
Horizontal stack of sized cells. → guide: Layouttext
A single styled string. → guide: Text & stylingrichText
Multi-span text with mixed styling and page-number tokens. → guide: Text & styling
A Span is one of:
{ "value": string, "style"?: Style }— an interpolatable, styled text run.{ "pageNumber": true }— the current page number.{ "totalPages": true }— the total page count.
spacer
A fixed vertical gap. → guide: Layoutimage
A base64-embedded image. → guide: Imagestable
A grid with an optional header and aforEach-driven body. → guide: Tables
Inside
body.row, the current array element binds to item — e.g. {{item.description}}. A Cell is:
Style
style merges over page.defaultTextStyle. fontSize must be > 0 when present. → guide: Text & styling
Colours
A colour is either:- a hex string —
#RGB,#RRGGBB, or#AARRGGBB(3, 6, or 8 hex digits; case-insensitive — in the 8-digit form the alpha byte comes first, ARGB), or - a dotted palette token (case-insensitive) from QuestPDF’s Material palette —
"grey.darken1","blue.medium","red.lighten2","indigo.darken3".
422. Full palette: the QuestPDF colour reference. → guide: Text & styling
Interpolation
Tokens are{{path.to.value}}; whitespace inside the braces is allowed.
- Paths resolve against
data—{{customer.name}},{{invoice.total}}. - Inside
table.body.forEach, the element binds toitem—{{item.unitPrice}}. - No array indexing (
lines[0].name) and no expressions. Put computed values indata. - A missing path fails with
422and lists every missing path.
Errors
All failures are RFC 7807 Problem Details (application/problem+json) with a top-level errors array of { code, message }. Full reference: Errors.
422 codes:
Example (missing data):
Out of scope (v1)
Not supported, by design — deferred to a later schema, gated by customer demand:- QR codes, barcodes, signature fields, charts
- Custom font upload, URL-sourced images
- Expressions, math, formatting helpers (
{{currency total}}) - Loops or conditionals outside
table.body.forEach - Saved/named templates — every request inlines its template
- Array indexing in paths (
lines[0]) and a literal{{in output