210 × 148 mm
Delivery notes
Proof of delivery form
An A5 landscape proof-of-delivery form for courier stops: route and stop number, consignee and delivery window, a parcel list with a Code 128 barcode per parcel, condition tick boxes, recipient name, signature and time boxes, and driver notes.
Opens Dynamic Document API with this template preloaded in a free workspace.
Template language features
- Loops
- Conditionals
- Macros
- Filters
- Number formatting
- Date formatting
- Barcode
Filters such as format_currency and qrcode are described in the template language reference.
Variables
Derived from the sample data: 7 top-level fields, 27 paths in total. Send the same shape as data.
| Path | Type | Example |
|---|---|---|
| carrier | object | |
| carrier.name | string | "Brannock Couriers" |
| carrier.depot | string | "Galway depot" |
| carrier.support_email | string | "pod@brannock.example.com" |
| run | object | |
| run.route | string | "G-14" |
| run.stop_number | number | 7 |
| run.stops_total | number | 22 |
| run.vehicle | string | "Van 08" |
| run.driver | string | "Aoife Brennan-Kelleher" |
| run.window_start | date | "2026-09-17T10:00:00+01:00" |
| run.window_end | date | "2026-09-17T12:00:00+01:00" |
| run.timezone | string | "Europe/Dublin" |
| shipper | object | |
| shipper.name | string | "Cairnfield Kitchen Supply Ltd" |
| shipper.reference | string | "CKS-SO-30917" |
| consignee | object | |
| consignee.name | string | "Lough Arrow Bakehouse" |
| consignee.contact | string | "Niamh Costigan" |
| consignee.address | string | "Unit 4, Cloonfad Business Park ⏎ Dublin Road ⏎…" |
| delivery_instructions | string | "Use the rear loading door. Ring twice; if nobo…" |
| parcels | array<object> · 4 | |
| parcels[].tracking | string | "BRC0917G1400701" |
| parcels[].description | string | "Stainless mixing bowls, set of 5" |
| parcels[].weight_kg | number | 6.4 |
| parcels[].handling | string | "Fragile" |
| conditions | array<string> · 4 | "All parcels received" |
Sample data
Fictional records used for previews. Replace them with your own data when you call the API.
{
"carrier": {
"name": "Brannock Couriers",
"depot": "Galway depot",
"support_email": "pod@brannock.example.com"
},
"run": {
"route": "G-14",
"stop_number": 7,
"stops_total": 22,
"vehicle": "Van 08",
"driver": "Aoife Brennan-Kelleher",
"window_start": "2026-09-17T10:00:00+01:00",
"window_end": "2026-09-17T12:00:00+01:00",
"timezone": "Europe/Dublin"
},
"shipper": {
"name": "Cairnfield Kitchen Supply Ltd",
"reference": "CKS-SO-30917"
},
"consignee": {
"name": "Lough Arrow Bakehouse",
"contact": "Niamh Costigan",
"address": "Unit 4, Cloonfad Business Park\nDublin Road\nTuam, Co. Galway"
},
"delivery_instructions": "Use the rear loading door. Ring twice; if nobody answers, knock at the bakery window.",
"parcels": [
{ "tracking": "BRC0917G1400701", "description": "Stainless mixing bowls, set of 5", "weight_kg": 6.4, "handling": null },
{ "tracking": "BRC0917G1400702", "description": "Proving baskets, 12 pieces", "weight_kg": 3.1, "handling": null },
{ "tracking": "BRC0917G1400703", "description": "Digital kitchen scales, 2 units", "weight_kg": 4.8, "handling": "Fragile" },
{ "tracking": "BRC0917G1400704", "description": "Baking trays, 600 × 400 mm, 10 pieces", "weight_kg": 11.2, "handling": "Heavy" }
],
"conditions": [
"All parcels received",
"Packaging undamaged",
"Damage or shortage, see notes",
"Left in agreed safe place"
]
}Source
The body markup with Jinja, the stylesheet placed in <head>.
{#- Proof of delivery form (A5 landscape): stop details and parcel barcodes on the left, recipient sign-off on the right. -#}
{%- set locale = "en-IE" -%}
{%- set tz = run.timezone | default("Europe/Dublin") -%}
{%- set total_weight = parcels | sum_by("weight_kg") -%}
{%- macro digit_boxes(count) -%}
{%- for _ in range(count) %}<span class="digit"></span>{% endfor -%}
{%- endmacro %}
<article class="pod">
<header class="bar">
<div class="brand">
<svg class="logo" viewBox="0 0 32 32" aria-hidden="true">
<rect width="32" height="32" rx="7" fill="#a61e4d"/>
<path d="M7 12l9-5 9 5v9l-9 5-9-5z" fill="none" stroke="#ffffff" stroke-width="2" stroke-linejoin="round"/>
<path d="M7 12l9 5 9-5M16 17v9" fill="none" stroke="#ffffff" stroke-width="2" stroke-linejoin="round"/>
</svg>
<div>
<p class="brand-name">{{ carrier.name }}</p>
<p class="brand-meta">{{ carrier.depot }}</p>
</div>
</div>
<h1>Proof of delivery</h1>
<div class="stop">
<span class="stop-label">Route {{ run.route }} · Stop</span>
<span class="stop-number">{{ run.stop_number }}<small>/{{ run.stops_total }}</small></span>
</div>
</header>
<div class="columns">
<section class="left">
<div class="details">
<div class="consignee">
<p class="label">Deliver to</p>
<p class="strong">{{ consignee.name }}</p>
<p>{{ consignee.address | nl2br }}</p>
<p class="muted">Contact: {{ consignee.contact }}</p>
</div>
<dl class="facts">
<dt>Date</dt><dd>{{ run.window_start | format_date("%a %d %b %Y", locale, tz) }}</dd>
<dt>Window</dt><dd>{{ run.window_start | format_date("%H:%M", locale, tz) }}–{{ run.window_end | format_date("%H:%M", locale, tz) }}</dd>
<dt>Shipper</dt><dd>{{ shipper.name }}</dd>
<dt>Reference</dt><dd>{{ shipper.reference }}</dd>
<dt>Driver</dt><dd>{{ run.driver }} · {{ run.vehicle }}</dd>
</dl>
</div>
<div class="parcels">
<p class="label">Parcels <span class="count">{{ parcels | length }} parcels · {{ total_weight | format_number(locale, 1) }} kg</span></p>
<ol>
{%- for parcel in parcels %}
<li>
<span class="seq">{{ loop.index }}/{{ loop.length }}</span>
<span class="code">{{ parcel.tracking | barcode("code128", alt="Barcode " ~ parcel.tracking) }}</span>
<span class="parcel-text">
<span class="tracking">{{ parcel.tracking }}</span>
<span>{{ parcel.description }}</span>
<span class="weight">{{ parcel.weight_kg | format_number(locale, 1) }} kg{% if parcel.handling %} <b class="handling">{{ parcel.handling }}</b>{% endif %}</span>
</span>
</li>
{%- endfor %}
</ol>
</div>
</section>
<section class="right">
<div class="conditions">
<p class="label">Condition on arrival</p>
<ul>
{%- for condition in conditions %}
<li><span class="box"></span>{{ condition }}</li>
{%- endfor %}
</ul>
</div>
<div class="recipient">
<p class="label">Recipient</p>
<div class="field"><span>Name in capitals</span></div>
<div class="field signature"><span>Signature</span></div>
<div class="when">
<div class="time"><span class="t-label">Time</span>{{ digit_boxes(2) }}<b>:</b>{{ digit_boxes(2) }}</div>
<div class="field short"><span>Parcels received</span></div>
</div>
</div>
<div class="notes">
<p class="label">Driver notes</p>
<p class="instructions">{{ delivery_instructions }}</p>
<span class="rule"></span>
<span class="rule"></span>
</div>
</section>
</div>
<footer class="foot">Keep this copy with the delivery paperwork. Queries: {{ carrier.support_email }}, quoting route {{ run.route }}, stop {{ run.stop_number }}.</footer>
</article><title>Proof of delivery {{ shipper.reference }} – {{ consignee.name }}</title>
<style>
:root {
--ink: #1f1a1d;
--muted: #6b6168;
--rule: #e2dade;
--berry: #a61e4d;
--berry-soft: #fcecf2;
}
* { box-sizing: border-box; }
html { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
body {
margin: 0;
color: var(--ink);
font-family: "Noto Sans", "Liberation Sans", Arial, sans-serif;
font-size: 7.6pt;
line-height: 1.35;
}
p, h1, ol, ul, dl, dd { margin: 0; padding: 0; }
.strong { font-weight: 700; }
.muted { color: var(--muted); }
.label {
margin-bottom: 1.2mm;
font-size: 6.2pt;
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--berry);
}
.pod { display: flex; flex-direction: column; height: 131.5mm; overflow: hidden; }
/* Top bar */
.bar {
display: grid;
grid-template-columns: 1fr auto 1fr;
align-items: center;
padding-bottom: 2.5mm;
border-bottom: 0.6mm solid var(--berry);
}
.brand { display: flex; align-items: center; gap: 2.2mm; }
.logo { width: 8.5mm; height: 8.5mm; }
.brand-name { font-size: 9.5pt; font-weight: 700; line-height: 1.15; }
.brand-meta { font-size: 6.8pt; color: var(--muted); }
.bar h1 { font-size: 15pt; font-weight: 700; letter-spacing: -0.01em; text-align: center; }
.stop { display: flex; align-items: baseline; justify-content: flex-end; gap: 2mm; }
.stop-label { font-size: 6.8pt; color: var(--muted); }
.stop-number {
padding: 0.4mm 2.6mm;
border-radius: 1.4mm;
background: var(--ink);
color: #ffffff;
font-size: 14pt;
font-weight: 700;
line-height: 1.2;
}
.stop-number small { font-size: 8pt; font-weight: 400; color: #d9cfd4; }
.columns { flex: 1; display: grid; grid-template-columns: 1fr 74mm; gap: 6mm; padding-top: 3mm; min-height: 0; }
/* Left column */
.details { display: grid; grid-template-columns: 1fr 1.1fr; gap: 4mm; padding-bottom: 2.5mm; border-bottom: 0.25mm solid var(--rule); }
.consignee .strong { font-size: 8.6pt; }
.consignee .muted { margin-top: 0.8mm; }
.facts { display: grid; grid-template-columns: auto 1fr; gap: 0.5mm 2.5mm; align-content: start; }
.facts dt { color: var(--muted); }
.facts dd { font-weight: 600; }
.parcels { padding-top: 2.5mm; }
.count { margin-left: 1.5mm; font-weight: 400; letter-spacing: 0; text-transform: none; color: var(--muted); }
.parcels ol { list-style: none; }
.parcels li {
display: grid;
grid-template-columns: 7mm 42mm 1fr;
gap: 2.5mm;
align-items: center;
padding: 1.3mm 0;
border-bottom: 0.2mm solid var(--rule);
break-inside: avoid;
page-break-inside: avoid;
}
.seq { font-weight: 700; color: var(--muted); }
.code img, .code svg { display: block; width: 42mm; height: 9.5mm; }
.parcel-text span { display: block; }
.tracking { font-family: "Liberation Mono", "DejaVu Sans Mono", monospace; font-size: 7pt; font-weight: 700; }
.weight { color: var(--muted); }
.handling {
margin-left: 1mm;
padding: 0 1.4mm;
border-radius: 0.8mm;
background: var(--berry-soft);
color: var(--berry);
font-size: 6.2pt;
letter-spacing: 0.04em;
text-transform: uppercase;
}
/* Right column */
.right { display: flex; flex-direction: column; justify-content: space-between; padding-left: 5mm; border-left: 0.25mm dashed #c9bcc3; }
.conditions ul { list-style: none; }
.conditions li { display: flex; align-items: center; gap: 2mm; margin-bottom: 1.1mm; font-size: 7.8pt; }
.box { flex: none; display: inline-block; width: 3.6mm; height: 3.6mm; border: 0.35mm solid var(--ink); border-radius: 0.5mm; }
.recipient { padding: 2.4mm 3mm 3mm; border: 0.45mm solid var(--berry); border-radius: 1.5mm; }
.field { position: relative; height: 8mm; border-bottom: 0.3mm solid var(--ink); }
.field.signature { height: 15mm; margin-top: 1mm; }
.field span, .time .t-label { position: absolute; top: 0.2mm; left: 0; font-size: 5.8pt; letter-spacing: 0.05em; text-transform: uppercase; color: var(--muted); }
.when { display: grid; grid-template-columns: auto 1fr; gap: 4mm; align-items: end; margin-top: 1.5mm; }
.time { position: relative; display: flex; align-items: center; gap: 0.8mm; padding-top: 3.2mm; }
.time b { font-size: 10pt; }
.digit { display: inline-block; width: 4.6mm; height: 6mm; border: 0.3mm solid var(--ink); border-radius: 0.6mm; }
.field.short { height: 9.2mm; }
.notes .instructions { margin-bottom: 1mm; padding: 1.2mm 2mm; border-radius: 1mm; background: var(--berry-soft); font-size: 7pt; }
.rule { display: block; height: 5.5mm; border-bottom: 0.25mm dotted var(--muted); }
.foot { padding-top: 1.6mm; border-top: 0.25mm solid var(--rule); font-size: 6.4pt; 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": {
"carrier": {
"name": "Brannock Couriers",
"depot": "Galway depot",
"support_email": "pod@brannock.example.com"
},
"run": {
"route": "G-14",
"stop_number": 7,
"stops_total": 22,
"vehicle": "Van 08",
"driver": "Aoife Brennan-Kelleher",
"window_start": "2026-09-17T10:00:00+01:00",
"window_end": "2026-09-17T12:00:00+01:00",
"timezone": "Europe/Dublin"
},
"shipper": {
"name": "Cairnfield Kitchen Supply Ltd",
"reference": "CKS-SO-30917"
},
"consignee": {
"name": "Lough Arrow Bakehouse",
"contact": "Niamh Costigan",
"address": "Unit 4, Cloonfad Business Park\nDublin Road\nTuam, Co. Galway"
},
"delivery_instructions": "Use the rear loading door. Ring twice; if nobody answers, knock at the bakery window.",
"parcels": [
{
"tracking": "BRC0917G1400701",
"description": "Stainless mixing bowls, set of 5",
"weight_kg": 6.4,
"handling": null
},
{
"tracking": "BRC0917G1400702",
"description": "Proving baskets, 12 pieces",
"weight_kg": 3.1,
"handling": null
}
],
"conditions": [
"All parcels received",
"Packaging undamaged"
]
},
"output": {
"format": "pdf",
"filename": "delivery-note-proof-of-delivery.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": {
"carrier": {
"name": "Brannock Couriers",
"depot": "Galway depot",
"support_email": "pod@brannock.example.com"
},
"run": {
"route": "G-14",
"stop_number": 7,
"stops_total": 22,
"vehicle": "Van 08",
"driver": "Aoife Brennan-Kelleher",
"window_start": "2026-09-17T10:00:00+01:00",
"window_end": "2026-09-17T12:00:00+01:00",
"timezone": "Europe/Dublin"
},
"shipper": {
"name": "Cairnfield Kitchen Supply Ltd",
"reference": "CKS-SO-30917"
},
"consignee": {
"name": "Lough Arrow Bakehouse",
"contact": "Niamh Costigan",
"address": "Unit 4, Cloonfad Business Park\nDublin Road\nTuam, Co. Galway"
},
"delivery_instructions": "Use the rear loading door. Ring twice; if nobody answers, knock at the bakery window.",
"parcels": [
{
"tracking": "BRC0917G1400701",
"description": "Stainless mixing bowls, set of 5",
"weight_kg": 6.4,
"handling": null
},
{
"tracking": "BRC0917G1400702",
"description": "Proving baskets, 12 pieces",
"weight_kg": 3.1,
"handling": null
}
],
"conditions": [
"All parcels received",
"Packaging undamaged"
]
},
"output": {
"format": "pdf",
"filename": "delivery-note-proof-of-delivery.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": {
"carrier": {
"name": "Brannock Couriers",
"depot": "Galway depot",
"support_email": "pod@brannock.example.com",
},
"run": {
"route": "G-14",
"stop_number": 7,
"stops_total": 22,
"vehicle": "Van 08",
"driver": "Aoife Brennan-Kelleher",
"window_start": "2026-09-17T10:00:00+01:00",
"window_end": "2026-09-17T12:00:00+01:00",
"timezone": "Europe/Dublin",
},
"shipper": {
"name": "Cairnfield Kitchen Supply Ltd",
"reference": "CKS-SO-30917",
},
"consignee": {
"name": "Lough Arrow Bakehouse",
"contact": "Niamh Costigan",
"address": "Unit 4, Cloonfad Business Park\nDublin Road\nTuam, Co. Galway",
},
"delivery_instructions": "Use the rear loading door. Ring twice; if nobody answers, knock at the bakery window.",
"parcels": [
{
"tracking": "BRC0917G1400701",
"description": "Stainless mixing bowls, set of 5",
"weight_kg": 6.4,
"handling": None,
},
{
"tracking": "BRC0917G1400702",
"description": "Proving baskets, 12 pieces",
"weight_kg": 3.1,
"handling": None,
},
],
"conditions": ["All parcels received", "Packaging undamaged"],
},
"output": {
"format": "pdf",
"filename": "delivery-note-proof-of-delivery.pdf",
},
},
timeout=90,
)
response.raise_for_status()
print(response.json())