Templates
Templates are reusable HTML documents with dynamic variables. Design them once in the dashboard, then render them via API with different data each time.
Creating a template
From the dashboard
Click New template on the dashboard. Choose a starter template (Invoice, Payslip, Certificate, Receipt, Letter) or start blank.
Via API
curl -X POST https://pdf4.dev/api/v1/templates \
-H "Authorization: Bearer p4_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Monthly invoice",
"html": "<h1>Invoice #{{invoice_number}}</h1><p>Total: {{total}}</p>",
"sample_data": {
"invoice_number": "INV-001",
"total": "$1,000.00"
}
}'A URL-safe slug is auto-generated from the name (e.g., monthly-invoice). You can use either the id or the slug to reference a template in render requests.
Template structure
Each template has:
| Field | Description |
|---|---|
id | Unique identifier (tmpl_xxx format) |
name | Display name |
slug | URL-safe identifier, unique per user |
html | HTML content with {{variables}} |
plain_text | Auto-generated plain text version |
pdf_format | Page size, margins, and global styles |
sample_data | Default values for preview (not used during API rendering) |
Using variables
Insert {{variable_name}} anywhere in your HTML. When rendering, pass a data object to replace them:
<h1>Hello {{customer_name}}</h1>
<p>Your order #{{order_id}} has been confirmed.</p>
<p>Total: {{total}}</p>{
"data": {
"customer_name": "Jane Smith",
"order_id": "ORD-2025-042",
"total": "$299.00"
}
}See Variables for detailed syntax rules.
Sample data
The sample_data field stores default values used in the dashboard preview. These are not used during API rendering: you must always pass data explicitly.
This lets you see a realistic preview while editing without affecting production renders.
Referencing templates
When calling POST /api/v1/render, you can reference a template by:
- ID:
"template_id": "tmpl_a1b2c3d4e5f6" - Slug:
"template_id": "monthly-invoice"
Both resolve to the same template. Slugs are human-readable and stable unless you rename the template.
Components
Templates can include reusable header, footer, and block components. In the code editor, they appear as custom HTML tags:
<pdf4-header component-id="comp_abc">Company Header</pdf4-header>
<pdf4-block component-id="comp_xyz">Signature Block</pdf4-block>
<pdf4-footer component-id="comp_def">Page Footer</pdf4-footer>Multi-page repetition
Header and footer components repeat on every page of the rendered PDF. Under the hood, the renderer restructures the document into a table with <thead> (header) and <tfoot> (footer) elements, which Chromium's print engine repeats automatically on each page.
Style inheritance
Components are injected into the same document as the template, so they inherit all global styles set via the pdf_format object: font_family, font_size, color, line_height, and any font loaded via google_fonts_url.
Custom fonts
To use a Google Font (or any @import-compatible CSS URL) across your template and all its components, set google_fonts_url in the format:
{
"format": {
"font_family": "Roboto, sans-serif",
"google_fonts_url": "https://fonts.googleapis.com/css2?family=Roboto&display=swap"
}
}The font stylesheet is loaded in <head> so it is available before rendering.
Component gap
Use component_gap to control the spacing between header/footer components and the page content:
{
"format": {
"component_gap": "5mm"
}
}Footer position
Use footer_position to control whether the footer sticks to content or pins to the page bottom:
{
"format": {
"footer_position": "page-bottom"
}
}Two modes: "after-content" (default) places the footer right after the last content row, "page-bottom" pins it to the bottom of every page.
See PDF format for all available format options.
Duplicating templates
Duplicate a template via the dashboard (3-dot menu) or API:
curl -X POST https://pdf4.dev/api/v1/templates/tmpl_xxx/duplicate \
-H "Authorization: Bearer p4_live_xxx"The copy gets "(copy)" appended to its name.