210 × 297 mm
HR & employment
Expense claim
An A4 employee expense claim: receipts in other currencies are converted at their exchange rate, mileage is paid per mile, reclaimable VAT is worked out per line, and the totals, the spend by category and the amount due after an advance follow, with a QR code to the receipt images and three sign-off boxes.
Opens Dynamic Document API with this template preloaded in a free workspace.
Template language features
- Loops
- Conditionals
- Macros
- Filters
- Currency formatting
- Date formatting
- Number formatting
- Grouping
- QR code
- Repeating table headers
- Header & footer
- Page numbers
- signature
Filters such as format_currency and qrcode are described in the template language reference.
Variables
Derived from the sample data: 5 top-level fields, 34 paths in total. Send the same shape as data.
| Path | Type | Example |
|---|---|---|
| company | object | |
| company.name | string | "Tidewater Analytics Ltd" |
| company.address | string | "4th Floor, Quayside House ⏎ 12 Wapping Lane ⏎ …" |
| company.email | string | "expenses@tidewater.example.com" |
| company.currency | string | "GBP" |
| employee | object | |
| employee.name | string | "Priya Raman" |
| employee.number | string | "TA-0219" |
| employee.department | string | "Client Services" |
| employee.cost_centre | string | "CS-200" |
| employee.bank_account_ending | string | "4821" |
| claim | object | |
| claim.number | string | "EXP-2026-0917" |
| claim.period_start | date | "2026-09-01" |
| claim.period_end | date | "2026-09-30" |
| claim.submitted_on | date | "2026-09-30" |
| claim.purpose | string | "Client workshops in Leeds and Amsterdam, and a…" |
| claim.advance | number | 150 |
| claim.mileage_rate | number | 0.45 |
| claim.receipts_url | string | "https://expenses.tidewater.example.com/claims/…" |
| claim.approver | string | "Martin Kowalski" |
| claim.approver_role | string | "Head of Client Services" |
| lines | array<object> · 15 | |
| lines[].date | date | "2026-09-02" |
| lines[].receipt? | string | "R01" |
| lines[].category | string | "Travel" |
| lines[].description | string | "Contactless fares, client meetings in the City" |
| lines[].project | string | "CLT-130" |
| lines[].currency | string | "GBP" |
| lines[].amount? | number | 14.7 |
| lines[].vat_rate | number | 0 |
| lines[].fx_rate? | number | 0.8612 |
| lines[].miles? | number | 64 |
| notes | string | "Foreign-currency receipts are converted at the…" |
Sample data
Fictional records used for previews. Replace them with your own data when you call the API.
{
"company": {
"name": "Tidewater Analytics Ltd",
"address": "4th Floor, Quayside House\n12 Wapping Lane\nLondon E1W 2XY",
"email": "expenses@tidewater.example.com",
"currency": "GBP"
},
"employee": {
"name": "Priya Raman",
"number": "TA-0219",
"department": "Client Services",
"cost_centre": "CS-200",
"bank_account_ending": "4821"
},
"claim": {
"number": "EXP-2026-0917",
"period_start": "2026-09-01",
"period_end": "2026-09-30",
"submitted_on": "2026-09-30",
"purpose": "Client workshops in Leeds and Amsterdam, and a site visit in Reading",
"advance": 150.0,
"mileage_rate": 0.45,
"receipts_url": "https://expenses.tidewater.example.com/claims/EXP-2026-0917/receipts",
"approver": "Martin Kowalski",
"approver_role": "Head of Client Services"
},
"lines": [
{
"date": "2026-09-02",
"receipt": "R01",
"category": "Travel",
"description": "Contactless fares, client meetings in the City",
"project": "CLT-130",
"currency": "GBP",
"amount": 14.7,
"vat_rate": 0
},
{
"date": "2026-09-07",
"receipt": "R02",
"category": "Travel",
"description": "Rail, London King's Cross to Leeds, return",
"project": "CLT-104",
"currency": "GBP",
"amount": 126.0,
"vat_rate": 0
},
{
"date": "2026-09-07",
"receipt": "R03",
"category": "Accommodation",
"description": "Hotel, Leeds, 1 night",
"project": "CLT-104",
"currency": "GBP",
"amount": 138.0,
"vat_rate": 20
},
{
"date": "2026-09-08",
"receipt": "R04",
"category": "Subsistence",
"description": "Working lunch on the workshop day, 3 people",
"project": "CLT-104",
"currency": "GBP",
"amount": 52.8,
"vat_rate": 20
},
{
"date": "2026-09-08",
"receipt": "R05",
"category": "Subsistence",
"description": "Breakfast at Leeds station",
"project": "CLT-104",
"currency": "GBP",
"amount": 9.6,
"vat_rate": 20
},
{
"date": "2026-09-14",
"receipt": "R06",
"category": "Travel",
"description": "Flight, London Heathrow to Amsterdam, return",
"project": "CLT-117",
"currency": "GBP",
"amount": 214.8,
"vat_rate": 0
},
{
"date": "2026-09-15",
"receipt": "R07",
"category": "Travel",
"description": "Taxi, Schiphol airport to client office",
"project": "CLT-117",
"currency": "EUR",
"amount": 38.5,
"fx_rate": 0.8612,
"vat_rate": 0
},
{
"date": "2026-09-15",
"receipt": "R08",
"category": "Accommodation",
"description": "Hotel, Amsterdam, 2 nights",
"project": "CLT-117",
"currency": "EUR",
"amount": 312.0,
"fx_rate": 0.8612,
"vat_rate": 0
},
{
"date": "2026-09-16",
"receipt": "R09",
"category": "Subsistence",
"description": "Dinner, Amsterdam",
"project": "CLT-117",
"currency": "EUR",
"amount": 42.8,
"fx_rate": 0.8612,
"vat_rate": 0
},
{
"date": "2026-09-16",
"receipt": "R10",
"category": "Travel",
"description": "Train, Amsterdam Centraal to Schiphol airport",
"project": "CLT-117",
"currency": "EUR",
"amount": 6.2,
"fx_rate": 0.8612,
"vat_rate": 0
},
{
"date": "2026-09-21",
"category": "Mileage",
"description": "Client visit, Reading and back, own car",
"project": "CLT-121",
"currency": "GBP",
"miles": 64,
"vat_rate": 0
},
{
"date": "2026-09-22",
"receipt": "R11",
"category": "Software",
"description": "Survey tool, one-month licence",
"project": "INT-002",
"currency": "GBP",
"amount": 24.0,
"vat_rate": 20
},
{
"date": "2026-09-23",
"receipt": "R12",
"category": "Office supplies",
"description": "Printing of workshop handouts",
"project": "CLT-117",
"currency": "GBP",
"amount": 18.6,
"vat_rate": 20
},
{
"date": "2026-09-24",
"receipt": "R13",
"category": "Training",
"description": "Online course on survey design, one module",
"project": "INT-002",
"currency": "GBP",
"amount": 45.0,
"vat_rate": 20
},
{
"date": "2026-09-28",
"receipt": "R14",
"category": "Phone",
"description": "Roaming charges during the Amsterdam trip",
"project": "CLT-117",
"currency": "GBP",
"amount": 12.0,
"vat_rate": 20
}
],
"notes": "Foreign-currency receipts are converted at the rate on the card statement. Mileage is paid at 45p per mile for business journeys in your own car. Please keep the original receipts until the claim has been paid."
}Source
The body markup with Jinja, the stylesheet placed in <head> and the header and footer settings.
{#- Employee expense claim. Each line is converted to the company currency (amount × fx_rate, or miles × the mileage
rate), rounded to the cent; reclaimable VAT is worked out from the converted amount and the line's vat_rate
(0 when no VAT can be reclaimed). Totals, the summary by category and the amount due after the advance all derive
from the lines. -#}
{%- set loc = "en-GB" -%}
{%- set cur = company.currency -%}
{%- set symbols = {"GBP": "£", "EUR": "€", "USD": "US$", "CHF": "CHF "} -%}
{%- set ns = namespace(rows=[], total=0.0, vat=0.0) -%}
{%- for line in lines -%}
{%- if line.miles -%}
{%- set amount = (line.miles * claim.mileage_rate) | round(2) -%}
{%- else -%}
{%- set amount = (line.amount * (line.fx_rate | default(1))) | round(2) -%}
{%- endif -%}
{%- set rate = line.vat_rate | default(0) -%}
{%- set vat = (amount * rate / (100 + rate)) | round(2) -%}
{%- set ns.rows = ns.rows + [{"category": line.category, "amount": amount, "vat": vat}] -%}
{%- set ns.total = ns.total + amount -%}
{%- set ns.vat = ns.vat + vat -%}
{%- endfor -%}
{%- set total = ns.total | round(2) -%}
{%- set vat_total = ns.vat | round(2) -%}
{%- set advance = claim.advance | default(0) -%}
{%- set due = (total - advance) | round(2) -%}
{%- set cns = namespace(max=0.0) -%}
{%- for group in ns.rows | groupby("category") -%}{%- set s = group.list | sum_by("amount") -%}{%- if s > cns.max -%}{%- set cns.max = s -%}{%- endif -%}{%- endfor -%}
{%- macro money(value) -%}{{ value | format_currency(cur, loc) }}{%- endmacro -%}
{%- macro day(value) -%}{{ value | format_date("%-d %b %Y", loc) }}{%- endmacro -%}
{%- macro short_day(value) -%}{{ value | format_date("%-d %b", loc) }}{%- endmacro -%}
<header class="top">
<div class="brand">
<svg viewBox="0 0 44 44" aria-hidden="true">
<rect width="44" height="44" rx="10" fill="#0f6e6e"/>
<path d="M8 27c4.5-4 9-4 13.5 0s9 4 14.5 0" fill="none" stroke="#ffffff" stroke-width="3" stroke-linecap="round"/>
<path d="M8 19c4.5-4 9-4 13.5 0s9 4 14.5 0" fill="none" stroke="#9fd8d3" stroke-width="3" stroke-linecap="round"/>
</svg>
<div>
<p class="brand-name">{{ company.name }}</p>
<p class="brand-address">{{ company.address | nl2br }}</p>
</div>
</div>
<div class="doc">
<h1>Expense claim</h1>
<p class="number">{{ claim.number }}</p>
</div>
</header>
<section class="info">
<div>
<p class="label">Claimant</p>
<dl>
<dt>Name</dt><dd>{{ employee.name }}</dd>
<dt>Employee no.</dt><dd>{{ employee.number }}</dd>
<dt>Department</dt><dd>{{ employee.department }}</dd>
<dt>Cost centre</dt><dd>{{ employee.cost_centre }}</dd>
</dl>
</div>
<div>
<p class="label">Claim</p>
<dl>
<dt>Period</dt><dd>{{ day(claim.period_start) }} – {{ day(claim.period_end) }}</dd>
<dt>Submitted</dt><dd>{{ day(claim.submitted_on) }}</dd>
<dt>Purpose</dt><dd>{{ claim.purpose }}</dd>
<dt>Approver</dt><dd>{{ claim.approver }}</dd>
</dl>
</div>
{% if claim.receipts_url %}
<div class="receipts">
{{ claim.receipts_url | qrcode(size=160, margin=0, ecc="M", alt="QR code linking to the receipt images") }}
Receipt images
</div>
{% endif %}
</section>
<section class="summary">
<div class="tile"><p class="label">Total claimed</p><p class="value">{{ money(total) }}</p></div>
<div class="tile"><p class="label">VAT reclaimable</p><p class="value">{{ money(vat_total) }}</p></div>
<div class="tile"><p class="label">Advance received</p><p class="value">{{ money(advance) }}</p></div>
<div class="tile due"><p class="label">{{ "Due to you" if due >= 0 else "To repay" }}</p><p class="value">{{ money(due | abs) }}</p></div>
</section>
<table class="lines">
<thead>
<tr>
<th class="date" scope="col">Date</th>
<th class="ref" scope="col">Ref.</th>
<th class="cat" scope="col">Category</th>
<th scope="col">Description</th>
<th class="num original" scope="col">Original</th>
<th class="num amount" scope="col">Amount</th>
<th class="num vat" scope="col">VAT</th>
</tr>
</thead>
<tbody>
{% for line in lines %}
{%- set row = ns.rows[loop.index0] %}
<tr>
<td class="date">{{ short_day(line.date) }}</td>
<td class="ref">{{ line.receipt | default("–") }}</td>
<td class="cat"><span class="chip">{{ line.category }}</span></td>
<td>{{ line.description }}{% if line.project %}<span class="project">Project {{ line.project }}</span>{% endif %}</td>
<td class="num original">
{%- if line.miles -%}{{ line.miles | format_number(loc, 0) }} mi × {{ money(claim.mileage_rate) }}
{%- elif line.currency and line.currency != cur -%}{{ symbols[line.currency] or (line.currency ~ " ") }}{{ line.amount | format_number(loc, 2) }} × {{ line.fx_rate | format_number(loc, 4) }}
{%- else -%}–{%- endif -%}
</td>
<td class="num amount">{{ money(row.amount) }}</td>
<td class="num vat">{{ money(row.vat) if row.vat else "–" }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<section class="bottom">
<div>
<p class="label">By category</p>
{% for group in ns.rows | groupby("category") %}
{%- set s = group.list | sum_by("amount") %}
<div class="cat-row">
<span>{{ group.grouper }}</span>
<span class="cat-bar"><span style="width: {{ (s / cns.max * 100) | round(1) }}%"></span></span>
<span class="num">{{ money(s) }}</span>
</div>
{% endfor %}
</div>
<table class="totals">
<tr><th scope="row">Expenses ({{ lines | length }} items)</th><td class="num">{{ money(total) }}</td></tr>
<tr><th scope="row" class="muted">of which reclaimable VAT</th><td class="num muted">{{ money(vat_total) }}</td></tr>
<tr class="grand"><th scope="row">Total claimed</th><td class="num">{{ money(total) }}</td></tr>
{% if advance %}<tr><th scope="row">Less advance received</th><td class="num">−{{ money(advance) }}</td></tr>{% endif %}
<tr class="due"><th scope="row">{{ "Due to you" if due >= 0 else "To repay" }}</th><td class="num">{{ money(due | abs) }}</td></tr>
</table>
</section>
{% if notes %}<p class="notes">{{ notes }}</p>{% endif %}
<section class="approvals">
<div class="approval">
<h2>Claimant</h2>
<p>I confirm these expenses were incurred on company business and have not been claimed before.</p>
<div class="sign"></div>
<div class="sign-meta"><span>{{ employee.name }}</span><span>Date</span></div>
</div>
<div class="approval">
<h2>Approved by</h2>
<p>{{ claim.approver_role }}: checked against the expenses policy and the project budgets.</p>
<div class="sign"></div>
<div class="sign-meta"><span>{{ claim.approver }}</span><span>Date</span></div>
</div>
<div class="approval">
<h2>Finance</h2>
<p>{% if due >= 0 %}Pay {{ money(due) }} to the account ending {{ employee.bank_account_ending }}.{% else %}Recover {{ money(due | abs) }} through payroll.{% endif %}</p>
<div class="sign"></div>
<div class="sign-meta"><span>Paid on</span><span>Initials</span></div>
</div>
</section><title>Expense claim {{ claim.number }} – {{ employee.name }}</title>
<style>
:root {
--ink: #17212b;
--muted: #5e6b78;
--rule: #dbe1e7;
--soft: #f2f5f8;
--teal: #0f6e6e;
--teal-soft: #e2f1f0;
--coral: #d0603c;
}
* { box-sizing: border-box; }
html { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
body {
margin: 0;
color: var(--ink);
font-family: "Inter", "Liberation Sans", Arial, sans-serif;
font-size: 8.6pt;
line-height: 1.42;
}
p, h1, h2 { margin: 0; }
.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.muted { color: var(--muted); }
.label { font-size: 6.8pt; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); margin-bottom: 1.2mm; }
/* Header */
.top { display: flex; justify-content: space-between; align-items: flex-start; gap: 8mm; }
.brand { display: flex; gap: 3mm; align-items: flex-start; }
.brand svg { width: 11mm; height: 11mm; flex: none; }
.brand-name { font-size: 11pt; font-weight: 700; }
.brand-address { margin-top: 0.6mm; font-size: 7.6pt; color: var(--muted); line-height: 1.4; }
.doc { text-align: right; }
.doc h1 { font-size: 22pt; font-weight: 700; letter-spacing: -0.02em; line-height: 1; }
.doc .number { margin-top: 1.6mm; font-size: 9.5pt; font-weight: 600; color: var(--teal); font-variant-numeric: tabular-nums; }
.info { display: grid; grid-template-columns: 1fr 1.25fr auto; gap: 7mm; margin: 6mm 0 5mm; padding: 4mm 0; border-top: 0.4mm solid var(--ink); border-bottom: 0.2mm solid var(--rule); }
.info dl { display: grid; grid-template-columns: auto 1fr; gap: 0.7mm 3.5mm; margin: 0; }
.info dt { color: var(--muted); }
.info dd { margin: 0; font-weight: 600; }
.receipts { width: 26mm; text-align: center; font-size: 6.8pt; color: var(--muted); line-height: 1.3; }
.receipts img { display: block; width: 20mm; height: 20mm; margin: 0 auto 1mm; }
/* Summary */
.summary { display: grid; grid-template-columns: repeat(4, 1fr); gap: 3mm; margin-bottom: 6mm; break-inside: avoid; page-break-inside: avoid; }
.tile { padding: 3mm 3.5mm; border-radius: 1.5mm; background: var(--soft); }
.tile .value { margin-top: 0.6mm; font-size: 14pt; font-weight: 700; letter-spacing: -0.01em; font-variant-numeric: tabular-nums; }
.tile.due { background: var(--teal); color: #ffffff; }
.tile.due .label { color: #cfe8e6; }
/* Lines */
table.lines { width: 100%; border-collapse: collapse; }
table.lines thead { display: table-header-group; }
table.lines th {
padding: 1.8mm 1.6mm; border-bottom: 0.35mm solid var(--ink); text-align: left; vertical-align: bottom;
font-size: 6.6pt; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted);
}
table.lines th.num { text-align: right; }
table.lines td { padding: 1.6mm 1.6mm; border-bottom: 0.2mm solid var(--rule); vertical-align: top; }
table.lines tr { break-inside: avoid; page-break-inside: avoid; }
.date { width: 13mm; white-space: nowrap; }
.ref { width: 10mm; font-family: "DejaVu Sans Mono", "Liberation Mono", monospace; font-size: 7.4pt; color: var(--muted); }
.cat { width: 25mm; }
.chip { display: inline-block; padding: 0.2mm 1.6mm; border-radius: 0.8mm; background: var(--teal-soft); color: var(--teal); font-size: 7pt; font-weight: 600; white-space: nowrap; }
.project { display: block; margin-top: 0.4mm; font-size: 7pt; color: var(--muted); }
.original { width: 30mm; font-size: 7.6pt; color: var(--muted); }
.amount { width: 20mm; font-weight: 600; }
.vat { width: 16mm; }
/* Bottom */
.bottom { display: grid; grid-template-columns: 1fr 78mm; gap: 9mm; margin-top: 6mm; break-inside: avoid; page-break-inside: avoid; }
.cat-row { display: grid; grid-template-columns: 30mm 1fr 19mm; gap: 2.5mm; align-items: center; padding: 1.1mm 0; }
.cat-bar { height: 2.2mm; border-radius: 1.1mm; background: #e6ebef; overflow: hidden; }
.cat-bar span { display: block; height: 100%; border-radius: 1.1mm; background: var(--teal); }
.totals { width: 100%; border-collapse: collapse; }
.totals td, .totals th { padding: 1.4mm 2mm; }
.totals th { font-weight: inherit; text-align: left; }
.totals .grand td, .totals .grand th { border-top: 0.4mm solid var(--ink); font-size: 10pt; font-weight: 700; }
.totals .due td, .totals .due th { background: var(--teal-soft); color: var(--teal); font-size: 10pt; font-weight: 700; }
.notes { margin-top: 5mm; padding: 3mm 4mm; border-left: 0.9mm solid var(--coral); background: #fbf1ed; font-size: 7.8pt; break-inside: avoid; page-break-inside: avoid; }
/* Approvals */
.approvals { display: grid; grid-template-columns: repeat(3, 1fr); gap: 5mm; margin-top: 7mm; break-inside: avoid; page-break-inside: avoid; }
.approval { padding: 3.5mm 4mm; border: 0.3mm solid var(--rule); border-radius: 1.5mm; }
.approval h2 { font-size: 7.2pt; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--teal); }
.approval p { margin-top: 1.2mm; font-size: 7.6pt; }
.sign { height: 11mm; border-bottom: 0.3mm solid var(--ink); }
.sign-meta { display: flex; justify-content: space-between; margin-top: 1mm; font-size: 7pt; 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": {
"company": {
"name": "Tidewater Analytics Ltd",
"address": "4th Floor, Quayside House\n12 Wapping Lane\nLondon E1W 2XY",
"email": "expenses@tidewater.example.com",
"currency": "GBP"
},
"employee": {
"name": "Priya Raman",
"number": "TA-0219",
"department": "Client Services",
"cost_centre": "CS-200",
"bank_account_ending": "4821"
},
"claim": {
"number": "EXP-2026-0917",
"period_start": "2026-09-01",
"period_end": "2026-09-30",
"submitted_on": "2026-09-30",
"purpose": "Client workshops in Leeds and Amsterdam, and a site visit in Reading",
"advance": 150,
"mileage_rate": 0.45,
"receipts_url": "https://expenses.tidewater.example.com/claims/EXP-2026-0917/receipts",
"approver": "Martin Kowalski",
"approver_role": "Head of Client Services"
},
"lines": [
{
"date": "2026-09-02",
"receipt": "R01",
"category": "Travel",
"description": "Contactless fares, client meetings in the City",
"project": "CLT-130",
"currency": "GBP",
"amount": 14.7,
"vat_rate": 0
},
{
"date": "2026-09-07",
"receipt": "R02",
"category": "Travel",
"description": "Rail, London King'\''s Cross to Leeds, return",
"project": "CLT-104",
"currency": "GBP",
"amount": 126,
"vat_rate": 0
}
],
"notes": "Foreign-currency receipts are converted at the rate on the card statement. Mileage is paid at 45p per mile for business journeys in your own car. Please keep the original receipts until the claim has been paid."
},
"output": {
"format": "pdf",
"filename": "expense-claim.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": {
"company": {
"name": "Tidewater Analytics Ltd",
"address": "4th Floor, Quayside House\n12 Wapping Lane\nLondon E1W 2XY",
"email": "expenses@tidewater.example.com",
"currency": "GBP"
},
"employee": {
"name": "Priya Raman",
"number": "TA-0219",
"department": "Client Services",
"cost_centre": "CS-200",
"bank_account_ending": "4821"
},
"claim": {
"number": "EXP-2026-0917",
"period_start": "2026-09-01",
"period_end": "2026-09-30",
"submitted_on": "2026-09-30",
"purpose": "Client workshops in Leeds and Amsterdam, and a site visit in Reading",
"advance": 150,
"mileage_rate": 0.45,
"receipts_url": "https://expenses.tidewater.example.com/claims/EXP-2026-0917/receipts",
"approver": "Martin Kowalski",
"approver_role": "Head of Client Services"
},
"lines": [
{
"date": "2026-09-02",
"receipt": "R01",
"category": "Travel",
"description": "Contactless fares, client meetings in the City",
"project": "CLT-130",
"currency": "GBP",
"amount": 14.7,
"vat_rate": 0
},
{
"date": "2026-09-07",
"receipt": "R02",
"category": "Travel",
"description": "Rail, London King's Cross to Leeds, return",
"project": "CLT-104",
"currency": "GBP",
"amount": 126,
"vat_rate": 0
}
],
"notes": "Foreign-currency receipts are converted at the rate on the card statement. Mileage is paid at 45p per mile for business journeys in your own car. Please keep the original receipts until the claim has been paid."
},
"output": {
"format": "pdf",
"filename": "expense-claim.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": {
"company": {
"name": "Tidewater Analytics Ltd",
"address": "4th Floor, Quayside House\n12 Wapping Lane\nLondon E1W 2XY",
"email": "expenses@tidewater.example.com",
"currency": "GBP",
},
"employee": {
"name": "Priya Raman",
"number": "TA-0219",
"department": "Client Services",
"cost_centre": "CS-200",
"bank_account_ending": "4821",
},
"claim": {
"number": "EXP-2026-0917",
"period_start": "2026-09-01",
"period_end": "2026-09-30",
"submitted_on": "2026-09-30",
"purpose": "Client workshops in Leeds and Amsterdam, and a site visit in Reading",
"advance": 150,
"mileage_rate": 0.45,
"receipts_url": "https://expenses.tidewater.example.com/claims/EXP-2026-0917/receipts",
"approver": "Martin Kowalski",
"approver_role": "Head of Client Services",
},
"lines": [
{
"date": "2026-09-02",
"receipt": "R01",
"category": "Travel",
"description": "Contactless fares, client meetings in the City",
"project": "CLT-130",
"currency": "GBP",
"amount": 14.7,
"vat_rate": 0,
},
{
"date": "2026-09-07",
"receipt": "R02",
"category": "Travel",
"description": "Rail, London King's Cross to Leeds, return",
"project": "CLT-104",
"currency": "GBP",
"amount": 126,
"vat_rate": 0,
},
],
"notes": "Foreign-currency receipts are converted at the rate on the card statement. Mileage is paid at 45p per mile for business journeys in your own car. Please keep the original receipts until the claim has been paid.",
},
"output": {
"format": "pdf",
"filename": "expense-claim.pdf",
},
},
timeout=90,
)
response.raise_for_status()
print(response.json())More hr & employment templates
- 210 × 297 mm
Arbeitszeugnis (employment reference)
A4A German qualified employment reference on letterhead: the template writes the opening, the overall rating, the conduct sentence and the closing formula from the rating and the reason for leaving, in the right grammatical forms, switches to an interim reference with one field, and ends with two signature lines.
- 210 × 297 mm
Monthly timesheet
A4An A4 monthly timesheet that lists every day of the period grouped by ISO week, works out hours from start, end and break, credits leave and sickness, compares the total with the contracted hours, charts hours by activity and ends with employee, manager and payroll sign-off boxes.