HTML template
What this guide covers
This guide walks you through rendering a single HTML invoice in n8n using invoice_sample_1.html and invoice_sample_data_1.json. The template uses mustache syntax ({{recipient.name}}, {{#each subInfo}}). HTML is the only template type that supports pasting raw markup in HTML Code. Output is HTML only (ideal for email bodies or web previews).
Before You Start
invoice_sample_1.html is a full invoice layout with nested paths ({{recipient.postalAddress.street1}}) and a line-item loop ({{#each subInfo}}). Paths must match your JSON structure exactly.invoice_sample_data_1.json (recommended), test.xml, or test.csv. JSON uses nested objects and a subInfo array. CSV flattens fields and uses one row per line item.Sample File Pack
Download all four files below. One HTML template plus three data formats with the same invoice content.
What's Inside the Sample Files
Template layout (invoice_sample_1.html)
The sample is a styled HTML invoice (tables, logo, PDF4me seller block). Dynamic sections:
| Document section | Static content (fixed in template) | Mustache placeholder (filled from data) |
|---|---|---|
| Recipient address | (layout only) | {{recipient.name}}, {{coText}}, {{recipient.postalAddress.*}} |
| Seller block | PDF4me, Zurich, dev.pdf4me.com | (static) |
| Buyer / delivery | Buyer label | {{buyer.name}}, {{coTextDelivery}}, {{buyer.postalAddress.*}} |
| Invoice meta | Due Date, Invoice Number, Issued On labels | {{dueDate}}, {{invoiceNumber}}, {{issuedOn}} |
| Line items table | Product, Period, Quantity, Price, VAT, Total headers | {{#each subInfo}} … {{plan}}, {{quantity}}, {{vat}}, {{totalPrice}} |
| Period column | (single range per invoice) | {{periodStart}} - {{periodEnd}} |
| Total row | Total balance label | {{totalAmount}} |
HTML templates use {{fieldName}} and {{object.nestedKey}}. Repeat line items with {{#each subInfo}} … {{/each}}. This is different from Word templates, which use <<[fieldName]>>. See the HTML template setup guide for more patterns.
HTML Code is only valid when Template File Type is HTML. For Word, Pdf Form, Mail Merge, or Google Docs, use Binary Data, Base64, or URL instead.
Field mapping across all data files
| HTML placeholder | JSON path (invoice_sample_data_1.json) | XML element (test.xml) | CSV column (test.csv) | Sample value |
|---|---|---|---|---|
{{recipient.name}} | recipient.name | Recipient/Name | recipient_name | Test AG |
{{coText}} | coText | CoText | coText | cotext |
{{recipient.postalAddress.street1}} | recipient.postalAddress.street1 | Recipient/PostalAddress/Street1 | recipient_street1 | Test Street1 |
{{recipient.postalAddress.street2}} | recipient.postalAddress.street2 | Recipient/PostalAddress/Street2 | recipient_street2 | Test Street2 |
{{recipient.postalAddress.zipCode}} {{city}} | recipient.postalAddress.zipCode, .city | Recipient/PostalAddress/ZipCode, City | recipient_zipCode, recipient_city | 8000 Zurich |
{{recipient.postalAddress.country}} | recipient.postalAddress.country | Recipient/PostalAddress/Country | recipient_country | Switzerland |
{{buyer.name}} | buyer.name | Buyer/Name | buyer_name | buyer name |
{{coTextDelivery}} | coTextDelivery | CoTextDelivery | coTextDelivery | Delivery text |
{{buyer.postalAddress.street1}} | buyer.postalAddress.street1 | Buyer/PostalAddress/Street1 | buyer_street1 | Test Street1 |
{{buyer.postalAddress.street2}} | buyer.postalAddress.street2 | Buyer/PostalAddress/Street2 | buyer_street2 | Test Street2 |
{{dueDate}} | dueDate | DueDate | dueDate | 2025-04-30 |
{{invoiceNumber}} | invoiceNumber | InvoiceNumber | invoiceNumber | 123456 |
{{issuedOn}} | issuedOn | IssuedOn | issuedOn | 2025-04-01 |
{{periodStart}} - {{periodEnd}} | periodStart, periodEnd | PeriodStart, PeriodEnd | periodStart, periodEnd | 2025-03-01 to 2025-03-31 |
{{#each subInfo}} {{plan}} | subInfo[].plan | SubInfo/Item/Plan | plan | PDF4me base 1000 |
{{quantity}} | subInfo[].quantity | SubInfo/Item/Quantity | quantity | 1 |
{{vat}} | subInfo[].vat | SubInfo/Item/Vat | vat | 2.83 |
{{totalPrice}} | subInfo[].totalPrice | SubInfo/Item/TotalPrice | totalPrice | 37.83 |
{{totalAmount}} | totalAmount | TotalAmount | totalAmount | 124.31 |
The sample JSON includes two objects in subInfo (PDF4me base 1000 and Call Package 2000). The {{#each subInfo}} blocks in the HTML render one table cell row per item.
The Workflow at a Glance
Fastest test: paste HTML and JSON directly in the PDF4me node (no file nodes required).
Manual Trigger → PDF4me Generate Document (Single) → (optional) Send Email / Write Binary File
| Step | n8n node | Purpose |
|---|---|---|
| 1 | Manual Trigger | Start the workflow on demand |
| 2 | PDF4me → Generate Document (Single) | Paste HTML Code + JSON Text, output rendered HTML |
| 3 | Send Email or Write Binary File (optional) | Deliver or save generated_document_output.html |
/generate-document-single-full-html.png)
Target configuration: pasted HTML Code + JSON in Document Data Text + HTML output
Step 1: Download the Sample Files
- Download
invoice_sample_1.htmlandinvoice_sample_data_1.jsonfrom the Sample File Pack above. - Open both files in a text editor so you can copy the full contents into the n8n node.
- Optionally download
test.xmlortest.csvto test XML or CSV data types later.
Step 2: Create the n8n Workflow
- In n8n, create a new workflow.
- Add a Manual Trigger node.
- Add PDF4me → Generate Document (Single) after the trigger.
- Connect your PDF4me credential.
For production you can add a Read Binary File node instead of HTML Code (see Alternative template input below).
Step 3: Configure the HTML Template (HTML Code)
Open the PDF4me node and set the template fields:
| Field | Value |
|---|---|
| Template File Type | HTML |
| Output Type | HTML (only option for HTML templates) |
| Template File Input Type | HTML Code |
| Template File Name | invoice_sample_1.html |
| HTML Code | Paste the entire contents of invoice_sample_1.html |
If your snippet omits <html> or <head>, the node wraps it in a basic HTML shell automatically. The sample file is a complete document, so paste it as-is.
Step 4: Configure Document Data (JSON)
| Field | Value |
|---|---|
| Document Data Input Type | Text |
| Document Data Type | JSON |
| Document Data Text | Paste the full contents of invoice_sample_data_1.json (see block below) |
{
"recipient": {
"name": "Test AG",
"postalAddress": {
"street1": "Test Street1",
"street2": "Test Street2",
"zipCode": "8000",
"city": "Zurich",
"country": "Switzerland"
}
},
"coText": "cotext",
"buyer": {
"name": "buyer name",
"postalAddress": {
"street1": "Test Street1",
"street2": "Test Street2"
}
},
"coTextDelivery": "Delivery text",
"dueDate": "2025-04-30",
"invoiceNumber": "123456",
"issuedOn": "2025-04-01",
"subInfo": [
{
"plan": "PDF4me base 1000",
"quantity": 1,
"price": 35,
"vat": 2.83,
"totalPrice": 37.83
},
{
"plan": "Call Package 2000",
"quantity": 1,
"price": 80,
"vat": 6.48,
"totalPrice": 86.48
}
],
"totalAmount": 124.31,
"periodStart": "2025-03-01",
"periodEnd": "2025-03-31"
}
Core node settings (summary)
| Field | Value | Notes |
|---|---|---|
| Credential to connect with | Your PDF4me credential | Get API key |
| Resource | Generate | |
| Generate Operations | Generate Document (Single) | |
| Binary Data Output Name | data (default) | Output is HTML in this binary property |
Step 5: Execute and Verify the HTML
- Click Execute workflow.
- Open the PDF4me node output. Under Binary, open property
data(generated_document_output.html). - Confirm the rendered invoice shows:
- Recipient → Test AG, cotext, Test Street1/2, 8000 Zurich, Switzerland
- Buyer → buyer name, Delivery text, Test Street1/2
- Invoice meta → Due Date 2025-04-30, Invoice Number 123456, Issued On 2025-04-01
- Line items → PDF4me base 1000 and Call Package 2000 with quantities and VAT
- Total balance → 124.31
If a placeholder renders blank, check the mustache path against your JSON. recipient.postalAddress.street1 in the template requires the same nested structure in data.
Step 6: Send or Save the Output (Optional)
Send Email: map the PDF4me binary data as the HTML body (enable HTML email).
Write Binary File:
| Field | Value |
|---|---|
| File Name | invoice-output.html |
| Data Property Name | data |
| Output Path | Folder where n8n should write the file |
Alternative Template Input: Load HTML from File
If you prefer not to paste HTML into the node:
- Add Read Binary File before PDF4me and point it to
invoice_sample_1.html. - In PDF4me set Template File Input Type to Binary Data, Template Binary Property to
data, Template File Name toinvoice_sample_1.html. - Keep Document Data Input Type as Text and paste the JSON as in Step 4.
You can also host the .html at a public URL and use Template File Input Type: URL with Template File URL.
Alternative Data Formats
Option A: JSON file as binary (invoice_sample_data_1.json)
- Add Read Binary File for the JSON file (or use a Merge node if the template is also binary).
- Set Document Data Input Type to Binary Data, Document Data Type to JSON, Document Binary Property to your data field, Document Data File Name to
invoice_sample_data_1.json.
Option B: XML (test.xml)
Set Document Data Type to XML and paste the contents of test.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Invoice>
<Recipient>
<Name>Test AG</Name>
<PostalAddress>
<Street1>Test Street1</Street1>
<Street2>Test Street2</Street2>
<ZipCode>8000</ZipCode>
<City>Zurich</City>
<Country>Switzerland</Country>
</PostalAddress>
</Recipient>
<CoText>cotext</CoText>
<Buyer>
<Name>buyer name</Name>
<PostalAddress>
<Street1>Test Street1</Street1>
<Street2>Test Street2</Street2>
</PostalAddress>
</Buyer>
<CoTextDelivery>Delivery text</CoTextDelivery>
<DueDate>2025-04-30</DueDate>
<InvoiceNumber>123456</InvoiceNumber>
<IssuedOn>2025-04-01</IssuedOn>
<SubInfo>
<Item>
<Plan>PDF4me base 1000</Plan>
<Quantity>1</Quantity>
<Price>35</Price>
<Vat>2.83</Vat>
<TotalPrice>37.83</TotalPrice>
</Item>
<Item>
<Plan>Call Package 2000</Plan>
<Quantity>1</Quantity>
<Price>80</Price>
<Vat>6.48</Vat>
<TotalPrice>86.48</TotalPrice>
</Item>
</SubInfo>
<TotalAmount>124.31</TotalAmount>
<PeriodStart>2025-03-01</PeriodStart>
<PeriodEnd>2025-03-31</PeriodEnd>
</Invoice>
Option C: CSV (test.csv)
Set Document Data Type to CSV and paste the CSV body. The sample has two data rows (one per subInfo line item); header columns use flattened names like recipient_name and plan:
recipient_name,recipient_street1,recipient_street2,recipient_zipCode,recipient_city,recipient_country,coText,buyer_name,buyer_street1,buyer_street2,coTextDelivery,dueDate,invoiceNumber,issuedOn,periodStart,periodEnd,totalAmount,plan,quantity,price,vat,totalPrice
"Test AG","Test Street1","Test Street2","8000","Zurich","Switzerland","cotext","buyer name","Test Street1","Test Street2","Delivery text","2025-04-30","123456","2025-04-01","2025-03-01","2025-03-31",124.31,"PDF4me base 1000",1,35,2.83,37.83
"Test AG","Test Street1","Test Street2","8000","Zurich","Switzerland","cotext","buyer name","Test Street1","Test Street2","Delivery text","2025-04-30","123456","2025-04-01","2025-03-01","2025-03-31",124.31,"Call Package 2000",1,80,6.48,86.48
Production Workflow Patterns
Common ways to supply HTML template and data in productionOnce the sample test works, replace the Manual Trigger with these patterns.
- Webhook receives billing payload.
- PDF4me runs with fixed HTML Code template.
- Map webhook JSON to Document Data Text.
- Send Email uses output HTML as the message body.
- Google Drive / S3 stores
invoice_sample_1.html. - Download node loads HTML as binary.
- PDF4me: Template File Input Type = Binary Data.
- Data built from Sheets or CRM as JSON.
- Host
.htmland.jsonat public HTTPS URLs. - Set Template File Input Type = URL and Document Data Input Type = URL.
- No Read Binary File nodes required.
Frequently Asked Questions
Related Guides
- Generate Document (Single) overview: all parameters, output fields, and template types
- PDF4me Word Template: Word
.docxwith<<[field]>>tags and PDF output - Generate HTML from template in Make: same pattern in Make