Skip to content

210 × 297 mm

Real estate

Betriebskostenabrechnung (utility cost statement)

A German annual utility cost statement for one flat in a DIN 5008 letter layout: each cost type is split by its allocation key (floor area, water meter, persons, units), heating costs come from the metering service, and the balance against the prepayments shows as a payment due or a refund.

A4 portraitLocale de-DEHTML + JinjaHeader & footer

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
  • 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: 9 top-level fields, 59 paths in total. Send the same shape as data.

PathTypeExample
managerobject
manager.namestring"Brookhoff Hausverwaltung GmbH"
manager.short_namestring"Brookhoff Hausverwaltung"
manager.streetstring"Am Kanalufer 9"
manager.postcodestring"22303"
manager.citystring"Hamburg"
manager.phonestring"+49 40 66969 040"
manager.emailstring"abrechnung@brookhoff.example.com"
manager.websitestring"brookhoff.example.com"
manager.registerstring"Amtsgericht Hamburg, HRB 123456"
manager.managing_directorstring"Jasper Brookhoff"
manager.vat_idstring"DE123456789"
manager.ibanstring"DE00 EXMP 0000 0045 6789 01"
manager.bicstring"EXMPDEHHXXX"
manager.office_hoursstring"Mo–Do 9–16 Uhr, Fr 9–13 Uhr"
contactobject
contact.namestring"Merle Tiedemann"
contact.phonestring"+49 40 66969 047"
contact.emailstring"m.tiedemann@brookhoff.example.com"
landlordstring"Eigentümergemeinschaft Holunderstieg 12–14"
propertyobject
property.referencestring"HOL-12"
property.addressstring"Holunderstieg 12–14, 22083 Hamburg"
property.unitsnumber18
tenancyobject
tenancy.tenant_numberstring"M-0314-07"
tenancy.unitstring"Holunderstieg 14, 3. OG links (Whg. 07)"
tenancy.tenantsarray<object> · 2
tenancy.tenants[].salutationstring"Frau"
tenancy.tenants[].first_namestring"Leonie"
tenancy.tenants[].last_namestring"Hartwig"
tenancy.streetstring"Holunderstieg 14"
tenancy.postcodestring"22083"
tenancy.citystring"Hamburg"
statementobject
statement.datedate"2026-09-21"
statement.period_startdate"2025-01-01"
statement.period_enddate"2025-12-31"
statement.payment_daysnumber30
statement.monthly_prepaymentnumber215
statement.months_paidnumber12
statement.new_monthly_prepaymentnumber225
statement.new_prepayment_fromdate"2026-11-01"
allocation_keysarray<object> · 4
allocation_keys[].idstring"area"
allocation_keys[].labelstring"Wohnfläche"
allocation_keys[].unitstring"m²"
allocation_keys[].decimalsnumber2
allocation_keys[].totalnumber1386.5
allocation_keys[].sharenumber74.6
costsarray<object> · 13
costs[].namestring"Grundsteuer"
costs[].totalnumber3186.4
costs[].keystring"area"
costs[].tax_35a?string"service"
heatingobject
heating.labelstring"Heiz- und Warmwasserkosten"
heating.notestring"lt. Einzelabrechnung des Messdienstes"
heating.amountnumber846.27

Sample data

Fictional records used for previews. Replace them with your own data when you call the API.

