210 × 297 mm
Reports
Site inspection report
An A4 facility inspection report with an overall result, pass and fail counts, findings ranked by severity with due dates, a checklist grouped by area with status badges, photo reference placeholders and a separate sign-off page with page numbers.
Opens Dynamic Document API with this template preloaded in a free workspace.
Template language features
- Loops
- Conditionals
- Macros
- Filters
- Grouping
- Date formatting
- Number formatting
- Markdown
- Page breaks
- Repeating table headers
- Header & footer
- Page numbers
Filters such as format_currency and qrcode are described in the template language reference.
Variables
Derived from the sample data: 8 top-level fields, 50 paths in total. Send the same shape as data.
| Path | Type | Example |
|---|---|---|
| inspector_company | object | |
| inspector_company.name | string | "Blackbutt Facility Assurance Pty Ltd" |
| inspector_company.short_name | string | "Blackbutt Facility Assurance" |
| inspector_company.abn | string | "11 222 333 444" |
| inspector_company.address | string | "Level 2, 60 Denham Street, Townsville QLD 4810" |
| inspector_company.email | string | "reports@blackbutt.example.com" |
| inspector_company.website | string | "blackbutt.example.com" |
| site | object | |
| site.name | string | "Riverbend Community Aquatic Centre" |
| site.address | string | "18 Mangrove Parade ⏎ Riverbend QLD 4815" |
| site.contact | string | "Priya Venkataraman, Centre Manager" |
| inspection | object | |
| inspection.reference | string | "INS-2026-0915-04" |
| inspection.type | string | "Quarterly facility safety inspection" |
| inspection.date | date | "2026-09-15" |
| inspection.start_time | date | "2026-09-15T07:30:00+10:00" |
| inspection.end_time | date | "2026-09-15T11:10:00+10:00" |
| inspection.timezone | string | "Australia/Brisbane" |
| inspection.inspector | string | "Callum Ashworth" |
| inspection.inspector_role | string | "Senior Facility Inspector" |
| inspection.accreditation | string | "QFA-00417" |
| inspection.weather | string | "Fine, 27 °C" |
| inspection.next_inspection_months | number | 3 |
| inspection.locale | string | "en-AU" |
| checklist | array<object> · 18 | |
| checklist[].id | string | "CR-01" |
| checklist[].area | string | "Change rooms" |
| checklist[].item | string | "Floors dry and clean, non-slip matting in plac…" |
| checklist[].status | string | "pass" |
| checklist[].note | string | "Measured 47 °C at basin 3" |
| checklist[].photo | string | "P-01" |
| findings | array<object> · 4 | |
| findings[].id | string | "F-01" |
| findings[].severity | string | "high" |
| findings[].title | string | "Acid and chlorine stored too close together" |
| findings[].checklist_ref | string | "CS-02" |
| findings[].action | string | "Move the acid drums to the segregated bay and …" |
| findings[].owner | string | "Centre Manager" |
| findings[].due_in_days | number | 1 |
| photos | array<object> · 4 | |
| photos[].ref | string | "P-01" |
| photos[].checklist_ref | string | "CR-03" |
| photos[].caption | string | "East wall baby-change table, loose hinge brack…" |
| photos[].file | string | "IMG_4471.jpg" |
| summary | string | "The centre is generally **well maintained** an…" |
| sign_off | object | |
| sign_off.declaration | string | "I inspected the areas listed in this report on…" |
| sign_off.site_representative | string | "Priya Venkataraman" |
| sign_off.site_representative_role | string | "Centre Manager" |
| sign_off.distribution | array<string> · 3 | "Centre Manager" |
Sample data
Fictional records used for previews. Replace them with your own data when you call the API.
{
"inspector_company": {
"name": "Blackbutt Facility Assurance Pty Ltd",
"short_name": "Blackbutt Facility Assurance",
"abn": "11 222 333 444",
"address": "Level 2, 60 Denham Street, Townsville QLD 4810",
"email": "reports@blackbutt.example.com",
"website": "blackbutt.example.com"
},
"site": {
"name": "Riverbend Community Aquatic Centre",
"address": "18 Mangrove Parade\nRiverbend QLD 4815",
"contact": "Priya Venkataraman, Centre Manager"
},
"inspection": {
"reference": "INS-2026-0915-04",
"type": "Quarterly facility safety inspection",
"date": "2026-09-15",
"start_time": "2026-09-15T07:30:00+10:00",
"end_time": "2026-09-15T11:10:00+10:00",
"timezone": "Australia/Brisbane",
"inspector": "Callum Ashworth",
"inspector_role": "Senior Facility Inspector",
"accreditation": "QFA-00417",
"weather": "Fine, 27 °C",
"next_inspection_months": 3,
"locale": "en-AU"
},
"checklist": [
{ "id": "CR-01", "area": "Change rooms", "item": "Floors dry and clean, non-slip matting in place", "status": "pass", "note": null, "photo": null },
{ "id": "CR-02", "area": "Change rooms", "item": "Hot water at outlets at or below 50 °C", "status": "pass", "note": "Measured 47 °C at basin 3", "photo": null },
{ "id": "CR-03", "area": "Change rooms", "item": "Baby-change tables secure and clean", "status": "fail", "note": "Hinge bracket loose on the east wall unit", "photo": "P-01" },
{ "id": "CR-04", "area": "Change rooms", "item": "Accessible shower grab rails secure", "status": "pass", "note": null, "photo": null },
{ "id": "CS-01", "area": "Chemical store", "item": "Safety data sheets current and accessible", "status": "pass", "note": null, "photo": null },
{ "id": "CS-02", "area": "Chemical store", "item": "Chlorine and acid stored apart, each on a spill tray", "status": "fail", "note": "Acid drum stored within 1 m of the chlorine pallet", "photo": "P-02" },
{ "id": "CS-03", "area": "Chemical store", "item": "Eyewash station flushed and weekly check signed", "status": "pass", "note": "Last signed 14 September", "photo": null },
{ "id": "CS-04", "area": "Chemical store", "item": "Exhaust ventilation operating", "status": "pass", "note": null, "photo": null },
{ "id": "EX-01", "area": "Emergency exits", "item": "Exit signs illuminated", "status": "fail", "note": "Sign above the north exit not lit when tested", "photo": "P-03" },
{ "id": "EX-02", "area": "Emergency exits", "item": "Exit paths clear of obstructions", "status": "pass", "note": null, "photo": null },
{ "id": "EX-03", "area": "Emergency exits", "item": "Emergency lighting 90-minute discharge test logged", "status": "na", "note": "Due at the next six-monthly service", "photo": null },
{ "id": "PR-01", "area": "Plant room", "item": "Pump and motor guards fitted", "status": "pass", "note": null, "photo": null },
{ "id": "PR-02", "area": "Plant room", "item": "Balance tank access hatch locked", "status": "pass", "note": null, "photo": null },
{ "id": "PR-03", "area": "Plant room", "item": "Dosing system alarms tested", "status": "pass", "note": "Low-chlorine alarm triggered correctly", "photo": null },
{ "id": "PC-01", "area": "Pool concourse", "item": "Depth markings visible at all entry points", "status": "pass", "note": null, "photo": null },
{ "id": "PC-02", "area": "Pool concourse", "item": "Rescue equipment in place and complete", "status": "pass", "note": null, "photo": null },
{ "id": "PC-03", "area": "Pool concourse", "item": "Shade sail fixings secure", "status": "na", "note": "Sails removed for replacement; reinstallation booked for 22 September", "photo": null },
{ "id": "PC-04", "area": "Pool concourse", "item": "First aid kit contents in date", "status": "fail", "note": "Two burn dressings expired in August 2026", "photo": "P-04" }
],
"findings": [
{
"id": "F-01",
"severity": "high",
"title": "Acid and chlorine stored too close together",
"checklist_ref": "CS-02",
"action": "Move the acid drums to the segregated bay and check both spill trays for residue.",
"owner": "Centre Manager",
"due_in_days": 1
},
{
"id": "F-02",
"severity": "high",
"title": "North exit sign not illuminated",
"checklist_ref": "EX-01",
"action": "Replace the lamp or battery pack, retest the sign and record the repair in the maintenance log.",
"owner": "Maintenance contractor",
"due_in_days": 3
},
{
"id": "F-03",
"severity": "medium",
"title": "Loose bracket on a baby-change table",
"checklist_ref": "CR-03",
"action": "Take the unit out of service until the bracket is re-fixed and load-tested.",
"owner": "Maintenance contractor",
"due_in_days": 7
},
{
"id": "F-04",
"severity": "low",
"title": "Expired first aid consumables",
"checklist_ref": "PC-04",
"action": "Replace the expired dressings and add expiry dates to the monthly first aid check.",
"owner": "Duty Supervisor",
"due_in_days": 14
}
],
"photos": [
{ "ref": "P-01", "checklist_ref": "CR-03", "caption": "East wall baby-change table, loose hinge bracket", "file": "IMG_4471.jpg" },
{ "ref": "P-02", "checklist_ref": "CS-02", "caption": "Acid drum beside the chlorine pallet", "file": "IMG_4478.jpg" },
{ "ref": "P-03", "checklist_ref": "EX-01", "caption": "North exit sign during the illumination test", "file": "IMG_4483.jpg" },
{ "ref": "P-04", "checklist_ref": "PC-04", "caption": "First aid kit with expired burn dressings", "file": "IMG_4490.jpg" }
],
"summary": "The centre is generally **well maintained** and staff were helpful throughout the inspection. Plant room controls, rescue equipment and change room hygiene were all in good order.\n\nTwo high-severity findings need attention **within three days**: chemical storage separation and the north exit sign. The remaining items are minor and can be closed through routine maintenance.",
"sign_off": {
"declaration": "I inspected the areas listed in this report on the date shown. The findings describe the conditions observed at the time of the inspection and are not a guarantee of ongoing compliance.",
"site_representative": "Priya Venkataraman",
"site_representative_role": "Centre Manager",
"distribution": ["Centre Manager", "Council Facilities Coordinator", "Workplace Health and Safety Committee"]
}
}Source
The body markup with Jinja, the stylesheet placed in <head> and the header and footer settings.
{#- Site inspection report. Checklist items are grouped by area with group_by; status counts, the pass
rate and the overall result are derived from the checklist and findings. Photos are referenced
by placeholder boxes (no external images), and page_break() starts the sign-off page. -#}
{%- set locale = inspection.locale | default("en-AU") -%}
{%- set tz = inspection.timezone -%}
{%- set passed = checklist | selectattr("status", "equalto", "pass") | list | length -%}
{%- set failed = checklist | selectattr("status", "equalto", "fail") | list | length -%}
{%- set not_applicable = checklist | selectattr("status", "equalto", "na") | list | length -%}
{%- set assessed = passed + failed -%}
{%- set high_findings = findings | selectattr("severity", "equalto", "high") | list | length -%}
{%- set next_due = inspection.date | date_add(months=inspection.next_inspection_months) -%}
{%- if high_findings > 0 -%}
{%- set result = "Action required" -%}{%- set result_class = "result-action" -%}
{%- elif failed > 0 -%}
{%- set result = "Minor issues" -%}{%- set result_class = "result-minor" -%}
{%- else -%}
{%- set result = "Satisfactory" -%}{%- set result_class = "result-ok" -%}
{%- endif -%}
{%- macro status_badge(status) -%}
{%- set labels = {"pass": "Pass", "fail": "Fail", "na": "N/A"} -%}
<span class="badge status-{{ status }}">{{ labels[status] }}</span>
{%- endmacro -%}
{%- macro severity_badge(severity) -%}
<span class="badge severity-{{ severity }}">{{ severity | capitalize }}</span>
{%- endmacro -%}
{%- macro signature_box(title, name, role) -%}
<div class="sig-box">
<p class="label">{{ title }}</p>
<div class="sig-area"></div>
<p class="sig-name">{{ name }}</p>
<p class="sig-role">{{ role }}</p>
<div class="sig-date"><span>Date</span></div>
</div>
{%- endmacro -%}
<header class="cover">
<div class="cover-top">
<div class="brand">
<svg class="mark" viewBox="0 0 40 40" aria-hidden="true">
<path d="M20 3l15 6v10c0 9.5-6.4 16-15 18-8.6-2-15-8.5-15-18V9z" fill="#f2a900"/>
<path d="M13 20.5l5 5 9.5-10" fill="none" stroke="#23272f" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<span>{{ inspector_company.short_name }}</span>
</div>
<span class="ref">{{ inspection.reference }}</span>
</div>
<p class="kicker">{{ inspection.type }}</p>
<h1>{{ site.name }}</h1>
</header>
<section class="details">
<div>
<p class="label">Site</p>
<p>{{ site.address | nl2br }}</p>
<p class="muted">Contact: {{ site.contact }}</p>
</div>
<dl>
<dt>Date</dt><dd>{{ inspection.date | format_date("full", locale) }}</dd>
<dt>Time on site</dt><dd>{{ inspection.start_time | format_date("%H:%M", locale, tz) }}–{{ inspection.end_time | format_date("%H:%M", locale, tz) }}</dd>
<dt>Inspector</dt><dd>{{ inspection.inspector }}, {{ inspection.inspector_role }}</dd>
<dt>Accreditation</dt><dd>{{ inspection.accreditation }}</dd>
<dt>Conditions</dt><dd>{{ inspection.weather }}</dd>
</dl>
</section>
<section class="outcome">
<div class="result {{ result_class }}">
<p class="label">Overall result</p>
<p class="result-text">{{ result }}</p>
<p class="result-note">{{ findings | length }} finding{{ "s" if findings | length != 1 else "" }}, {{ high_findings }} high severity</p>
</div>
<div class="tallies">
<div class="tally"><span class="tally-n">{{ checklist | length }}</span><span class="tally-k">Items checked</span></div>
<div class="tally t-pass"><span class="tally-n">{{ passed }}</span><span class="tally-k">Passed</span></div>
<div class="tally t-fail"><span class="tally-n">{{ failed }}</span><span class="tally-k">Failed</span></div>
<div class="tally t-na"><span class="tally-n">{{ not_applicable }}</span><span class="tally-k">Not applicable</span></div>
<div class="tally"><span class="tally-n">{{ (passed / assessed) | format_percent(locale) if assessed else "–" }}</span><span class="tally-k">Pass rate</span></div>
<div class="spread">
<span class="s-pass" style="width: {{ (passed / (checklist | length) * 100) | round(3) }}%"></span><span class="s-fail" style="width: {{ (failed / (checklist | length) * 100) | round(3) }}%"></span><span class="s-na" style="width: {{ (not_applicable / (checklist | length) * 100) | round(3) }}%"></span>
</div>
</div>
</section>
{% if summary %}
<section class="summary">
<h2 class="section-title">Summary</h2>
{{ summary | markdown }}
</section>
{% endif %}
<section class="findings">
<h2 class="section-title">Findings and actions</h2>
<table class="findings-table">
<thead>
<tr>
<th class="col-id" scope="col">Ref</th>
<th class="col-sev" scope="col">Severity</th>
<th scope="col">Finding and required action</th>
<th class="col-owner" scope="col">Owner</th>
<th class="col-due" scope="col">Due</th>
</tr>
</thead>
<tbody>
{% for finding in findings %}
<tr>
<td class="col-id">{{ finding.id }}</td>
<td class="col-sev">{{ severity_badge(finding.severity) }}</td>
<td>
<span class="finding-title">{{ finding.title }}</span>
<span class="finding-action">{{ finding.action }}</span>
<span class="finding-ref">Checklist item {{ finding.checklist_ref }}</span>
</td>
<td class="col-owner">{{ finding.owner }}</td>
<td class="col-due">{{ inspection.date | date_add(days=finding.due_in_days) | format_date("medium", locale) }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</section>
<section class="checklist">
<h2 class="section-title">Checklist by area</h2>
{% for group in checklist | group_by("area") %}
{%- set group_failed = group.list | selectattr("status", "equalto", "fail") | list | length -%}
<table class="check-table">
<colgroup><col class="c-id"><col class="c-item"><col class="c-status"><col class="c-note"></colgroup>
<thead>
<tr class="area-row">
<th colspan="4" scope="colgroup">
<span class="area-name">{{ group.grouper }}</span>
<span class="area-count">{{ group.list | length }} items{% if group_failed %} · {{ group_failed }} failed{% else %} · all passed or not applicable{% endif %}</span>
</th>
</tr>
<tr class="col-row">
<th scope="col">Ref</th>
<th scope="col">Item</th>
<th scope="col">Status</th>
<th scope="col">Notes</th>
</tr>
</thead>
<tbody>
{% for check in group.list %}
<tr class="{{ 'row-fail' if check.status == 'fail' else '' }}">
<td class="col-id">{{ check.id }}</td>
<td class="col-item">{{ check.item }}</td>
<td class="col-status">{{ status_badge(check.status) }}</td>
<td class="col-note">
{% if check.note %}{{ check.note }}{% else %}<span class="muted">—</span>{% endif %}
{% if check.photo %}<span class="photo-ref">Photo {{ check.photo }}</span>{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endfor %}
</section>
{% if photos %}
<section class="photos">
<h2 class="section-title">Photo references</h2>
<div class="photo-grid">
{% for photo in photos %}
<figure class="photo" aria-labelledby="photo-file-{{ loop.index }} photo-caption-{{ loop.index }}">
<div class="photo-box">
<svg viewBox="0 0 48 36" aria-hidden="true">
<path d="M6 10h8l3-5h14l3 5h8a2 2 0 0 1 2 2v19a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V12a2 2 0 0 1 2-2z" fill="none" stroke="#9aa1ab" stroke-width="2" stroke-linejoin="round"/>
<circle cx="24" cy="21" r="7" fill="none" stroke="#9aa1ab" stroke-width="2"/>
</svg>
<span class="photo-file" id="photo-file-{{ loop.index }}">{{ photo.file }}</span>
</div>
<figcaption id="photo-caption-{{ loop.index }}"><strong>{{ photo.ref }}</strong> · {{ photo.caption }} <span class="muted">({{ photo.checklist_ref }})</span></figcaption>
</figure>
{% endfor %}
</div>
</section>
{% endif %}
{{ page_break() }}
<section class="sign-off">
<h2 class="section-title">Sign-off</h2>
<div class="sign-summary">
<div class="result {{ result_class }}">
<p class="label">Overall result</p>
<p class="result-text">{{ result }}</p>
</div>
<dl>
<dt>Report reference</dt><dd>{{ inspection.reference }}</dd>
<dt>Site</dt><dd>{{ site.name }}</dd>
<dt>Inspection date</dt><dd>{{ inspection.date | format_date("long", locale) }}</dd>
<dt>Open actions</dt><dd>{{ findings | length }} ({{ high_findings }} high severity)</dd>
<dt>Next inspection due</dt><dd>{{ next_due | format_date("long", locale) }}</dd>
</dl>
</div>
<p class="declaration">{{ sign_off.declaration }}</p>
<div class="signatures">
{{ signature_box("Inspector", inspection.inspector, inspection.inspector_role ~ ", " ~ inspector_company.name) }}
{{ signature_box("Received on behalf of the site", sign_off.site_representative, sign_off.site_representative_role ~ ", " ~ site.name) }}
</div>
<div class="distribution">
<p class="label">Distribution</p>
<ol>
{% for recipient in sign_off.distribution %}<li>{{ recipient }}</li>{% endfor %}
</ol>
</div>
<p class="issuer">
{{ inspector_company.name }} · ABN {{ inspector_company.abn }} · {{ inspector_company.address }} · {{ inspector_company.email }}
</p>
</section><title>{{ inspection.type }} {{ inspection.reference }} – {{ site.name }}</title>
<style>
:root {
--ink: #23272f;
--muted: #677080;
--rule: #e1e4e8;
--panel: #f5f6f7;
--amber: #f2a900;
--amber-soft: #fff4d6;
--pass: #1e7b4f;
--pass-bg: #e2f2e9;
--fail: #c23b2b;
--fail-bg: #fbe6e3;
--na: #6f7782;
--na-bg: #eceef1;
--medium: #b45f06;
--medium-bg: #fdeed9;
--low: #33609f;
--low-bg: #e4ecf7;
}
* { box-sizing: border-box; }
html { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
body {
margin: 0;
color: var(--ink);
font-family: "Roboto", "Liberation Sans", Arial, sans-serif;
font-size: 8.8pt;
line-height: 1.42;
}
p { margin: 0; }
.muted { color: var(--muted); }
.label { margin-bottom: 1mm; font-size: 7pt; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); }
.section-title {
display: flex; align-items: center; gap: 2.5mm; margin: 8mm 0 3mm; font-size: 11pt; font-weight: 700;
break-after: avoid; page-break-after: avoid;
}
.section-title::before { content: ""; width: 1.4mm; height: 4.6mm; background: var(--amber); }
/* Cover band */
.cover { padding: 5mm 6mm 6mm; border-radius: 2mm; background: var(--ink); color: #ffffff; }
.cover-top { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6mm; }
.brand { display: flex; align-items: center; gap: 2.5mm; font-weight: 700; font-size: 9.5pt; }
.mark { width: 8mm; height: 8mm; }
.ref { padding: 0.8mm 2.5mm; border: 0.3mm solid #5b616c; border-radius: 1mm; font-family: "DejaVu Sans Mono", "Liberation Mono", monospace; font-size: 8pt; }
.kicker { font-size: 8pt; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--amber); }
.cover h1 { margin: 1mm 0 0; font-size: 22pt; font-weight: 700; line-height: 1.12; }
/* Details */
.details { display: grid; grid-template-columns: 1fr 1.35fr; gap: 8mm; margin-top: 6mm; padding-bottom: 5mm; border-bottom: 0.3mm solid var(--rule); }
.details p + p { margin-top: 1mm; }
.details dl { display: grid; grid-template-columns: 26mm 1fr; gap: 1mm 3mm; margin: 0; }
.details dt { color: var(--muted); }
.details dd { margin: 0; font-weight: 500; }
/* Outcome */
.outcome { display: grid; grid-template-columns: 52mm 1fr; gap: 5mm; margin-top: 6mm; break-inside: avoid; page-break-inside: avoid; }
.result { padding: 4mm 5mm; border-radius: 2mm; }
.result .label { color: inherit; opacity: 0.8; }
.result-text { font-size: 15pt; font-weight: 700; line-height: 1.2; }
.result-note { margin-top: 1mm; font-size: 8pt; }
.result-action { background: var(--fail-bg); color: var(--fail); border-left: 1.5mm solid var(--fail); }
.result-minor { background: var(--amber-soft); color: #8a5d00; border-left: 1.5mm solid var(--amber); }
.result-ok { background: var(--pass-bg); color: var(--pass); border-left: 1.5mm solid var(--pass); }
.tallies { display: grid; grid-template-columns: repeat(5, 1fr); gap: 2mm; align-content: start; }
.tally { padding: 2.5mm 3mm; border-radius: 1.5mm; background: var(--panel); }
.tally-n { display: block; font-size: 15pt; font-weight: 700; line-height: 1.15; font-variant-numeric: tabular-nums; }
.tally-k { display: block; font-size: 7pt; color: var(--muted); }
.t-pass .tally-n { color: var(--pass); }
.t-fail .tally-n { color: var(--fail); }
.t-na .tally-n { color: var(--na); }
.spread { grid-column: 1 / -1; display: flex; height: 2.4mm; margin-top: 1mm; border-radius: 1.2mm; overflow: hidden; background: var(--panel); }
.s-pass { background: var(--pass); }
.s-fail { background: var(--fail); }
.s-na { background: #b7bcc4; }
.summary p { margin: 0 0 2mm; max-width: 170mm; }
/* Tables */
table { width: 100%; border-collapse: collapse; }
thead { display: table-header-group; }
th {
padding: 1.8mm 2mm; border-bottom: 0.4mm solid var(--ink); text-align: left;
font-size: 7pt; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted);
}
td { padding: 2.2mm 2mm; border-bottom: 0.2mm solid var(--rule); vertical-align: top; }
tbody tr { break-inside: avoid; page-break-inside: avoid; }
.col-id { width: 14mm; font-family: "DejaVu Sans Mono", "Liberation Mono", monospace; font-size: 7.5pt; white-space: nowrap; }
.badge {
display: inline-block; min-width: 12mm; padding: 0.4mm 1.8mm; border-radius: 1mm; text-align: center;
font-size: 7pt; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; white-space: nowrap;
}
.status-pass { background: var(--pass-bg); color: var(--pass); }
.status-fail { background: var(--fail); color: #ffffff; }
.status-na { background: var(--na-bg); color: var(--na); }
.severity-high { background: var(--fail); color: #ffffff; }
.severity-medium { background: var(--medium-bg); color: var(--medium); }
.severity-low { background: var(--low-bg); color: var(--low); }
.findings-table .col-sev { width: 19mm; }
.findings-table .col-owner { width: 30mm; }
.findings-table .col-due { width: 22mm; white-space: nowrap; font-weight: 700; }
.finding-title { display: block; font-weight: 700; }
.finding-action { display: block; margin-top: 0.4mm; }
.finding-ref { display: block; margin-top: 0.6mm; font-size: 7.5pt; color: var(--muted); }
.check-table { table-layout: fixed; margin-bottom: 5mm; }
.check-table col.c-id { width: 16mm; }
.check-table col.c-status { width: 18mm; }
.check-table col.c-note { width: 62mm; }
.check-table .area-row th {
padding: 2.2mm 2mm; border-bottom: none; background: var(--panel);
font-size: 9pt; letter-spacing: 0; text-transform: none; color: var(--ink);
}
.check-table .col-row th { padding: 1.2mm 2mm; font-size: 6.5pt; }
.area-name { font-weight: 700; }
.area-count { margin-left: 2mm; font-size: 7.5pt; font-weight: 400; color: var(--muted); }
.check-table .row-fail td { background: #fff7f5; }
.col-note { font-size: 8pt; }
.photo-ref {
display: inline-block; margin-left: 1mm; padding: 0 1.4mm; border: 0.25mm solid var(--muted); border-radius: 0.8mm;
font-size: 6.8pt; color: var(--muted); white-space: nowrap;
}
/* Photos */
.photos { break-inside: avoid; page-break-inside: avoid; }
.photo-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 5mm; }
.photo { margin: 0; break-inside: avoid; page-break-inside: avoid; }
.photo-box {
display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1.5mm; height: 42mm;
border: 0.4mm dashed #b7bcc4; border-radius: 1.5mm; background: repeating-linear-gradient(135deg, #fafafa 0 3mm, #f3f4f5 3mm 6mm);
}
.photo-box svg { width: 12mm; height: 9mm; }
.photo-file { font-family: "DejaVu Sans Mono", "Liberation Mono", monospace; font-size: 7pt; color: var(--muted); }
.photo figcaption { margin-top: 1.5mm; font-size: 8pt; }
/* Sign-off */
.sign-summary { display: grid; grid-template-columns: 60mm 1fr; gap: 6mm; align-items: stretch; }
.sign-summary dl { display: grid; grid-template-columns: 36mm 1fr; gap: 1.5mm 3mm; margin: 0; padding: 4mm 5mm; border-radius: 2mm; background: var(--panel); }
.sign-summary dt { color: var(--muted); }
.sign-summary dd { margin: 0; font-weight: 700; }
.declaration { margin: 8mm 0; padding-left: 4mm; border-left: 1mm solid var(--amber); font-size: 9.5pt; max-width: 165mm; }
.signatures { display: grid; grid-template-columns: 1fr 1fr; gap: 10mm; break-inside: avoid; page-break-inside: avoid; }
.sig-box { padding: 4mm 5mm; border: 0.3mm solid var(--rule); border-radius: 2mm; }
.sig-area { height: 20mm; border-bottom: 0.35mm solid var(--ink); }
.sig-name { margin-top: 2mm; font-weight: 700; }
.sig-role { font-size: 8pt; color: var(--muted); }
.sig-date { margin-top: 6mm; height: 7mm; border-bottom: 0.3mm solid #b7bcc4; position: relative; }
.sig-date span { position: absolute; left: 0; bottom: 1mm; font-size: 7pt; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }
.distribution { margin-top: 8mm; }
.distribution ol { margin: 1mm 0 0; padding-left: 5mm; }
.issuer { margin-top: 10mm; padding-top: 3mm; border-top: 0.3mm solid var(--rule); font-size: 7.5pt; color: var(--muted); }
</style>Render it with the API
After adding the template to your workspace, render it by ID and pass your data. Arrays are shortened here.
curl -X POST https://api-eu.dynamicdocumentapi.com/v1/renders \
-H "Authorization: Bearer $DYNAMIC_DOCUMENT_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"input": {
"type": "template",
"template_id": "tpl_01J9ZK3M7Q8V5W2X4Y6Z8A0B1C"
},
"data": {
"inspector_company": {
"name": "Blackbutt Facility Assurance Pty Ltd",
"short_name": "Blackbutt Facility Assurance",
"abn": "11 222 333 444",
"address": "Level 2, 60 Denham Street, Townsville QLD 4810",
"email": "reports@blackbutt.example.com",
"website": "blackbutt.example.com"
},
"site": {
"name": "Riverbend Community Aquatic Centre",
"address": "18 Mangrove Parade\nRiverbend QLD 4815",
"contact": "Priya Venkataraman, Centre Manager"
},
"inspection": {
"reference": "INS-2026-0915-04",
"type": "Quarterly facility safety inspection",
"date": "2026-09-15",
"start_time": "2026-09-15T07:30:00+10:00",
"end_time": "2026-09-15T11:10:00+10:00",
"timezone": "Australia/Brisbane",
"inspector": "Callum Ashworth",
"inspector_role": "Senior Facility Inspector",
"accreditation": "QFA-00417",
"weather": "Fine, 27 °C",
"next_inspection_months": 3,
"locale": "en-AU"
},
"checklist": [
{
"id": "CR-01",
"area": "Change rooms",
"item": "Floors dry and clean, non-slip matting in place",
"status": "pass",
"note": null,
"photo": null
},
{
"id": "CR-02",
"area": "Change rooms",
"item": "Hot water at outlets at or below 50 °C",
"status": "pass",
"note": "Measured 47 °C at basin 3",
"photo": null
}
],
"findings": [
{
"id": "F-01",
"severity": "high",
"title": "Acid and chlorine stored too close together",
"checklist_ref": "CS-02",
"action": "Move the acid drums to the segregated bay and check both spill trays for residue.",
"owner": "Centre Manager",
"due_in_days": 1
},
{
"id": "F-02",
"severity": "high",
"title": "North exit sign not illuminated",
"checklist_ref": "EX-01",
"action": "Replace the lamp or battery pack, retest the sign and record the repair in the maintenance log.",
"owner": "Maintenance contractor",
"due_in_days": 3
}
],
"photos": [
{
"ref": "P-01",
"checklist_ref": "CR-03",
"caption": "East wall baby-change table, loose hinge bracket",
"file": "IMG_4471.jpg"
},
{
"ref": "P-02",
"checklist_ref": "CS-02",
"caption": "Acid drum beside the chlorine pallet",
"file": "IMG_4478.jpg"
}
],
"summary": "The centre is generally **well maintained** and staff were helpful throughout the inspection. Plant room controls, rescue equipment and change room hygiene were all in good order.\n\nTwo high-severity findings need attention **within three days**: chemical storage separation and the north exit sign. The remaining items are minor and can be closed through routine maintenance.",
"sign_off": {
"declaration": "I inspected the areas listed in this report on the date shown. The findings describe the conditions observed at the time of the inspection and are not a guarantee of ongoing compliance.",
"site_representative": "Priya Venkataraman",
"site_representative_role": "Centre Manager",
"distribution": [
"Centre Manager",
"Council Facilities Coordinator"
]
}
},
"output": {
"format": "pdf",
"filename": "report-site-inspection.pdf"
}
}'const response = await fetch("https://api-eu.dynamicdocumentapi.com/v1/renders", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.DYNAMIC_DOCUMENT_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
"input": {
"type": "template",
"template_id": "tpl_01J9ZK3M7Q8V5W2X4Y6Z8A0B1C"
},
"data": {
"inspector_company": {
"name": "Blackbutt Facility Assurance Pty Ltd",
"short_name": "Blackbutt Facility Assurance",
"abn": "11 222 333 444",
"address": "Level 2, 60 Denham Street, Townsville QLD 4810",
"email": "reports@blackbutt.example.com",
"website": "blackbutt.example.com"
},
"site": {
"name": "Riverbend Community Aquatic Centre",
"address": "18 Mangrove Parade\nRiverbend QLD 4815",
"contact": "Priya Venkataraman, Centre Manager"
},
"inspection": {
"reference": "INS-2026-0915-04",
"type": "Quarterly facility safety inspection",
"date": "2026-09-15",
"start_time": "2026-09-15T07:30:00+10:00",
"end_time": "2026-09-15T11:10:00+10:00",
"timezone": "Australia/Brisbane",
"inspector": "Callum Ashworth",
"inspector_role": "Senior Facility Inspector",
"accreditation": "QFA-00417",
"weather": "Fine, 27 °C",
"next_inspection_months": 3,
"locale": "en-AU"
},
"checklist": [
{
"id": "CR-01",
"area": "Change rooms",
"item": "Floors dry and clean, non-slip matting in place",
"status": "pass",
"note": null,
"photo": null
},
{
"id": "CR-02",
"area": "Change rooms",
"item": "Hot water at outlets at or below 50 °C",
"status": "pass",
"note": "Measured 47 °C at basin 3",
"photo": null
}
],
"findings": [
{
"id": "F-01",
"severity": "high",
"title": "Acid and chlorine stored too close together",
"checklist_ref": "CS-02",
"action": "Move the acid drums to the segregated bay and check both spill trays for residue.",
"owner": "Centre Manager",
"due_in_days": 1
},
{
"id": "F-02",
"severity": "high",
"title": "North exit sign not illuminated",
"checklist_ref": "EX-01",
"action": "Replace the lamp or battery pack, retest the sign and record the repair in the maintenance log.",
"owner": "Maintenance contractor",
"due_in_days": 3
}
],
"photos": [
{
"ref": "P-01",
"checklist_ref": "CR-03",
"caption": "East wall baby-change table, loose hinge bracket",
"file": "IMG_4471.jpg"
},
{
"ref": "P-02",
"checklist_ref": "CS-02",
"caption": "Acid drum beside the chlorine pallet",
"file": "IMG_4478.jpg"
}
],
"summary": "The centre is generally **well maintained** and staff were helpful throughout the inspection. Plant room controls, rescue equipment and change room hygiene were all in good order.\n\nTwo high-severity findings need attention **within three days**: chemical storage separation and the north exit sign. The remaining items are minor and can be closed through routine maintenance.",
"sign_off": {
"declaration": "I inspected the areas listed in this report on the date shown. The findings describe the conditions observed at the time of the inspection and are not a guarantee of ongoing compliance.",
"site_representative": "Priya Venkataraman",
"site_representative_role": "Centre Manager",
"distribution": [
"Centre Manager",
"Council Facilities Coordinator"
]
}
},
"output": {
"format": "pdf",
"filename": "report-site-inspection.pdf"
}
}),
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const result = await response.json();
console.log(result);import os
import uuid
import requests
response = requests.post(
"https://api-eu.dynamicdocumentapi.com/v1/renders",
headers={
"Authorization": f"Bearer {os.environ['DYNAMIC_DOCUMENT_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"input": {
"type": "template",
"template_id": "tpl_01J9ZK3M7Q8V5W2X4Y6Z8A0B1C",
},
"data": {
"inspector_company": {
"name": "Blackbutt Facility Assurance Pty Ltd",
"short_name": "Blackbutt Facility Assurance",
"abn": "11 222 333 444",
"address": "Level 2, 60 Denham Street, Townsville QLD 4810",
"email": "reports@blackbutt.example.com",
"website": "blackbutt.example.com",
},
"site": {
"name": "Riverbend Community Aquatic Centre",
"address": "18 Mangrove Parade\nRiverbend QLD 4815",
"contact": "Priya Venkataraman, Centre Manager",
},
"inspection": {
"reference": "INS-2026-0915-04",
"type": "Quarterly facility safety inspection",
"date": "2026-09-15",
"start_time": "2026-09-15T07:30:00+10:00",
"end_time": "2026-09-15T11:10:00+10:00",
"timezone": "Australia/Brisbane",
"inspector": "Callum Ashworth",
"inspector_role": "Senior Facility Inspector",
"accreditation": "QFA-00417",
"weather": "Fine, 27 °C",
"next_inspection_months": 3,
"locale": "en-AU",
},
"checklist": [
{
"id": "CR-01",
"area": "Change rooms",
"item": "Floors dry and clean, non-slip matting in place",
"status": "pass",
"note": None,
"photo": None,
},
{
"id": "CR-02",
"area": "Change rooms",
"item": "Hot water at outlets at or below 50 °C",
"status": "pass",
"note": "Measured 47 °C at basin 3",
"photo": None,
},
],
"findings": [
{
"id": "F-01",
"severity": "high",
"title": "Acid and chlorine stored too close together",
"checklist_ref": "CS-02",
"action": "Move the acid drums to the segregated bay and check both spill trays for residue.",
"owner": "Centre Manager",
"due_in_days": 1,
},
{
"id": "F-02",
"severity": "high",
"title": "North exit sign not illuminated",
"checklist_ref": "EX-01",
"action": "Replace the lamp or battery pack, retest the sign and record the repair in the maintenance log.",
"owner": "Maintenance contractor",
"due_in_days": 3,
},
],
"photos": [
{
"ref": "P-01",
"checklist_ref": "CR-03",
"caption": "East wall baby-change table, loose hinge bracket",
"file": "IMG_4471.jpg",
},
{
"ref": "P-02",
"checklist_ref": "CS-02",
"caption": "Acid drum beside the chlorine pallet",
"file": "IMG_4478.jpg",
},
],
"summary": "The centre is generally **well maintained** and staff were helpful throughout the inspection. Plant room controls, rescue equipment and change room hygiene were all in good order.\n\nTwo high-severity findings need attention **within three days**: chemical storage separation and the north exit sign. The remaining items are minor and can be closed through routine maintenance.",
"sign_off": {
"declaration": "I inspected the areas listed in this report on the date shown. The findings describe the conditions observed at the time of the inspection and are not a guarantee of ongoing compliance.",
"site_representative": "Priya Venkataraman",
"site_representative_role": "Centre Manager",
"distribution": ["Centre Manager", "Council Facilities Coordinator"],
},
},
"output": {
"format": "pdf",
"filename": "report-site-inspection.pdf",
},
},
timeout=90,
)
response.raise_for_status()
print(response.json())More reports templates
- 210 × 297 mm
Meeting minutes
A4An A4 meeting record that is easy to edit visually: key facts, an attendee table, optional apologies, one section per agenda item with an optional highlighted decision, an action-item table and a next-meeting note.
- 210 × 297 mm
Monthly KPI report
A4A two-page A4 management report with KPI cards that show the change against last month, a 12-month revenue bar chart drawn with render_chart from a JSON array, the current month highlighted against a target line, revenue by channel, a top-products table and Markdown commentary, with page numbers.