Skip to content
Start free

Layout Format

A page design’s layout is a JSON document: the page setup, an optional header and footer, and the sections that flow down the page, with the text, pictures, tables and other elements in them. Send it as layout when you create or update a page design with API v2. Getting a template returns its layout. The Page Designer edits the same layout, so a page design you create with the API can be changed in DocSpring, and the other way round.

The format’s JSON Schema is at https://docspring.com/schemas/page-designer/layout.v1.json. Point your editor or validator at it to check a layout before you send it.

DocSpring also checks things the schema can’t, such as unique IDs and valid Liquid. A layout with problems isn’t saved: the response is a 422 with a detail for each problem, whose message starts with the JSON path of the value it’s about:

{
"error": {
"code": "validation_failed",
"message": "Invalid request: /layout Layout is invalid: /sections/0/elements/0/content: the field \"customer.name |\" isn't valid Liquid: Expected id but found end_of_string in \"{{ customer.name | }}\"",
"details": [
{
"code": "invalid",
"message": "Layout is invalid: /sections/0/elements/0/content: the field \"customer.name |\" isn't valid Liquid: Expected id but found end_of_string in \"{{ customer.name | }}\"",
"pointer": "/layout"
}
],
"request_id": "54b79eb5-a7c3-41d8-913f-9152979130f7"
}
}

This is version 1 of the format: every layout has "version": 1. Version 1 may gain new optional properties and new values, such as another element type, font or page size, so a layout that’s valid today stays valid. Code that reads layouts should skip element types and properties it doesn’t know. A change that would make a valid version 1 layout invalid comes with a new version number and its own JSON Schema, and DocSpring keeps accepting version 1 layouts.

An invoice heading with the customer’s name in bold, and a table with a row for each line item:

{
"version": 1,
"page": {
"size": "letter",
"orientation": "portrait",
"margins": { "top": 36, "right": 36, "bottom": 36, "left": 36 },
"font": { "family": "Roboto", "size": 10 }
},
"sections": [
{
"id": "heading",
"type": "free",
"height": 40,
"elements": [
{
"id": "title",
"type": "text",
"x": 0,
"y": 0,
"width": 540,
"height": 24,
"font": { "size": 18 },
"content": {
"type": "doc",
"content": [
{
"type": "paragraph",
"content": [
{ "type": "text", "text": "Invoice for " },
{
"type": "field",
"attrs": { "expression": "customer.name" },
"marks": [{ "type": "bold" }]
}
]
}
]
}
}
]
},
{
"id": "items",
"type": "stack",
"direction": "vertical",
"elements": [
{
"id": "line_items_table",
"type": "table",
"width": null,
"height": null,
"source": "line_items",
"as": "item",
"columns": [
{
"id": "description",
"width": 3,
"header": {
"type": "doc",
"content": [
{
"type": "paragraph",
"content": [{ "type": "text", "text": "Description" }]
}
]
},
"cell": {
"type": "doc",
"content": [
{
"type": "paragraph",
"content": [
{
"type": "field",
"attrs": { "expression": "item.description" }
}
]
}
]
}
},
{
"id": "amount",
"width": 1,
"align": "right",
"header": {
"type": "doc",
"content": [
{
"type": "paragraph",
"content": [{ "type": "text", "text": "Amount" }]
}
]
},
"cell": {
"type": "doc",
"content": [
{
"type": "paragraph",
"content": [
{
"type": "field",
"attrs": { "expression": "item.amount | currency" }
}
]
}
]
}
}
],
"header": { "background": "#eeeeee" },
"border": { "width": 0.5, "color": "#999999" }
}
]
}
]
}

DocSpring adds a field for each value the layout reads: customer/name, line_items/~/description and line_items/~/amount here. Fields it already has are kept as they are, including fields the layout no longer reads (the fields DocSpring adds).

PropertyRequiredDescription
versionYes1
pageYesThe page size, margins and default text style (Page)
headerNoElements in every page’s top margin (Header and footer)
footerNoElements in every page’s bottom margin
sectionsYesThe sections, top to bottom (Sections). Pages break wherever they fill

The sections hold the elements: text, images, tables, charts, checkboxes, form fields, QR codes, barcodes, shapes, lines and HTML boxes. Text boxes and table cells hold rich text, whose fields print values from your data. Sections and elements can have a condition. Fonts and box styles style them.

Lengths are in points: 72 points make an inch. Colors are #rrggbb. In a free section or a header or footer, each element has an x and y from the top left corner of the section’s content, and a width and height. In a stack or a column, elements go one after another and take the room they need.

  • Every section, element, table column, column and page number has an id: 1 to 64 letters, digits, _ and -, unique in the layout.
  • A layout is at most 2,000,000 bytes, with up to 500 sections and 500 elements in each section, header and footer.
  • Lengths go up to 14,400 points (200 inches).