Skip to content

Templates in workflows

A template on its own is a design; a workflow makes it a production line. The AI writes the copy, a catalogue brings the facts, a photo is generated or cut out — and a template node puts it all on the page, the same way every time, for one customer or for a thousand. This page explains how to connect a template to a workflow so that the result is right and stays right.

You need Node What it produces
One document from structured data — the usual choice Render Document Template (design/template_render) PDF, page images, a pages manifest, a layout report; PDF/X-4 for print; always a fixed published revision
One document, one input port per field Generate PDF (document/pdf) one PDF
One PDF with a page set per item of a list — a catalogue, one certificate per participant Multi-page PDF (aggregate/pdf) one PDF, with optional cover and closing PDFs

To join a fixed set of PDFs that already exist, use Merge PDF (utility/merge_pdf) instead; it does not iterate.

The template’s contract lists its fields: code, type, required, default, and for lists the keys of each item. Read it before wiring (get_design_template, view contract; REST GET /api/v1/design-templates/{tpl_id}/versions/{revision}/contract). The field codes are the keys of the data.

Render Document Template accepts the data three ways, which can be combined:

Port Carries Precedence
field inputs — one port per field code (hero_image, investment, claims) a single value for that field highest
assets a JSON map of image field codes to storage references or URLs middle
data, or data_0, data_1, … JSON objects keyed by field code, merged in index order (a later object overrides an earlier one’s keys) lowest

Generate PDF and Multi-page PDF take only field inputs: each field code of the template is an input port, typed like the field. Connect the fields to fill; the others keep the value written in the template. A connection to a field the template does not have is rejected, with the list of valid fields.

The single most important rule: the AI writes words, never facts. Prices, dates, names, legal notes, claims with a source — they come from inputs, catalogues and systems, and must reach the page untouched. Two patterns make it structural:

  • Separate data objects. The copy written by the AI on data_0, the verified offer on data_1: the offer wins on any shared key, and the AI never even sees the prices.
  • Field inputs for facts. Connect each fact to its own field port — investment from a number input, claims from a JSON value, client_logo from an image input. A field input overrides whatever the data says.

The F01 proposal does both:

Brief ──► Write the copy (AI, JSON) ──► Copy fits the page (JSON schema) ──data──► Render Document Template ──► PDF
└─► Cover prompt ──► Paint the cover ──hero_image──► │ ──► Preview
Client logo ──client_logo──► │ Investment ──investment──► │ Approved claims ──claims──► │ ──► Layout report

A total, a VAT amount, a deposit or an average is a fact too: the AI must not compute it, even when it has the numbers. When the source gives the lines but not the totals, compute them with Calculate (utility/calculate): an expression such as round(sum(quote.items[*].amount) * (1 + vat_rate), 2) whose variables — quote, vat_rate — become its input ports. The arithmetic is exact decimal, a text value is never read as a number, and a missing field or a division by zero stops the run instead of printing a wrong or empty amount. Connect its result to a field port (total), or run it once per item inside an enumerator for a per-line amount.

When the source system already has the totals, pass them through instead: a document that recalculates them could disagree with the invoice by a rounding. The F12 quote does that.

A template has limited space; the AI does not know it unless you say so, and check it.

  1. Ask for JSON with the template’s keys, and give each key its limit in characters, taken from the space on the page: “headline”: at most 70 characters, one or two lines. Say what must never appear (numbers, prices, promises).
  2. Validate it before the render with JSON Schema Validate (utility/json_schema_validate): the exact keys, additionalProperties: false, and maxLength for every text. In mode fail a copy that does not fit stops the run with the list of violations — no document with a truncated headline is produced.
  3. Let the template decide the rest: growth rules, shrink or ellipsis for the texts that vary (see Text).
{ "id": "copy_contract", "type": "utility/json_schema_validate",
"parameters": { "schema_source": "inline", "mode": "fail",
"schema_definition": { "type": "object", "additionalProperties": false,
"required": ["headline", "subheadline"],
"properties": { "headline": { "type": "string", "minLength": 20, "maxLength": 70 },
"subheadline": { "type": "string", "minLength": 40, "maxLength": 150 } } } } }

A list field (a repeated list in the template) receives one JSON value — the whole array. Pass it with a JSON Value input (input/json_value) or from a node that produces JSON; do not use an enumerator, which would split the list into one run per item. See Iteration.

One document per item, or one PDF for the whole list

Section titled “One document per item, or one PDF for the whole list”
  • One file per item — a flyer per product, a certificate per participant as separate files: put the template node inside the iterated branch. It runs once per item and produces one PDF per item.
  • One PDF with a page set per item — a catalogue, a register of certificates: use Multi-page PDF after the iterated branch. Connect the per-item values to its field ports; values that are not iterated (the course title, the date) are the same on every item’s pages. introPdf and outroPdf add a cover and closing pages — for example a cover rendered by another template node.
Participants (JSON enumerator) ──► per item: name, hours, merit ──┐
Course title, dates ──────────────────────────────────────────────┼──► Multi-page PDF ──► one PDF
Cover (Generate PDF, another template) ──introPdf─────────────────┘

The F10 certificates build exactly this.

  • Render Document Template always renders a published revision: template_id plus template_revision; without a revision, the current published one is fixed when the workflow is saved. template_version_policy latest_compatible lets new runs follow later compatible revisions; pinned (default) never moves.
  • Generate PDF and Multi-page PDF render the template’s current draft when template_revision is not set — useful while designing, risky in production: a later edit to the draft changes every document. Set template_revision before you rely on the workflow.
{ "id": "render", "type": "design/template_render",
"parameters": { "template_id": "tpl_…", "template_revision": 3, "output": "both",
"missing_policy": "fail_required", "overflow_policy": "template" } }
Parameter Values Use
output pdf, image, both, pages PDF; one page image (page_selection must pick one page); both; or a manifest of every page image
page_selection all, 1, 1-3, 1,3-5 which pages become images
missing_policy fail_required (default), use_template_default stop when a required field has no value, or print the template’s own value
overflow_policy template (default), fail, fit, clip keep each list’s own rule, or impose one on every list
max_repeat 1–100 ceiling on the items of any list
pdf_export_mode, color_profile_guid standard / pdfx4 and a workspace profile print-ready output (see Print-ready PDF)

Besides the PDF and the images, the node returns a layout report (madoo.template-layout-report/v1): the status, the revision used, list rows printed and left out, images loaded and failed, texts that did not fit, links left out, the time taken. Expose it as a JSON output while building a workflow — it tells you what happened on the page without opening the PDF. quality_check is a shorter summary of the same health.

The template nodes cost no credits; the AI steps before them do.

  • The contract has been read, and every required field is connected or in the data.
  • Facts reach the page through field inputs or a separate data object, never through the AI.
  • Totals and other computed amounts come from the source system or from Calculate, never from the AI.
  • AI copy is JSON with the template’s keys, validated against a schema with maxLength from the page.
  • Lists reach their field as one JSON value, not through an enumerator.
  • The template revision is fixed for every template node in production.
  • The layout report of a test run shows no rows left out, no image failed, no text cut.