210 × 297 mm
Invoices
E-Rechnung (ZUGFeRD / XRechnung)
A German A4 invoice rendered straight from the EN 16931 invoice model, so the same data produces the visible invoice and the embedded Factur-X / ZUGFeRD or XRechnung XML (output.einvoice.invoice_path = "invoice"). It prints the engine's computed amounts, lists VAT per rate, the Leitweg-ID and the bank details.
Opens Dynamic Document API with this template preloaded in a free workspace.
Template language features
- Loops
- Conditionals
- Macros
- Filters
- Currency formatting
- Date formatting
- Grouping
- 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: 1 top-level field, 62 paths in total. Send the same shape as data.
| Path | Type | Example |
|---|---|---|
| invoice | object | |
| invoice.number | string | "XR-2026-0007" |
| invoice.issue_date | date | "2026-09-23" |
| invoice.due_date | date | "2026-10-23" |
| invoice.currency | string | "EUR" |
| invoice.buyer_reference | string | "04011000-12345-34" |
| invoice.payment_terms | string | "Zahlbar innerhalb von 30 Tagen ohne Abzug." |
| invoice.invoice_period | object | |
| invoice.invoice_period.start | date | "2026-09-01" |
| invoice.invoice_period.end | date | "2026-09-30" |
| invoice.seller | object | |
| invoice.seller.name | string | "Größenwahn GmbH" |
| invoice.seller.vat_id | string | "DE123456789" |
| invoice.seller.tax_number | string | "30/123/45678" |
| invoice.seller.legal_registration | object | |
| invoice.seller.legal_registration.id | string | "HRB 12345" |
| invoice.seller.electronic_address | object | |
| invoice.seller.electronic_address.id | string | "rechnung@groessenwahn.example" |
| invoice.seller.electronic_address.scheme | string | "EM" |
| invoice.seller.address | object | |
| invoice.seller.address.line1 | string | "Beispielstraße 1" |
| invoice.seller.address.city | string | "Berlin" |
| invoice.seller.address.postcode | string | "10115" |
| invoice.seller.address.country | string | "DE" |
| invoice.seller.contact | object | |
| invoice.seller.contact.name | string | "Erika Muster" |
| invoice.seller.contact.phone | string | "+49 30 1234567" |
| invoice.seller.contact.email | string | "erika.muster@groessenwahn.example" |
| invoice.buyer | object | |
| invoice.buyer.name | string | "Bundesamt für Beispiele" |
| invoice.buyer.electronic_address | object | |
| invoice.buyer.electronic_address.id | string | "04011000-12345-34" |
| invoice.buyer.electronic_address.scheme | string | "0204" |
| invoice.buyer.address | object | |
| invoice.buyer.address.line1 | string | "Amtsweg 2" |
| invoice.buyer.address.city | string | "Bonn" |
| invoice.buyer.address.postcode | string | "53113" |
| invoice.buyer.address.country | string | "DE" |
| invoice.payment | object | |
| invoice.payment.means_code | string | "58" |
| invoice.payment.remittance_information | string | "XR-2026-0007" |
| invoice.payment.credit_transfers | array<object> · 1 | |
| invoice.payment.credit_transfers[].account_id | string | "DE02120300000000202051" |
| invoice.payment.credit_transfers[].account_name | string | "Größenwahn GmbH" |
| invoice.lines | array<object> · 2 | |
| invoice.lines[].quantity | string | "8" |
| invoice.lines[].unit | string | "HUR" |
| invoice.lines[].price | object | |
| invoice.lines[].price.net | string | "95.00" |
| invoice.lines[].tax | object | |
| invoice.lines[].tax.category | string | "S" |
| invoice.lines[].tax.rate | string | "19" |
| invoice.lines[].item | object | |
| invoice.lines[].item.name | string | "Softwarewartung" |
| invoice.lines[].item.description | string | "Wartung Fachverfahren, September 2026" |
| invoice.lines[].allowances? | array<object> · 1 | |
| invoice.lines[].allowances[].amount | string | "25.00" |
| invoice.lines[].allowances[].reason | string | "Rabatt" |
| invoice.notes | array<object> · 1 | |
| invoice.notes[].text | string | "Leistungen gemäß Rahmenvertrag RV-2025-17." |
| invoice.notes[].subject_code | string | "AAI" |
| invoice.contract_reference | string | "RV-2025-17" |
Sample data
Fictional records used for previews. Replace them with your own data when you call the API.
{
"invoice": {
"number": "XR-2026-0007",
"issue_date": "2026-09-23",
"due_date": "2026-10-23",
"currency": "EUR",
"buyer_reference": "04011000-12345-34",
"payment_terms": "Zahlbar innerhalb von 30 Tagen ohne Abzug.",
"invoice_period": {
"start": "2026-09-01",
"end": "2026-09-30"
},
"seller": {
"name": "Größenwahn GmbH",
"vat_id": "DE123456789",
"tax_number": "30/123/45678",
"legal_registration": {
"id": "HRB 12345"
},
"electronic_address": {
"id": "rechnung@groessenwahn.example",
"scheme": "EM"
},
"address": {
"line1": "Beispielstraße 1",
"city": "Berlin",
"postcode": "10115",
"country": "DE"
},
"contact": {
"name": "Erika Muster",
"phone": "+49 30 1234567",
"email": "erika.muster@groessenwahn.example"
}
},
"buyer": {
"name": "Bundesamt für Beispiele",
"electronic_address": {
"id": "04011000-12345-34",
"scheme": "0204"
},
"address": {
"line1": "Amtsweg 2",
"city": "Bonn",
"postcode": "53113",
"country": "DE"
}
},
"payment": {
"means_code": "58",
"remittance_information": "XR-2026-0007",
"credit_transfers": [
{
"account_id": "DE02120300000000202051",
"account_name": "Größenwahn GmbH"
}
]
},
"lines": [
{
"quantity": "8",
"unit": "HUR",
"price": {
"net": "95.00"
},
"tax": {
"category": "S",
"rate": "19"
},
"item": {
"name": "Softwarewartung",
"description": "Wartung Fachverfahren, September 2026"
}
},
{
"quantity": "1",
"unit": "C62",
"price": {
"net": "250.00"
},
"tax": {
"category": "S",
"rate": "19"
},
"item": {
"name": "Lizenz Modul Statistik"
},
"allowances": [
{
"amount": "25.00",
"reason": "Rabatt"
}
]
}
],
"notes": [
{
"text": "Leistungen gemäß Rahmenvertrag RV-2025-17.",
"subject_code": "AAI"
}
],
"contract_reference": "RV-2025-17"
}
}Source
The body markup with Jinja, the stylesheet placed in <head> and the header and footer settings.
{#- E-Rechnung aus dem EN 16931-Rechnungsmodell (`invoice`, proto/einvoice/invoice.schema.json).
Mit `output.einvoice.invoice_path = "invoice"` bettet der Renderer dieselben Daten als Factur-X/ZUGFeRD- bzw.
XRechnung-XML ein; die Plattform berechnet die Beträge für jedes Rendering als `render.invoice` (mit oder ohne
XML, proto/README.md §20.7) — so druckt das Template genau die Beträge des XML. `render.einvoice` zeigt nur an,
ob das XML eingebettet ist. Ohne beides (z. B. als reines HTML gerendert) rechnet es mit denselben Regeln selbst. -#}
{%- set inv = invoice -%}
{%- set cur = inv.currency -%}
{%- set loc = "de-DE" -%}
{%- set embedded = render.einvoice if (render is defined and render.einvoice is defined and render.einvoice) else none -%}
{%- set computed = render.invoice if (render is defined and render.invoice is defined and render.invoice) else embedded -%}
{%- set units = {"HUR": "Std.", "C62": "Stk.", "H87": "Stk.", "DAY": "Tag(e)", "WEE": "Woche(n)", "MON": "Monat(e)", "ANN": "Jahr(e)", "KGM": "kg", "MTR": "m", "LTR": "l", "LS": "pauschal", "E48": "Leistung"} -%}
{%- set means = {"58": "SEPA-Überweisung", "30": "Überweisung", "59": "SEPA-Lastschrift", "49": "Lastschrift", "48": "Kartenzahlung", "54": "Kreditkarte", "10": "Barzahlung"} -%}
{%- set exemptions = {"Z": "Nullsatz", "E": "Steuerbefreit", "AE": "Steuerschuldnerschaft des Leistungsempfängers", "K": "Innergemeinschaftliche Lieferung", "G": "Ausfuhrlieferung", "O": "Nicht steuerbar"} -%}
{%- set title = "Gutschrift" if inv.type_code in ["381", "261"] else ("Korrigierte Rechnung" if inv.type_code == "384" else "Rechnung") -%}
{#- Zeilenbeträge und USt-Gruppen (EN 16931 BR-CO: Zeile = Menge × Preis ÷ Basismenge ± Zu-/Abschläge) -#}
{%- set ns = namespace(rows=[], nets=[], line_total=0.0, allowance_total=0.0, charge_total=0.0) -%}
{%- for line in inv.lines -%}
{%- set base = (line.price.base_quantity | default(1)) | float -%}
{%- set lns = namespace(net=((line.quantity | float) * (line.price.net | float) / base) | round(2)) -%}
{%- for a in line.allowances | default([]) -%}{%- set lns.net = lns.net - (a.amount | float) -%}{%- endfor -%}
{%- for c in line.charges | default([]) -%}{%- set lns.net = lns.net + (c.amount | float) -%}{%- endfor -%}
{%- set net = (computed.lines[loop.index0].net_amount | float) if computed else (lns.net | round(2)) -%}
{%- set rate = (line.tax.rate | default(0)) | float -%}
{%- set ns.nets = ns.nets + [net] -%}
{%- set ns.rows = ns.rows + [{"key": line.tax.category ~ "|" ~ rate, "category": line.tax.category, "rate": rate, "net": net}] -%}
{%- set ns.line_total = ns.line_total + net -%}
{%- endfor -%}
{%- for a in inv.allowances | default([]) -%}
{%- set rate = (a.tax_rate | default(0)) | float -%}
{%- set ns.rows = ns.rows + [{"key": a.tax_category ~ "|" ~ rate, "category": a.tax_category, "rate": rate, "net": 0 - (a.amount | float)}] -%}
{%- set ns.allowance_total = ns.allowance_total + (a.amount | float) -%}
{%- endfor -%}
{%- for c in inv.charges | default([]) -%}
{%- set rate = (c.tax_rate | default(0)) | float -%}
{%- set ns.rows = ns.rows + [{"key": c.tax_category ~ "|" ~ rate, "category": c.tax_category, "rate": rate, "net": c.amount | float}] -%}
{%- set ns.charge_total = ns.charge_total + (c.amount | float) -%}
{%- endfor -%}
{%- if computed -%}
{%- set breakdown = computed.vat_breakdown -%}
{%- set totals = computed.totals -%}
{%- else -%}
{%- set bns = namespace(items=[], tax=0.0) -%}
{%- for group in ns.rows | groupby("key") -%}
{%- set first = group.list | first -%}
{%- set basis = (group.list | sum_by("net")) | round(2) -%}
{%- set tax = (basis * first.rate / 100) | round(2) -%}
{%- set bns.items = bns.items + [{"category": first.category, "rate": first.rate, "basis": basis, "tax": tax, "exemption_reason": none}] -%}
{%- set bns.tax = bns.tax + tax -%}
{%- endfor -%}
{%- set tax_basis = (ns.line_total - ns.allowance_total + ns.charge_total) | round(2) -%}
{%- set grand = (tax_basis + bns.tax) | round(2) -%}
{%- set prepaid = (inv.prepaid_amount | default(0)) | float -%}
{%- set rounding = (inv.rounding_amount | default(0)) | float -%}
{%- set breakdown = bns.items -%}
{%- set totals = {"line_total": ns.line_total | round(2), "allowance_total": ns.allowance_total | round(2), "charge_total": ns.charge_total | round(2), "tax_basis_total": tax_basis, "tax_total": bns.tax | round(2), "grand_total": grand, "prepaid": prepaid, "rounding": rounding, "due_payable": (grand - prepaid + rounding) | round(2)} -%}
{%- endif -%}
{%- macro money(value) -%}{{ value | format_currency(cur, loc) }}{%- endmacro -%}
{%- macro day(value) -%}{{ value | format_date("medium", loc) }}{%- endmacro -%}
{%- macro one_line(party) -%}
{{ party.name }}{% if party.address.line1 %} · {{ party.address.line1 }}{% endif %} · {{ party.address.postcode }} {{ party.address.city }}
{%- endmacro -%}
<header class="top">
<div class="brand">
<svg viewBox="0 0 40 40" aria-hidden="true">
<rect x="2" y="2" width="36" height="36" rx="8" fill="#1f5f8b"/>
<path d="M12 12h16M12 20h16M12 28h10" fill="none" stroke="#fff" stroke-width="3.2" stroke-linecap="round"/>
</svg>
<div>
<div class="brand-name">{{ inv.seller.trading_name or inv.seller.name }}</div>
{% if inv.seller.contact %}<div class="muted">{{ inv.seller.contact.email }}{% if inv.seller.contact.phone %} · {{ inv.seller.contact.phone }}{% endif %}</div>{% endif %}
</div>
</div>
<table class="facts">
<tr><th scope="row">{{ title }}snummer</th><td><strong>{{ inv.number }}</strong></td></tr>
<tr><th scope="row">Datum</th><td>{{ day(inv.issue_date) }}</td></tr>
{% if inv.delivery and inv.delivery.date %}<tr><th scope="row">Lieferdatum</th><td>{{ day(inv.delivery.date) }}</td></tr>{% endif %}
{% if inv.invoice_period %}<tr><th scope="row">Leistungszeitraum</th><td>{{ day(inv.invoice_period.start) }} – {{ day(inv.invoice_period.end) }}</td></tr>{% endif %}
{% if inv.due_date %}<tr><th scope="row">Fällig am</th><td>{{ day(inv.due_date) }}</td></tr>{% endif %}
{% if inv.buyer_reference %}<tr><th scope="row">{{ "Leitweg-ID" if (inv.buyer.electronic_address and inv.buyer.electronic_address.scheme == "0204") else "Ihre Referenz" }}</th><td>{{ inv.buyer_reference }}</td></tr>{% endif %}
{% if inv.order_reference %}<tr><th scope="row">Bestellnummer</th><td>{{ inv.order_reference }}</td></tr>{% endif %}
{% if inv.contract_reference %}<tr><th scope="row">Vertrag</th><td>{{ inv.contract_reference }}</td></tr>{% endif %}
{% if inv.buyer.vat_id %}<tr><th scope="row">Ihre USt-IdNr.</th><td>{{ inv.buyer.vat_id }}</td></tr>{% endif %}
</table>
</header>
<p class="sender-line">{{ one_line(inv.seller) }}</p>
<div class="recipient">
<p><strong>{{ inv.buyer.name }}</strong></p>
{% if inv.buyer.contact and inv.buyer.contact.name %}<p>z. Hd. {{ inv.buyer.contact.name }}</p>{% endif %}
{% if inv.buyer.address.line1 %}<p>{{ inv.buyer.address.line1 }}</p>{% endif %}
{% if inv.buyer.address.line2 %}<p>{{ inv.buyer.address.line2 }}</p>{% endif %}
<p>{{ inv.buyer.address.postcode }} {{ inv.buyer.address.city }}</p>
{% if inv.buyer.address.country != "DE" %}<p>{{ inv.buyer.address.country }}</p>{% endif %}
</div>
<h1>{{ title }} {{ inv.number }}</h1>
{% if inv.preceding_invoices %}
<p class="intro">Bezug: {% for p in inv.preceding_invoices %}Rechnung {{ p.number }}{% if p.issue_date %} vom {{ day(p.issue_date) }}{% endif %}{{ ", " if not loop.last }}{% endfor %}</p>
{% else %}
<p class="intro">Wir berechnen Ihnen die folgenden Leistungen.</p>
{% endif %}
<table class="items">
<thead>
<tr>
<th class="pos" scope="col">Pos.</th>
<th scope="col">Bezeichnung</th>
<th class="num" scope="col">Menge</th>
<th class="num" scope="col">Einzelpreis</th>
<th class="num" scope="col">USt</th>
<th class="num" scope="col">Betrag</th>
</tr>
</thead>
<tbody>
{% for line in inv.lines %}
<tr>
<td class="pos">{{ line.id or loop.index }}</td>
<td>
<span class="item-name">{{ line.item.name }}</span>
{% if line.item.description %}<span class="item-detail">{{ line.item.description }}</span>{% endif %}
{% if line.period %}<span class="item-detail">Zeitraum {{ day(line.period.start) }} – {{ day(line.period.end) }}</span>{% endif %}
{% for a in line.allowances | default([]) %}<span class="item-detail">abzüglich {{ a.reason or "Nachlass" }}: {{ money(a.amount | float) }}</span>{% endfor %}
{% for c in line.charges | default([]) %}<span class="item-detail">zuzüglich {{ c.reason or "Zuschlag" }}: {{ money(c.amount | float) }}</span>{% endfor %}
</td>
<td class="num">{{ (line.quantity | float) | format_number(loc) }} {{ units[line.unit or "C62"] or line.unit }}</td>
<td class="num">{{ money(line.price.net | float) }}</td>
<td class="num">{% if line.tax.category in ["S", "L", "M"] %}{{ (line.tax.rate | float) | format_number(loc) }} %{% else %}{{ line.tax.category }}{% endif %}</td>
<td class="num">{{ money(ns.nets[loop.index0]) }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<section class="summary">
<div class="notes">
{% for note in inv.notes | default([]) %}<p>{{ note.text }}</p>{% endfor %}
{% for b in breakdown %}
{% if b.category in exemptions %}
<p class="exemption">{{ exemptions[b.category] }}{% if inv.vat_exemptions and inv.vat_exemptions[b.category] and inv.vat_exemptions[b.category].reason %}: {{ inv.vat_exemptions[b.category].reason }}{% endif %}</p>
{% endif %}
{% endfor %}
</div>
<table class="totals">
<tr><th scope="row">Summe Positionen</th><td class="num">{{ money(totals.line_total | float) }}</td></tr>
{% if (totals.allowance_total | float) != 0 %}<tr><th scope="row">Nachlässe</th><td class="num">−{{ money(totals.allowance_total | float) }}</td></tr>{% endif %}
{% if (totals.charge_total | float) != 0 %}<tr><th scope="row">Zuschläge</th><td class="num">{{ money(totals.charge_total | float) }}</td></tr>{% endif %}
<tr class="sub"><th scope="row">Nettobetrag</th><td class="num">{{ money(totals.tax_basis_total | float) }}</td></tr>
{% for b in breakdown %}
<tr><th scope="row">{% if b.category in exemptions %}{{ exemptions[b.category] }} ({{ money(b.basis | float) }}){% else %}USt {{ (b.rate | float) | format_number(loc) }} % auf {{ money(b.basis | float) }}{% endif %}</th><td class="num">{{ money(b.tax | float) }}</td></tr>
{% endfor %}
<tr class="grand"><th scope="row">Gesamtbetrag</th><td class="num">{{ money(totals.grand_total | float) }}</td></tr>
{% if (totals.prepaid | float) != 0 %}<tr><th scope="row">Bereits gezahlt</th><td class="num">−{{ money(totals.prepaid | float) }}</td></tr>{% endif %}
{% if (totals.rounding | float) != 0 %}<tr><th scope="row">Rundung</th><td class="num">{{ money(totals.rounding | float) }}</td></tr>{% endif %}
<tr class="due"><th scope="row">Zahlbetrag</th><td class="num">{{ money(totals.due_payable | float) }}</td></tr>
</table>
</section>
{% if inv.payment %}
<section class="payment">
<p class="label">Zahlung</p>
<dl>
<dt>Zahlungsart</dt><dd>{{ means[inv.payment.means_code] or inv.payment.means_text or inv.payment.means_code }}</dd>
{% for account in inv.payment.credit_transfers | default([]) %}
<dt>Kontoinhaber</dt><dd>{{ account.account_name or inv.seller.name }}</dd>
<dt>IBAN</dt><dd>{{ account.account_id }}</dd>
{% if account.bic %}<dt>BIC</dt><dd>{{ account.bic }}</dd>{% endif %}
{% endfor %}
{% if inv.payment.direct_debit %}
<dt>Mandatsreferenz</dt><dd>{{ inv.payment.direct_debit.mandate_reference }}</dd>
<dt>Gläubiger-ID</dt><dd>{{ inv.payment.direct_debit.creditor_id }}</dd>
{% endif %}
<dt>Verwendungszweck</dt><dd>{{ inv.payment.remittance_information or inv.number }}</dd>
{% if inv.payment_terms %}<dt>Bedingungen</dt><dd>{{ inv.payment_terms }}</dd>{% endif %}
</dl>
</section>
{% endif %}
{% if embedded %}
<p class="einvoice-hint">Diese Rechnung enthält die strukturierten Rechnungsdaten nach EN 16931 ({{ embedded.profile }}) als eingebettete XML-Datei.</p>
{% endif %}<title>{{ "Gutschrift" if invoice.type_code in ["381", "261"] else ("Korrigierte Rechnung" if invoice.type_code == "384" else "Rechnung") }} {{ invoice.number }} – {{ invoice.seller.trading_name or invoice.seller.name }}</title>
<style>
:root {
--ink: #17202c;
--muted: #5b6472;
--rule: #d9dee5;
--soft: #f2f5f8;
--accent: #1f5f8b;
}
* { 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: 9pt;
line-height: 1.45;
}
p { margin: 0; }
.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.muted { color: var(--muted); }
.label { font-size: 7pt; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); margin-bottom: 1.2mm; }
.top { display: flex; justify-content: space-between; align-items: flex-start; }
.brand { display: flex; gap: 3mm; align-items: center; }
.brand svg { width: 10mm; height: 10mm; }
.brand-name { font-size: 11pt; font-weight: 700; }
.sender-line { margin-top: 14mm; font-size: 6.5pt; color: var(--muted); border-bottom: 0.2mm solid var(--rule); padding-bottom: 0.8mm; display: inline-block; }
.recipient { margin-top: 2mm; min-height: 27mm; font-size: 9.5pt; }
.recipient p { line-height: 1.4; }
.facts { width: 72mm; border-collapse: collapse; font-size: 8.5pt; }
.facts td, .facts th { padding: 0.5mm 0; vertical-align: top; }
.facts th { color: var(--muted); padding-right: 3mm; white-space: nowrap; font-weight: inherit; text-align: inherit; }
.facts td:last-child { text-align: right; }
h1 { font-size: 17pt; font-weight: 700; margin: 9mm 0 1.5mm; letter-spacing: -0.01em; }
.intro { margin-bottom: 6mm; color: var(--muted); }
table.items { width: 100%; border-collapse: collapse; }
table.items thead { display: table-header-group; }
table.items th {
font-size: 7pt; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase; color: var(--muted);
text-align: left; padding: 2mm 1.6mm; border-bottom: 0.3mm solid var(--ink);
}
table.items th.num { text-align: right; }
table.items td { padding: 2.4mm 1.6mm; border-bottom: 0.2mm solid var(--rule); vertical-align: top; }
table.items tr { break-inside: avoid; page-break-inside: avoid; }
table.items .pos { width: 8mm; color: var(--muted); }
table.items .item-name { font-weight: 600; }
table.items .item-detail { display: block; font-size: 8pt; color: var(--muted); margin-top: 0.5mm; }
.summary { display: grid; grid-template-columns: 1fr 78mm; gap: 10mm; margin-top: 6mm; break-inside: avoid; page-break-inside: avoid; }
.totals { width: 100%; border-collapse: collapse; }
.totals td, .totals th { padding: 1.2mm 1.6mm; }
.totals th { font-weight: inherit; text-align: inherit; }
.totals .sub td, .totals .sub th { border-top: 0.2mm solid var(--rule); }
.totals .grand td, .totals .grand th { border-top: 0.4mm solid var(--ink); font-size: 11pt; font-weight: 700; padding-top: 2.4mm; }
.totals .due td, .totals .due th { background: var(--soft); color: var(--accent); font-weight: 700; }
.notes p { margin-bottom: 2mm; }
.exemption { margin-top: 2mm; font-size: 8pt; color: var(--muted); }
.payment { margin-top: 8mm; padding: 4mm 5mm; border: 0.3mm solid var(--rule); border-radius: 2mm; break-inside: avoid; page-break-inside: avoid; }
.payment dl { display: grid; grid-template-columns: auto 1fr; gap: 0.8mm 5mm; margin: 1.5mm 0 0; }
.payment dt { color: var(--muted); }
.payment dd { margin: 0; font-variant-numeric: tabular-nums; }
.einvoice-hint { margin-top: 6mm; 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": {
"invoice": {
"number": "XR-2026-0007",
"issue_date": "2026-09-23",
"due_date": "2026-10-23",
"currency": "EUR",
"buyer_reference": "04011000-12345-34",
"payment_terms": "Zahlbar innerhalb von 30 Tagen ohne Abzug.",
"invoice_period": {
"start": "2026-09-01",
"end": "2026-09-30"
},
"seller": {
"name": "Größenwahn GmbH",
"vat_id": "DE123456789",
"tax_number": "30/123/45678",
"legal_registration": {
"id": "HRB 12345"
},
"electronic_address": {
"id": "rechnung@groessenwahn.example",
"scheme": "EM"
},
"address": {
"line1": "Beispielstraße 1",
"city": "Berlin",
"postcode": "10115",
"country": "DE"
},
"contact": {
"name": "Erika Muster",
"phone": "+49 30 1234567",
"email": "erika.muster@groessenwahn.example"
}
},
"buyer": {
"name": "Bundesamt für Beispiele",
"electronic_address": {
"id": "04011000-12345-34",
"scheme": "0204"
},
"address": {
"line1": "Amtsweg 2",
"city": "Bonn",
"postcode": "53113",
"country": "DE"
}
},
"payment": {
"means_code": "58",
"remittance_information": "XR-2026-0007",
"credit_transfers": [
{
"account_id": "DE02120300000000202051",
"account_name": "Größenwahn GmbH"
}
]
},
"lines": [
{
"quantity": "8",
"unit": "HUR",
"price": {
"net": "95.00"
},
"tax": {
"category": "S",
"rate": "19"
},
"item": {
"name": "Softwarewartung",
"description": "Wartung Fachverfahren, September 2026"
}
},
{
"quantity": "1",
"unit": "C62",
"price": {
"net": "250.00"
},
"tax": {
"category": "S",
"rate": "19"
},
"item": {
"name": "Lizenz Modul Statistik"
},
"allowances": [
{
"amount": "25.00",
"reason": "Rabatt"
}
]
}
],
"notes": [
{
"text": "Leistungen gemäß Rahmenvertrag RV-2025-17.",
"subject_code": "AAI"
}
],
"contract_reference": "RV-2025-17"
}
},
"output": {
"format": "pdf",
"filename": "invoice-e-rechnung.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": {
"invoice": {
"number": "XR-2026-0007",
"issue_date": "2026-09-23",
"due_date": "2026-10-23",
"currency": "EUR",
"buyer_reference": "04011000-12345-34",
"payment_terms": "Zahlbar innerhalb von 30 Tagen ohne Abzug.",
"invoice_period": {
"start": "2026-09-01",
"end": "2026-09-30"
},
"seller": {
"name": "Größenwahn GmbH",
"vat_id": "DE123456789",
"tax_number": "30/123/45678",
"legal_registration": {
"id": "HRB 12345"
},
"electronic_address": {
"id": "rechnung@groessenwahn.example",
"scheme": "EM"
},
"address": {
"line1": "Beispielstraße 1",
"city": "Berlin",
"postcode": "10115",
"country": "DE"
},
"contact": {
"name": "Erika Muster",
"phone": "+49 30 1234567",
"email": "erika.muster@groessenwahn.example"
}
},
"buyer": {
"name": "Bundesamt für Beispiele",
"electronic_address": {
"id": "04011000-12345-34",
"scheme": "0204"
},
"address": {
"line1": "Amtsweg 2",
"city": "Bonn",
"postcode": "53113",
"country": "DE"
}
},
"payment": {
"means_code": "58",
"remittance_information": "XR-2026-0007",
"credit_transfers": [
{
"account_id": "DE02120300000000202051",
"account_name": "Größenwahn GmbH"
}
]
},
"lines": [
{
"quantity": "8",
"unit": "HUR",
"price": {
"net": "95.00"
},
"tax": {
"category": "S",
"rate": "19"
},
"item": {
"name": "Softwarewartung",
"description": "Wartung Fachverfahren, September 2026"
}
},
{
"quantity": "1",
"unit": "C62",
"price": {
"net": "250.00"
},
"tax": {
"category": "S",
"rate": "19"
},
"item": {
"name": "Lizenz Modul Statistik"
},
"allowances": [
{
"amount": "25.00",
"reason": "Rabatt"
}
]
}
],
"notes": [
{
"text": "Leistungen gemäß Rahmenvertrag RV-2025-17.",
"subject_code": "AAI"
}
],
"contract_reference": "RV-2025-17"
}
},
"output": {
"format": "pdf",
"filename": "invoice-e-rechnung.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": {
"invoice": {
"number": "XR-2026-0007",
"issue_date": "2026-09-23",
"due_date": "2026-10-23",
"currency": "EUR",
"buyer_reference": "04011000-12345-34",
"payment_terms": "Zahlbar innerhalb von 30 Tagen ohne Abzug.",
"invoice_period": {
"start": "2026-09-01",
"end": "2026-09-30",
},
"seller": {
"name": "Größenwahn GmbH",
"vat_id": "DE123456789",
"tax_number": "30/123/45678",
"legal_registration": {
"id": "HRB 12345",
},
"electronic_address": {
"id": "rechnung@groessenwahn.example",
"scheme": "EM",
},
"address": {
"line1": "Beispielstraße 1",
"city": "Berlin",
"postcode": "10115",
"country": "DE",
},
"contact": {
"name": "Erika Muster",
"phone": "+49 30 1234567",
"email": "erika.muster@groessenwahn.example",
},
},
"buyer": {
"name": "Bundesamt für Beispiele",
"electronic_address": {
"id": "04011000-12345-34",
"scheme": "0204",
},
"address": {
"line1": "Amtsweg 2",
"city": "Bonn",
"postcode": "53113",
"country": "DE",
},
},
"payment": {
"means_code": "58",
"remittance_information": "XR-2026-0007",
"credit_transfers": [
{
"account_id": "DE02120300000000202051",
"account_name": "Größenwahn GmbH",
},
],
},
"lines": [
{
"quantity": "8",
"unit": "HUR",
"price": {
"net": "95.00",
},
"tax": {
"category": "S",
"rate": "19",
},
"item": {
"name": "Softwarewartung",
"description": "Wartung Fachverfahren, September 2026",
},
},
{
"quantity": "1",
"unit": "C62",
"price": {
"net": "250.00",
},
"tax": {
"category": "S",
"rate": "19",
},
"item": {
"name": "Lizenz Modul Statistik",
},
"allowances": [
{
"amount": "25.00",
"reason": "Rabatt",
},
],
},
],
"notes": [
{
"text": "Leistungen gemäß Rahmenvertrag RV-2025-17.",
"subject_code": "AAI",
},
],
"contract_reference": "RV-2025-17",
},
},
"output": {
"format": "pdf",
"filename": "invoice-e-rechnung.pdf",
},
},
timeout=90,
)
response.raise_for_status()
print(response.json())More invoices templates
- 210 × 297 mm
Bold brand invoice
A4A confident, colourful A4 invoice for studios and product companies: a brand-coloured hero with the amount due, brand colours you set from data, itemised EN 16931 lines, VAT, a pay-by-link QR code and the same data embedded as ZUGFeRD / Factur-X EN 16931 XML.
- 210 × 297 mm
EU reverse-charge invoice
A4An A4 invoice for cross-border B2B services within the EU, rendered from the EN 16931 invoice model: both VAT IDs, the date of supply, VAT category AE (reverse charge) with its exemption reason and notice, the total in words, bank transfer details and the same data embedded as ZUGFeRD / Factur-X EN 16931 XML.
- 210 × 297 mm
Freelancer invoice
A4A friendly A4 invoice for freelancers, easy to edit visually: a wordmark heading, bill-to and project details, service lines, VAT totals, bank details with a pay-by-link QR code, a personal thank-you note and page numbers. Embeds ZUGFeRD / Factur-X EN 16931 XML.