data.json
{
  "manager": {
    "name": "Brookhoff Hausverwaltung GmbH",
    "short_name": "Brookhoff Hausverwaltung",
    "street": "Am Kanalufer 9",
    "postcode": "22303",
    "city": "Hamburg",
    "phone": "+49 40 66969 040",
    "email": "abrechnung@brookhoff.example.com",
    "website": "brookhoff.example.com",
    "register": "Amtsgericht Hamburg, HRB 123456",
    "managing_director": "Jasper Brookhoff",
    "vat_id": "DE123456789",
    "iban": "DE00 EXMP 0000 0045 6789 01",
    "bic": "EXMPDEHHXXX",
    "office_hours": "Mo–Do 9–16 Uhr, Fr 9–13 Uhr"
  },
  "contact": {
    "name": "Merle Tiedemann",
    "phone": "+49 40 66969 047",
    "email": "m.tiedemann@brookhoff.example.com"
  },
  "landlord": "Eigentümergemeinschaft Holunderstieg 12–14",
  "property": {
    "reference": "HOL-12",
    "address": "Holunderstieg 12–14, 22083 Hamburg",
    "units": 18
  },
  "tenancy": {
    "tenant_number": "M-0314-07",
    "unit": "Holunderstieg 14, 3. OG links (Whg. 07)",
    "tenants": [
      { "salutation": "Frau", "first_name": "Leonie", "last_name": "Hartwig" },
      { "salutation": "Herr", "first_name": "Can", "last_name": "Yilmaz" }
    ],
    "street": "Holunderstieg 14",
    "postcode": "22083",
    "city": "Hamburg"
  },
  "statement": {
    "date": "2026-09-21",
    "period_start": "2025-01-01",
    "period_end": "2025-12-31",
    "payment_days": 30,
    "monthly_prepayment": 215.0,
    "months_paid": 12,
    "new_monthly_prepayment": 225.0,
    "new_prepayment_from": "2026-11-01"
  },
  "allocation_keys": [
    { "id": "area", "label": "Wohnfläche", "unit": "m²", "decimals": 2, "total": 1386.5, "share": 74.6 },
    { "id": "water", "label": "Wasserverbrauch", "unit": "m³", "decimals": 1, "total": 1536.0, "share": 84.6 },
    { "id": "persons", "label": "Personen", "unit": "Pers.", "decimals": 0, "total": 34, "share": 2 },
    { "id": "units", "label": "Wohneinheiten", "unit": "WE", "decimals": 0, "total": 18, "share": 1 }
  ],
  "costs": [
    { "name": "Grundsteuer", "total": 3186.4, "key": "area" },
    { "name": "Wasserversorgung", "total": 3456.0, "key": "water" },
    { "name": "Entwässerung (Schmutzwasser)", "total": 3148.8, "key": "water" },
    { "name": "Niederschlagswasser", "total": 892.5, "key": "area" },
    { "name": "Müllbeseitigung", "total": 3264.0, "key": "persons" },
    { "name": "Straßenreinigung", "total": 418.2, "key": "area" },
    { "name": "Gebäudereinigung", "total": 4104.0, "key": "units", "tax_35a": "service" },
    { "name": "Gartenpflege", "total": 1962.0, "key": "area", "tax_35a": "service" },
    { "name": "Allgemeinstrom (Beleuchtung)", "total": 1047.6, "key": "area" },
    { "name": "Schornsteinfeger", "total": 342.0, "key": "units", "tax_35a": "craft" },
    { "name": "Sach- und Haftpflichtversicherung", "total": 5214.3, "key": "area" },
    { "name": "Hauswart", "total": 5832.0, "key": "area", "tax_35a": "service" },
    { "name": "Wartung Rauchwarnmelder", "total": 270.0, "key": "units", "tax_35a": "craft" }
  ],
  "heating": {
    "label": "Heiz- und Warmwasserkosten",
    "note": "lt. Einzelabrechnung des Messdienstes",
    "amount": 846.27
  }
}

Source

The body markup with Jinja, the stylesheet placed in <head> and the header and footer settings.

