Skip to main content

Invoice Layout JSON

Invoice Builder layouts describe the structure and order of an invoice PDF. A layout is a JSON document interpreted by the invoice renderer using the application's built-in PDF components.

Layouts are intentionally declarative and restricted. JSON can choose which supported content appears and how supported blocks are composed, but it cannot provide React code, arbitrary styles, custom fonts, labels, or page settings.

How To Use A Layout​

  1. Open Layouts in the application.
  2. Export an existing layout JSON or create a JSON file using the schema below.
  3. Open a layout and use Upload schema to select the .json file.
  4. Confirm that the read-only viewer shows the expected structure.
  5. Save the layout.
  6. Select the saved, non-archived layout in invoice customization under page setup.

The upload is validated before it replaces the displayed schema. Invalid JSON or unsupported properties are rejected. The maximum layout size is 64 KB.

Ready-made layout examples, including V2 region, sidebar, nested-header, and receipt-style compositions, are available in layouts.

The Layouts Visual tab can edit both V1 and V2 schemas. The JSON tab is a read-only inspection view; use Upload schema to replace a layout with validated JSON. Visual edits support undo and redo, and Preview mode renders a representative invoice through the same PDF interpreter used by invoice and quote output.

An invoice stores a snapshot of the selected layout. Later changes to the saved layout do not change invoices that already have a snapshot.

Top-Level Structure​

{
"schemaVersion": 1,
"meta": {
"name": "My Layout",
"description": "Optional description"
},
"sections": []
}
PropertyRequiredDescription
schemaVersionYesMust be 1.
meta.nameYesNon-empty layout name, up to 120 characters.
meta.descriptionNoOptional description.
sectionsNoOrdered list of invoice sections. Sections are rendered in this order.

Only schemaVersion, meta, and sections are allowed at the top level. Each section type may occur at most once.

V2 Page Regions​

V2 layouts compose the complete page from explicit regions. V2 keeps content types whitelisted and continues to use invoice customization for fonts, colors, labels, table styles, and page format.

{
"schemaVersion": 2,
"meta": { "name": "Sidebar invoice" },
"orientation": "landscape",
"regions": [
{
"id": "sidebar",
"width": "30%",
"direction": "column",
"blocks": [{ "type": "logo" }, { "type": "businessInfo" }, { "type": "paymentInfo" }]
},
{
"id": "main",
"width": "70%",
"direction": "column",
"sections": ["header", "itemsTable", "financialTotals", "notes"]
}
]
}
PropertyRequiredDescription
schemaVersionYesMust be 2.
meta.nameYesNon-empty layout name, up to 120 characters.
meta.descriptionNoOptional description.
orientationNoportrait or landscape; defaults to the selected page format orientation.
regionsYesOrdered page regions. Each region must have unique id, a supported percentage width, and direction of row, column, or grid. Supported region widths are 20%, 25%, 30%, 35%, 40%, 50%, 60%, 65%, 70%, 75%, 80%, and 100%.
regions[].gapNoOptional spacing after the region, 5 or 10.
regions[].blocksConditionalA whitelisted header-block tree. A region cannot define both blocks and sections.
regions[].sectionsConditionalReferences to supported invoice sections. Each section may be referenced only once across the layout.
  • regions[].children is a recursive list of row, column, grid, block, or section nodes. Use section nodes for per-region section settings.
  • regions[].overflow is either continue or keepTogether.
  • regions[].gap accepts 5 or 10 and adds spacing after the region when rendered beside another region.

For V2, region widths must total no more than 100%. Use children when a region needs nested rows, columns, grids, or per-section configuration. A region must use exactly one content form: blocks, sections, or children.

When a V1 layout is upgraded through the Visual Builder, its sections are preserved as section nodes inside one main V2 region. V2-only features such as regions, grids, orientation, and overflow then become available; downgrading V2 back to V1 is not supported.

{
"type": "row",
"children": [
{ "type": "block", "block": { "type": "logo" } },
{ "type": "section", "section": { "type": "itemsTable", "visible": true, "columnSizing": "proportional" } }
]
}

Regions with continue flow across pages, while keepTogether requests a single region placement when the PDF renderer has enough space. Item-table headers repeat on continuation pages and individual item rows remain together. Financial and payment sections are kept together. Unsupported properties, executable content, duplicate region IDs, invalid widths, oversized combined widths, unsupported blocks, and duplicate sections are rejected before saving.

For a configured section, use a section node:

{
"type": "section",
"section": {
"type": "totalsRow",
"visible": true,
"totalsBlocks": [{ "type": "financialTotals" }, { "type": "spacer" }]
}
}

Visual Builder Dropdowns​

The Visual tab exposes the same values accepted by the schema validator. The labels below describe the controls shown while editing a V2 layout:

Visual controlValuesMeaning
Orientationportrait, landscapeSelects the PDF page orientation for the V2 composition. Default leaves orientation unset so the selected page format supplies it.
Region width20%, 25%, 30%, 35%, 40%, 50%, 60%, 65%, 70%, 75%, 80%, 100%The region's share of the page width. Combined region widths cannot exceed 100%.
Region directionrow, column, gridrow lays children horizontally, column lays children vertically, and grid lays children horizontally with wrapping.
Region gap5, 10Adds supported spacing after the region. The empty/default choice leaves the region gap unset.
Region overflowcontinue, keepTogetherWrap leaves the default flowing behavior. continue allows the region to flow across pages; keepTogether requests that the region stay together when space allows.
Section visibilitytrue, false, autoVisible always renders the section, Hidden suppresses it, and auto lets the section decide whether it has content.
Section alignmentstart, center, endControls the supported horizontal alignment of section output, currently used by financialTotals. The empty/default choice leaves alignment unset.
Watermark orderdefault, paidFirstDefault uses the normal watermark order. paidFirst places the paid watermark before the normal watermark when applicable.
Table sizingfixedFlex, proportionalTable default leaves the section's sizing unset. fixedFlex uses the standard fixed/flexible columns; proportional uses proportional column widths.
Header blocktitle, logo, businessInfo, clientInfo, invoiceMeta, paymentInfoAdds the selected header content block. The builder does not add an unspecified block type automatically.
Structural noderow, column, gridAdds a recursive composition node. Structural nodes can contain additional nodes.
Section nodewatermark, header, itemsTable, financialTotals, paymentInfo, totalsRow, notes, signature, pageCounterAdds the selected invoice section as a V2 node. Section types already used anywhere in the layout are removed from the palette because each section type may occur only once.
Block width20%, 40%, 50%, 60%, 100%Sets a header block's width within a row. The empty/default choice leaves width unset.
Block alignmentstart, center, endAligns the block's content within its available space.
Gap5, 10Sets the spacing between children. The empty/default choice leaves the schema property unset.
PaddingpaddingTop: 10, 20; paddingBottom: 20Adds supported spacing before or after a header block. Empty choices leave the property unset.
Payment sourcebank, legacyBusinessChooses the bank snapshot or legacy business payment information for a payment block.
JustificationbetweenPlaces row children with space between them. The empty/default choice leaves justification unset.
Boolean block optionsboxed, showTitle, showInvoiceLabel: enabled or disabledWrites true or false for the selected supported presentation property. The empty/default choice leaves it unset.

Region IDs are editable inline and must be unique and non-empty. Adding a region uses the lowest available generated ID such as region-1; the semantic main ID is reserved for the V1-to-V2 upgrade. Invalid or duplicate values are rejected before saving.

Header blocks are reusable composition elements. The same logo, businessInfo, clientInfo, invoiceMeta, or paymentInfo block may appear more than once when the page composition needs it. Repeating a block renders the corresponding invoice content again; it does not duplicate the underlying invoice data. This differs from invoice section types, which are unique across a layout.

Sections​

Every section has this shape:

{
"type": "itemsTable",
"visible": true
}

visible is required and accepts:

  • true: always render the section.
  • false: never render the section.
  • "auto": let the content component decide whether there is content to render. This is useful for optional notes, signatures, payment information, and watermarks.

Sections may also define align with "start", "center", or "end". This currently affects financialTotals; other section types ignore it.

The supported section types are:

watermark​

Renders the normal invoice watermark and, when applicable, the paid watermark. Optional watermarkOrder controls their order:

{
"type": "watermark",
"visible": "auto",
"watermarkOrder": "paidFirst"
}

Values are "default" or "paidFirst". If omitted, the default order is used.

Renders the header using recursive blocks. See Header blocks.

{
"type": "header",
"visible": true,
"blocks": [
{
"type": "row",
"justify": "between",
"children": [{ "type": "logo" }, { "type": "invoiceMeta", "showInvoiceLabel": true }]
}
]
}

itemsTable​

Renders the invoice item table. Optional columnSizing accepts:

  • "fixedFlex": the standard fixed/flexible column behavior.
  • "proportional": proportional column widths used by the legacy-compatible layouts.
{
"type": "itemsTable",
"visible": true,
"columnSizing": "fixedFlex"
}

Column labels, colors, borders, fonts, and table styling come from invoice customization, not this JSON.

financialTotals​

Renders subtotal, discounts, taxes, shipping, total, paid, and balance due using the current invoice values and customization labels. Optional align controls the horizontal placement and text alignment of the financial summary: "start", "center", or "end". The default is "end".

{ "type": "financialTotals", "visible": true, "align": "start" }

paymentInfo​

Renders payment information. With no extra property it uses the invoice bank snapshot.

{ "type": "paymentInfo", "visible": "auto" }

Payment information can also be placed inside a header block or a totalsRow. Those locations support the optional paymentSource property:

  • "bank": use the invoice bank information and QR code.
  • "legacyBusiness": use the legacy business payment information.

totalsRow​

Renders several totals-related blocks in one horizontal row. Use totalsBlocks in the desired order:

{
"type": "totalsRow",
"visible": true,
"totalsBlocks": [
{ "type": "paymentInfo", "paymentSource": "legacyBusiness" },
{ "type": "spacer" },
{ "type": "financialTotals" }
]
}

