Skip to content

Template and Payload

Press supports splitting a document into two parts: a template that defines the design, and a payload that provides the content. This separation is the key to using Press at scale -- store a template once and generate thousands of documents by sending different payloads.

How It Works

A template contains the layout, styles, components, and page definitions:

xml
<!-- Template: stored on the platform -->
<press>
  <document format="A4" page-margin="2cm">
    <page>
      <frame direction="row" space-after-desired="24pt">
        <frame width="fill">
          <frame font-size="10pt">To: {{ data.recipient }}</frame>
          <frame font-size="10pt">Date: {{ data.date }}</frame>
        </frame>
        <img src="logo" max-height="40pt" />
      </frame>
      <flow name="body" />
      <frame space-before-desired="24pt">
        <p>Yours sincerely,</p>
        <p font-style="bold">{{ data.sender }}</p>
      </frame>
    </page>
  </document>

  <assets>
    <images>
      <logo>https://examples.papermill.io/papermill_logo.png</logo>
    </images>
  </assets>

  <styles>
    <document>
      <font>Inter</font>
      <font-size>10pt</font-size>
      <line-height>1.5</line-height>
    </document>
  </styles>
</press>

A payload provides just the parts that change:

xml
<!-- Payload: sent via API -->
<press>
  <flows>
    <body type="markdown">
      Thank you for your application to the Graduate Programme.

      I'm delighted to confirm that you have been accepted. Your start
      date is 1 September 2026. Please find enclosed the onboarding
      documents for your review.

      We look forward to welcoming you to the team.
    </body>
  </flows>

  <data type="json">
  {
    "recipient": "Dr. A. Patel",
    "sender": "R. Whitfield, HR Director",
    "date": "15 January 2026"
  }
  </data>
</press>

Merging Rules

When Press receives both a template and a payload, it merges them:

Top-Level ElementMerge Behaviour
<flows>Payload flows replace template flows with the same name. New flows are added.
<data>Merged shallowly. Payload fields override template fields with the same key.
<components>Merged. Payload components are added to or override template components.
<styles>Template styles are used. Payload styles are merged in.
<assets>Template assets are used. Not presently overridden by payloads.
<document>Template document structure is used. Not overridden.
<pages>Template page definitions are used. Not overridden.

Data Merging in Detail

Template:

json
{ "currency": "£", "tax_rate": 20, "company": "Default Corp" }

Payload:

json
{ "company": "Meridian Consulting", "client": "Helena Torres" }

Result:

json
{ "currency": "£", "tax_rate": 20, "company": "Meridian Consulting", "client": "Helena Torres" }

The payload's company wins, template-only fields (currency, tax_rate) are preserved, and new fields (client) are added.

Using Template and Payload via the API

  1. Create your template on the Papermill platform
  2. Copy the template ID from the editor URL
  3. Send a payload via the API with the template ID:
javascript
const payload = `
  <press>
    <flows>
      <body>Thank you for your application...</body>
    </flows>
    <data>
      <recipient>Dr. A. Patel</recipient>
      <sender>R. Whitfield</sender>
      <date>15 January 2026</date>
    </data>
  </press>
`

const response = await fetch(`https://api.papermill.io/v2/pdf?template_id=${templateId}`, {
  method: 'POST',
  headers: {
    'Content-Type': 'text/xml',
    'X-API-Key': apiKey,
  },
  body: payload,
})

Benefits

  • Designers control the template: layout, fonts, colours, page structure
  • Developers control the payload: content, data, conditional sections
  • AI models can generate markdown payloads without needing to understand the template structure
  • One template generates unlimited variations by changing the payload

Best Practices

Put defaults in the template. If most invoices use GBP, set "currency": "£" in the template's <data>. Payloads only need to override it when the currency differs.

Use asset data for constants. Values that should never change (company logos, legal text) go in <assets><data>. These aren't affected by payload merging.

Keep payloads minimal. Only send the data and flows that change. The template handles everything else.

Use markdown flows for AI-generated content. AI models produce clean markdown. The template handles all formatting and layout.