{#- Betriebskostenabrechnung (annual utility cost statement) for one flat. Each cost type names an allocation key;
    the tenant's share is total × own units ÷ total units, rounded to the cent, and the heating costs come from the
    metering service's own statement. The balance against the prepayments decides between "Nachzahlung" (to pay)
    and "Guthaben" (to refund). Sample wording only, not legal advice. -#}
{%- set loc = "de-DE" -%}
{%- set ns = namespace(operating=0.0, service=0.0, craft=0.0, amounts=[]) -%}
{%- for cost in costs -%}
  {%- set key = allocation_keys | selectattr("id", "equalto", cost.key) | first -%}
  {%- set amount = (cost.total * key.share / key.total) | round(2) -%}
  {%- set ns.amounts = ns.amounts + [amount] -%}
  {%- set ns.operating = ns.operating + amount -%}
  {%- if cost.tax_35a == "service" -%}{%- set ns.service = ns.service + amount -%}{%- endif -%}
  {%- if cost.tax_35a == "craft" -%}{%- set ns.craft = ns.craft + amount -%}{%- endif -%}
{%- endfor -%}
{%- set operating = ns.operating | round(2) -%}
{%- set heating_amount = heating.amount if heating else 0 -%}
{%- set total = (operating + heating_amount) | round(2) -%}
{%- set prepaid = (statement.monthly_prepayment * statement.months_paid) | round(2) -%}
{%- set balance = (total - prepaid) | round(2) -%}
{%- set due_date = statement.date | date_add(days=statement.payment_days) -%}
{%- set house_total = costs | sum_by("total") -%}

{%- macro money(value) -%}{{ value | format_currency("EUR", loc) }}{%- endmacro -%}
{%- macro day(value) -%}{{ value | format_date("%d.%m.%Y", loc) }}{%- endmacro -%}
{%- macro units(value, key) -%}{{ value | format_number(loc, key.decimals) }} {{ key.unit }}{%- endmacro -%}
{%- macro addressee(tenant) -%}
  {%- if tenant.salutation == "Herr" -%}Herrn {% elif tenant.salutation == "Frau" -%}Frau {% endif -%}{{ tenant.first_name }} {{ tenant.last_name }}
{%- endmacro -%}
{%- macro greeting(tenant, first) -%}
  {%- set opening = "Sehr" if first else "sehr" -%}
  {%- if tenant.salutation == "Herr" -%}{{ opening }} geehrter Herr {{ tenant.last_name }}
  {%- elif tenant.salutation == "Frau" -%}{{ opening }} geehrte Frau {{ tenant.last_name }}
  {%- else -%}{{ "Guten Tag" if first else "guten Tag" }} {{ tenant.first_name }} {{ tenant.last_name }}{%- endif -%}
{%- endmacro -%}

<header class="letterhead">
  <div class="brand">
    <svg viewBox="0 0 48 48" aria-hidden="true">
      <rect x="2" y="2" width="44" height="44" rx="10" fill="#2c5f4f"/>
      <path d="M11 24.5L24 13l13 11.5" fill="none" stroke="#ffffff" stroke-width="3.4" stroke-linecap="round" stroke-linejoin="round"/>
      <path d="M15.5 22.5V35h17V22.5" fill="none" stroke="#ffffff" stroke-width="3.4" stroke-linejoin="round"/>
      <rect x="21.2" y="27" width="5.6" height="8" rx="1" fill="#a8d5c2"/>
    </svg>
    <div>
      <div class="brand-name">{{ manager.short_name }}</div>
      <div class="brand-sub">Miet- und WEG-Verwaltung</div>
    </div>
  </div>
  <div class="sender-block">
    {{ manager.name }}<br>
    {{ manager.street }} · {{ manager.postcode }} {{ manager.city }}<br>
    {{ manager.phone }} · {{ manager.email }}
  </div>
</header>

<section class="addressing">
  <div class="window">
    <p class="return-line">{{ manager.name }} · {{ manager.street }} · {{ manager.postcode }} {{ manager.city }}</p>
    <div class="recipient">
      {% for tenant in tenancy.tenants %}<p>{{ addressee(tenant) }}</p>{% endfor %}
      <p>{{ tenancy.street }}</p>
      <p>{{ tenancy.postcode }} {{ tenancy.city }}</p>
    </div>
  </div>
  <table class="refs">
    <tr><th scope="row">Datum</th><td>{{ day(statement.date) }}</td></tr>
    <tr><th scope="row">Mieternummer</th><td>{{ tenancy.tenant_number }}</td></tr>
    <tr><th scope="row">Objekt</th><td>{{ property.reference }}</td></tr>
    <tr><th scope="row">Ansprechpartnerin</th><td>{{ contact.name }}</td></tr>
    <tr><th scope="row">Telefon</th><td>{{ contact.phone }}</td></tr>
    <tr><th scope="row">E-Mail</th><td>{{ contact.email }}</td></tr>
  </table>
</section>

<h1 class="subject">Betriebskostenabrechnung für den Zeitraum {{ day(statement.period_start) }} bis {{ day(statement.period_end) }}</h1>

<p class="salutation">{% for tenant in tenancy.tenants %}{{ greeting(tenant, loop.first) }},{% if not loop.last %} {% endif %}{% endfor %}</p>
<p class="intro">
  anbei erhalten Sie die Abrechnung der Betriebskosten für Ihre Wohnung {{ tenancy.unit }} im Auftrag der
  {{ landlord }}. Abgerechnet werden die im Mietvertrag vereinbarten Betriebskosten mit den tatsächlichen Kosten des
  Abrechnungszeitraums. Die Heiz- und Warmwasserkosten wurden vom Messdienst nach Verbrauch ermittelt; dessen
  Einzelabrechnung liegt diesem Schreiben bei.
</p>

<div class="result{{ ' due' if balance > 0 else '' }}">
  <div>
    <p class="result-label">{% if balance > 0 %}Ihre Nachzahlung{% elif balance < 0 %}Ihr Guthaben{% else %}Ergebnis{% endif %}</p>
    <p class="result-text">
      {% if balance > 0 %}Bitte überweisen Sie den Betrag bis zum <strong>{{ day(due_date) }}</strong> unter Angabe Ihrer Mieternummer {{ tenancy.tenant_number }}.
      {% elif balance < 0 %}Wir überweisen Ihnen den Betrag bis zum <strong>{{ day(due_date) }}</strong> auf das uns bekannte Konto.
      {% else %}Ihre Vorauszahlungen decken die Kosten genau; es ist nichts zu zahlen.{% endif %}
    </p>
  </div>
  <p class="result-amount">{{ money(balance | abs) }}</p>
</div>

<section class="keys">
  <h2 class="section-title"><span>1</span>Verteilerschlüssel</h2>
  <div class="key-cards">
    {% for key in allocation_keys %}
    <div class="key-card">
      <p class="key-label">{{ key.label }}</p>
      <p class="key-value">{{ units(key.share, key) }}</p>
      <p class="key-total">von {{ units(key.total, key) }} · {{ (key.share / key.total) | format_percent(loc, 3) }}</p>
    </div>
    {% endfor %}
  </div>
  <p class="table-note">Wirtschaftseinheit {{ property.address }} mit {{ property.units }} Wohnungen. Nutzungszeitraum: der gesamte Abrechnungszeitraum.</p>
</section>

<section class="costs">
  <h2 class="section-title"><span>2</span>Kostenaufstellung</h2>
  <table class="grid">
    <thead>
      <tr>
        <th scope="col">Kostenart</th>
        <th class="num" scope="col">Gesamtkosten</th>
        <th scope="col">Verteilung</th>
        <th class="num" scope="col">Ihre Kosten</th>
      </tr>
    </thead>
    <tbody>
      {% for cost in costs %}
      {%- set key = allocation_keys | selectattr("id", "equalto", cost.key) | first %}
      <tr>
        <td>{{ cost.name }}{% if cost.tax_35a %} <span class="marker">*</span>{% endif %}</td>
        <td class="num">{{ money(cost.total) }}</td>
        <td><span class="key-tag">{{ key.label }}</span> <span class="share">{{ key.share | format_number(loc, key.decimals) }} / {{ units(key.total, key) }}</span></td>
        <td class="num">{{ money(ns.amounts[loop.index0]) }}</td>
      </tr>
      {% endfor %}
      {% if heating %}
      <tr>
        <td>{{ heating.label }}</td>
        <td class="num">–</td>
        <td><span class="key-tag">Verbrauch</span> <span class="share">{{ heating.note }}</span></td>
        <td class="num">{{ money(heating_amount) }}</td>
      </tr>
      {% endif %}
    </tbody>
    <tfoot>
      <tr>
        <th scope="row">Summe</th>
        <td class="num">{{ money(house_total) }}</td>
        <td class="blank"></td>
        <td class="num">{{ money(total) }}</td>
      </tr>
    </tfoot>
  </table>
  <p class="table-note">{% if heating %}Gesamtkosten der Wirtschaftseinheit ohne Heizkosten.{% endif %}{% if ns.service > 0 or ns.craft > 0 %} <span class="marker">*</span> Enthält Aufwendungen, die nach § 35a EStG steuerlich begünstigt sein können (siehe Hinweise).{% endif %}</p>
</section>

<section class="result-section">
  <h2 class="section-title"><span>3</span>Ergebnis</h2>
  <div class="summary">
    <div class="pay-box">
      {% if balance > 0 %}
      <p class="box-title">Zahlungsempfänger</p>
      <dl>
        <dt>Empfänger</dt><dd>{{ manager.name }}</dd>
        <dt>IBAN</dt><dd>{{ manager.iban }}</dd>
        <dt>BIC</dt><dd>{{ manager.bic }}</dd>
        <dt>Betrag</dt><dd>{{ money(balance) }}</dd>
        <dt>Zahlbar bis</dt><dd>{{ day(due_date) }}</dd>
        <dt>Verwendungszweck</dt><dd>BKA {{ statement.period_end | format_date("%Y", loc) }} {{ tenancy.tenant_number }}</dd>
      </dl>
      {% else %}
      <p class="box-title">Erstattung</p>
      <dl>
        <dt>Betrag</dt><dd>{{ money(balance | abs) }}</dd>
        <dt>Überweisung bis</dt><dd>{{ day(due_date) }}</dd>
        <dt>Konto</dt><dd>das uns bekannte Konto</dd>
      </dl>
      {% endif %}
    </div>
    <table class="totals">
      <tr><th scope="row">Betriebskosten</th><td class="num">{{ money(operating) }}</td></tr>
      {% if heating %}<tr><th scope="row">{{ heating.label }}</th><td class="num">{{ money(heating_amount) }}</td></tr>{% endif %}
      <tr class="grand"><th scope="row">Ihre Kosten gesamt</th><td class="num">{{ money(total) }}</td></tr>
      <tr><th scope="row">abzgl. Vorauszahlungen ({{ statement.months_paid }} × {{ money(statement.monthly_prepayment) }})</th><td class="num">−{{ money(prepaid) }}</td></tr>
      <tr class="balance{{ ' due' if balance > 0 else '' }}"><th scope="row">{% if balance > 0 %}Nachzahlung{% elif balance < 0 %}Guthaben{% else %}Ausgeglichen{% endif %}</th><td class="num">{{ money(balance | abs) }}</td></tr>
    </table>
  </div>
</section>

{% if statement.new_monthly_prepayment and statement.new_monthly_prepayment != statement.monthly_prepayment %}
<section class="prepayment-section">
  <h2 class="section-title"><span>4</span>Anpassung der Vorauszahlungen</h2>
  <div class="prepayment">
    <div class="change">
      <p class="old">{{ money(statement.monthly_prepayment) }}</p>
      <p class="new">{{ money(statement.new_monthly_prepayment) }}</p>
    </div>
    <p>
      Auf Grundlage dieser Abrechnung passen wir Ihre monatliche Vorauszahlung auf die Betriebs- und Heizkosten an.
      Ab dem <strong>{{ day(statement.new_prepayment_from) }}</strong> beträgt sie {{ money(statement.new_monthly_prepayment) }}
      statt bisher {{ money(statement.monthly_prepayment) }}. Bitte passen Sie einen Dauerauftrag entsprechend an.
    </p>
  </div>
</section>
{% endif %}

<section class="hints">
  <h2 class="section-title"><span>{{ 5 if (statement.new_monthly_prepayment and statement.new_monthly_prepayment != statement.monthly_prepayment) else 4 }}</span>Hinweise</h2>
  <ul class="notes">
    <li><strong>Belegeinsicht:</strong> Die Rechnungen und Verträge zu dieser Abrechnung können Sie nach Terminvereinbarung zu unseren Bürozeiten ({{ manager.office_hours }}) einsehen.</li>
    <li><strong>Einwendungen</strong> gegen diese Abrechnung teilen Sie uns bitte spätestens bis zum Ablauf des zwölften Monats nach Zugang schriftlich mit.</li>
    {% if ns.service > 0 or ns.craft > 0 %}
    <li><strong>Steuerermäßigung (§ 35a EStG):</strong> Von Ihren Kosten entfallen {{ money(ns.service | round(2)) }} auf haushaltsnahe Dienstleistungen und {{ money(ns.craft | round(2)) }} auf Handwerkerleistungen. Eine Bescheinigung für Ihre Steuererklärung senden wir Ihnen auf Anfrage zu.</li>
    {% endif %}
  </ul>
</section>

<section class="closing">
  <p>Bei Fragen zu dieser Abrechnung erreichen Sie uns unter {{ contact.phone }}.</p>
  <p class="greeting">Mit freundlichen Grüßen</p>
  <p class="company">{{ manager.name }}</p>
  <p class="signer">i. A. {{ contact.name }}</p>
  <p class="machine">Dieses Schreiben wurde maschinell erstellt und ist ohne Unterschrift gültig.</p>
  {% if heating %}<p class="enclosures"><strong>Anlage:</strong> Heiz- und Warmwasserkostenabrechnung des Messdienstes</p>{% endif %}
</section>

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": {
    "manager": {
      "name": "Brookhoff Hausverwaltung GmbH",
      "short_name": "Brookhoff Hausverwaltung",
      "street": "Am Kanalufer 9",
      "postcode": "22303",
      "city": "Hamburg",
      "phone": "+49 40 66969 040",
      "email": "abrechnung@brookhoff.example.com",
      "website": "brookhoff.example.com",
      "register": "Amtsgericht Hamburg, HRB 123456",
      "managing_director": "Jasper Brookhoff",
      "vat_id": "DE123456789",
      "iban": "DE00 EXMP 0000 0045 6789 01",
      "bic": "EXMPDEHHXXX",
      "office_hours": "Mo–Do 9–16 Uhr, Fr 9–13 Uhr"
    },
    "contact": {
      "name": "Merle Tiedemann",
      "phone": "+49 40 66969 047",
      "email": "m.tiedemann@brookhoff.example.com"
    },
    "landlord": "Eigentümergemeinschaft Holunderstieg 12–14",
    "property": {
      "reference": "HOL-12",
      "address": "Holunderstieg 12–14, 22083 Hamburg",
      "units": 18
    },
    "tenancy": {
      "tenant_number": "M-0314-07",
      "unit": "Holunderstieg 14, 3. OG links (Whg. 07)",
      "tenants": [
        {
          "salutation": "Frau",
          "first_name": "Leonie",
          "last_name": "Hartwig"
        },
        {
          "salutation": "Herr",
          "first_name": "Can",
          "last_name": "Yilmaz"
        }
      ],
      "street": "Holunderstieg 14",
      "postcode": "22083",
      "city": "Hamburg"
    },
    "statement": {
      "date": "2026-09-21",
      "period_start": "2025-01-01",
      "period_end": "2025-12-31",
      "payment_days": 30,
      "monthly_prepayment": 215,
      "months_paid": 12,
      "new_monthly_prepayment": 225,
      "new_prepayment_from": "2026-11-01"
    },
    "allocation_keys": [
      {
        "id": "area",
        "label": "Wohnfläche",
        "unit": "m²",
        "decimals": 2,
        "total": 1386.5,
        "share": 74.6
      },
      {
        "id": "water",
        "label": "Wasserverbrauch",
        "unit": "m³",
        "decimals": 1,
        "total": 1536,
        "share": 84.6
      }
    ],
    "costs": [
      {
        "name": "Grundsteuer",
        "total": 3186.4,
        "key": "area"
      },
      {
        "name": "Wasserversorgung",
        "total": 3456,
        "key": "water"
      }
    ],
    "heating": {
      "label": "Heiz- und Warmwasserkosten",
      "note": "lt. Einzelabrechnung des Messdienstes",
      "amount": 846.27
    }
  },
  "output": {
    "format": "pdf",
    "filename": "utility-cost-statement.pdf"
  }
}'