Supported totals row blocks are paymentInfo, financialTotals, and spacer. A spacer consumes flexible space and is useful for pushing financial totals to the opposite side.

notes​

Renders customer notes and terms and conditions. Use "auto" to omit the section when both are empty.

{ "type": "notes", "visible": "auto" }

signature​

Renders the signature image and authorised signatory information when available.

{ "type": "signature", "visible": "auto" }

pageCounter​

Renders the page counter.

{ "type": "pageCounter", "visible": true }

Header Blocks​

Header blocks can be nested only inside row and column blocks. This makes the header a small layout tree:

row
├── column
│ ├── logo
│ └── businessInfo
└── invoiceMeta

Leaf block types are:

TypeRenders
titleInvoice title.
logoBusiness logo.
businessInfoBusiness name and contact information.
clientInfoClient information.
invoiceMetaInvoice number, dates, status, and related metadata.
paymentInfoPayment information.

Container block types:

  • row: lays children out horizontally.
  • column: lays children out vertically.

Header block properties​

PropertySupported valuesApplies to
childrenArray of header blocksrow, column only.
width"20%", "40%", "50%", "60%", "100%"Any block used in a row.
align"start", "center", "end"Header blocks.
justify"between"Rows.
paddingTop10, 20Header blocks.
paddingBottom20Header blocks.
gap5, 10Rows and columns.
boxedtrue or falseSupported content blocks, commonly invoiceMeta.
showTitletrue or falseinvoiceMeta.
showInvoiceLabeltrue or falseinvoiceMeta.
paymentSource"bank", "legacyBusiness"paymentInfo.

row and column blocks must include a children array. Leaf blocks cannot include children.

Complete Example​

{
"schemaVersion": 1,
"meta": {
"name": "Two Column Invoice",
"description": "Business and invoice details above the items table"
},
"sections": [
{
"type": "watermark",
"visible": "auto",
"watermarkOrder": "paidFirst"
},
{
"type": "header",
"visible": true,
"blocks": [
{
"type": "row",
"justify": "between",
"paddingBottom": 20,
"children": [
{
"type": "column",
"width": "50%",
"children": [{ "type": "logo" }, { "type": "businessInfo" }]
},
{
"type": "column",
"width": "50%",
"align": "end",
"children": [
{
"type": "invoiceMeta",
"showTitle": true,
"showInvoiceLabel": true,
"boxed": true
}
]
}
]
},
{
"type": "row",
"paddingTop": 20,
"children": [
{ "type": "clientInfo", "width": "50%" },
{ "type": "paymentInfo", "width": "50%", "paymentSource": "bank" }
]
}
]
},
{ "type": "itemsTable", "visible": true, "columnSizing": "fixedFlex" },
{ "type": "financialTotals", "visible": true },
{ "type": "notes", "visible": "auto" },
{ "type": "signature", "visible": "auto" },
{ "type": "pageCounter", "visible": true }
]
}

What Layout JSON Controls​

Layout JSON controls the invoice's structural composition:

  • Which supported sections are included.
  • The order in which sections appear in the PDF.
  • Whether a section is always shown, hidden, or shown automatically when it has content.
  • The order of the normal and paid watermarks.
  • Whether the item table uses fixed/flexible or proportional column sizing.
  • Which header content blocks appear: title, logo, business information, client information, invoice metadata, and payment information.
  • Header composition through nested horizontal rows and vertical columns.
  • Header block widths, alignment, spacing, optional boxed presentation, invoice title visibility, and invoice label visibility.
  • Whether payment blocks use bank or legacy business payment information.
  • The order of payment information, financial totals, and flexible spacing inside a totalsRow.

The JSON controls composition, not the underlying invoice data. The renderer still supplies the current business, client, item, payment, and totals values.

What Layout JSON Does Not Control​

The following remain outside the layout schema and are configured elsewhere in invoice customization or application settings:

  • Translated labels and invoice text.
  • Colors, fonts, font sizes, borders, and table styling.
  • Page format, margins, and other page setup. V2 may select portrait or landscape orientation for its composition.
  • Invoice data, business data, client data, and payment values.
  • Thermal receipt printing.
  • Arbitrary React components, JavaScript, HTML, or CSS.

Validation Rules​

The application rejects a layout when:

  • The JSON is invalid or larger than 64 KB.
  • schemaVersion is not 1 or 2.
  • meta.name is missing, empty, or longer than 120 characters.
  • A property is not listed in this document.
  • A section or block type is unsupported.
  • A section is duplicated.
  • A container has no valid children array.
  • A block uses children, paymentSource, or another property in an unsupported location.
  • An enum value such as visible, width, align, columnSizing, or watermarkOrder is invalid.
  • A V2 region has invalid content ownership, duplicate region IDs, unsupported overflow behavior, or region widths totaling more than 100%.
  • A V2 recursive node has an unsupported type, invalid children, invalid spacing, nesting deeper than 12 levels, or a total layout node count above 500.

When adding new capabilities, the schema version and validator may be extended with a backwards-compatible field or a new version.