Skip to content

210 × 297 mm

Invoices

Freelancer invoice

A 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.

A4 portraitLocale en-GBHTML + JinjaHeader & footer

Opens Dynamic Document API with this template preloaded in a free workspace.

Template language features

  • Loops
  • Conditionals
  • Currency formatting
  • Date formatting
  • Number formatting
  • QR code
  • Header & footer
  • Page numbers
  • Repeating table headers
  • columns

Filters such as format_currency and qrcode are described in the template language reference.

Variables

Derived from the sample data: 6 top-level fields, 65 paths in total. Send the same shape as data.

PathTypeExample
invoiceobject
invoice.numberstring"TR-2026-031"
invoice.issue_datedate"2026-09-14"
invoice.due_datedate"2026-10-14"
invoice.currencystring"GBP"
invoice.order_referencestring"PO-2291"
invoice.payment_termsstring"Net 30 days"
invoice.invoice_periodobject
invoice.invoice_period.startdate"2026-08-17"
invoice.invoice_period.enddate"2026-09-11"
invoice.deliveryobject
invoice.delivery.datedate"2026-09-11"
invoice.sellerobject
invoice.seller.namestring"Tamsin Rook"
invoice.seller.vat_idstring"GB246813579"
invoice.seller.electronic_addressobject
invoice.seller.electronic_address.idstring"hello@tamsinrook.example.com"
invoice.seller.electronic_address.schemestring"EM"
invoice.seller.addressobject
invoice.seller.address.line1string"Flat 3, 18 Wickham Rise"
invoice.seller.address.citystring"Brighton"
invoice.seller.address.postcodestring"BN1 4QX"
invoice.seller.address.countrystring"GB"
invoice.seller.contactobject
invoice.seller.contact.namestring"Tamsin Rook"
invoice.seller.contact.phonestring"+44 20 7946 0418"
invoice.seller.contact.emailstring"hello@tamsinrook.example.com"
invoice.buyerobject
invoice.buyer.namestring"Pebblestone Homeware Ltd"
invoice.buyer.vat_idstring"GB864209753"
invoice.buyer.electronic_addressobject
invoice.buyer.electronic_address.idstring"accounts@pebblestone.example.com"
invoice.buyer.electronic_address.schemestring"EM"
invoice.buyer.addressobject
invoice.buyer.address.line1string"Unit 7, Ropewalk Yard"
invoice.buyer.address.line2string"12 Chandler's Lane"
invoice.buyer.address.citystring"Bristol"
invoice.buyer.address.postcodestring"BS2 0QT"
invoice.buyer.address.countrystring"GB"
invoice.buyer.contactobject
invoice.buyer.contact.namestring"Ollie Marchbank"
invoice.paymentobject
invoice.payment.means_codestring"30"
invoice.payment.remittance_informationstring"TR-2026-031"
invoice.payment.credit_transfersarray<object> · 1
invoice.payment.credit_transfers[].account_idstring"GB00EXMP40221812345678"
invoice.payment.credit_transfers[].account_namestring"Tamsin Rook"
invoice.payment.credit_transfers[].bicstring"EXMPGB2L"
invoice.linesarray<object> · 5
invoice.lines[].quantitystring"1"
invoice.lines[].unitstring"LS"
invoice.lines[].net_amountstring"1200.00"
invoice.lines[].priceobject
invoice.lines[].price.netstring"1200.00"
invoice.lines[].taxobject
invoice.lines[].tax.categorystring"S"
invoice.lines[].tax.ratestring"20"
invoice.lines[].itemobject
invoice.lines[].item.namestring"Brand voice guide"
invoice.lines[].item.descriptionstring"Flat fee · a 12-page guide to your tone, vocab…"
taglinestring"Copywriting & brand voice"
websitestring"tamsinrook.example.com"
bank_namestring"Harbourline Bank"
payment_linkstring"https://pay.example.com/tamsinrook/TR-2026-031"
thank_you_notestring"Thank you, Ollie! It was a joy to find the wor…"

Sample data

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

data.json
{
  "invoice": {
    "number": "TR-2026-031",
    "issue_date": "2026-09-14",
    "due_date": "2026-10-14",
    "currency": "GBP",
    "order_reference": "PO-2291",
    "payment_terms": "Net 30 days",
    "invoice_period": {
      "start": "2026-08-17",
      "end": "2026-09-11"
    },
    "delivery": {
      "date": "2026-09-11"
    },
    "seller": {
      "name": "Tamsin Rook",
      "vat_id": "GB246813579",
      "electronic_address": {
        "id": "hello@tamsinrook.example.com",
        "scheme": "EM"
      },
      "address": {
        "line1": "Flat 3, 18 Wickham Rise",
        "city": "Brighton",
        "postcode": "BN1 4QX",
        "country": "GB"
      },
      "contact": {
        "name": "Tamsin Rook",
        "phone": "+44 20 7946 0418",
        "email": "hello@tamsinrook.example.com"
      }
    },
    "buyer": {
      "name": "Pebblestone Homeware Ltd",
      "vat_id": "GB864209753",
      "electronic_address": {
        "id": "accounts@pebblestone.example.com",
        "scheme": "EM"
      },
      "address": {
        "line1": "Unit 7, Ropewalk Yard",
        "line2": "12 Chandler's Lane",
        "city": "Bristol",
        "postcode": "BS2 0QT",
        "country": "GB"
      },
      "contact": {
        "name": "Ollie Marchbank"
      }
    },
    "payment": {
      "means_code": "30",
      "remittance_information": "TR-2026-031",
      "credit_transfers": [
        {
          "account_id": "GB00EXMP40221812345678",
          "account_name": "Tamsin Rook",
          "bic": "EXMPGB2L"
        }
      ]
    },
    "lines": [
      {
        "quantity": "1",
        "unit": "LS",
        "net_amount": "1200.00",
        "price": {
          "net": "1200.00"
        },
        "tax": {
          "category": "S",
          "rate": "20"
        },
        "item": {
          "name": "Brand voice guide",
          "description": "Flat fee · a 12-page guide to your tone, vocabulary and style"
        }
      },
      {
        "quantity": "3",
        "unit": "DAY",
        "net_amount": "1260.00",
        "price": {
          "net": "420.00"
        },
        "tax": {
          "category": "S",
          "rate": "20"
        },
        "item": {
          "name": "Website copy",
          "description": "Day rate · Home, About, Shop, Care, FAQ and Contact pages"
        }
      },
      {
        "quantity": "4800",
        "unit": "D68",
        "net_amount": "720.00",
        "price": {
          "net": "0.15"
        },
        "tax": {
          "category": "S",
          "rate": "20"
        },
        "item": {
          "name": "Product descriptions",
          "description": "Per word · 40 products for the autumn range"
        }
      },
      {
        "quantity": "1",
        "unit": "LS",
        "net_amount": "450.00",
        "price": {
          "net": "450.00"
        },
        "tax": {
          "category": "S",
          "rate": "20"
        },
        "item": {
          "name": "Launch email sequence",
          "description": "Flat fee · three welcome emails with two subject lines each"
        }
      },
      {
        "quantity": "3.5",
        "unit": "HUR",
        "net_amount": "192.50",
        "price": {
          "net": "55.00"
        },
        "tax": {
          "category": "S",
          "rate": "20"
        },
        "item": {
          "name": "Revisions and calls",
          "description": "Hourly · an extra review round and two calls with your team"
        }
      }
    ]
  },
  "tagline": "Copywriting & brand voice",
  "website": "tamsinrook.example.com",
  "bank_name": "Harbourline Bank",
  "payment_link": "https://pay.example.com/tamsinrook/TR-2026-031",
  "thank_you_note": "Thank you, Ollie! It was a joy to find the words for the autumn range. If anything needs a small tweak before launch day, just drop me a line: little fixes are always on me."
}

Source

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

<div class="masthead">
  <div class="brand">
    <img class="logo" src="data:image/png;base64,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" alt="{{ invoice.seller.name }} logo">
    <div>
      <h1>{{ invoice.seller.name }}<span class="accent">.</span></h1>
      <p class="tagline">{{ tagline }}</p>
    </div>
  </div>
  <div class="doc-info">
    <p class="label">Invoice</p>
    <p class="doc-number">{{ invoice.number }}</p>
    <p><span class="muted">Due</span> <strong>{{ invoice.due_date | format_date("long", "en-GB") }}</strong></p>
  </div>
</div>

<div class="parties">
  <div>
    <h2 class="label">Bill to</h2>
    <p><strong>{{ invoice.buyer.name }}</strong></p>
    {% if invoice.buyer.contact.name %}<p>Attn. {{ invoice.buyer.contact.name }}</p>{% endif %}
    <p>{{ invoice.buyer.address.line1 }}</p>
    {% if invoice.buyer.address.line2 %}<p>{{ invoice.buyer.address.line2 }}</p>{% endif %}
    <p>{{ invoice.buyer.address.city }} {{ invoice.buyer.address.postcode }}</p>
  </div>
  <div>
    <h2 class="label">From</h2>
    <p><strong>{{ invoice.seller.name }}</strong></p>
    <p>{{ invoice.seller.address.line1 }}</p>
    <p>{{ invoice.seller.address.city }} {{ invoice.seller.address.postcode }}</p>
    <p class="muted">VAT {{ invoice.seller.vat_id }}</p>
  </div>
  <div>
    <h2 class="label">Details</h2>
    <table class="facts">
      <tbody>
        <tr><th scope="row">Issued</th><td>{{ invoice.issue_date | format_date("long", "en-GB") }}</td></tr>
        {% if invoice.order_reference %}<tr><th scope="row">Your PO</th><td>{{ invoice.order_reference }}</td></tr>{% endif %}
        {% if invoice.invoice_period %}<tr><th scope="row">Period</th><td>{{ invoice.invoice_period.start | format_date("d MMM", "en-GB") }} – {{ invoice.invoice_period.end | format_date("d MMM y", "en-GB") }}</td></tr>{% endif %}
        <tr><th scope="row">Terms</th><td>{{ invoice.payment_terms }}</td></tr>
      </tbody>
    </table>
  </div>
</div>

<table class="items">
  <thead>
    <tr>
      <th scope="col">Service</th>
      <th class="qty" scope="col">Qty</th>
      <th class="price" scope="col">Rate</th>
      <th class="amount" scope="col">Amount</th>
    </tr>
  </thead>
  <tbody>
    {% for line in invoice.lines %}
    <tr>
      <td>
        <p class="item-name">{{ line.item.name }}</p>
        {% if line.item.description %}<p class="item-note">{{ line.item.description }}</p>{% endif %}
      </td>
      <td class="qty">{{ line.quantity | format_number("en-GB") }}</td>
      <td class="price">{{ line.price.net | format_currency(invoice.currency, "en-GB") }}</td>
      <td class="amount">{{ render.invoice.lines[loop.index0].net_amount | format_currency(invoice.currency, "en-GB") }}</td>
    </tr>
    {% endfor %}
  </tbody>
</table>

<div class="closing">
  <div>
    <h2>Thank you!</h2>
    <p>{{ thank_you_note }}</p>
    <p class="muted">— <em>{{ invoice.seller.contact.name }}</em></p>
  </div>
  <table class="totals">
    <tbody>
      <tr><th scope="row">Subtotal</th><td>{{ render.invoice.totals.line_total | format_currency(invoice.currency, "en-GB") }}</td></tr>
      {% for vat in render.invoice.vat_breakdown %}
      <tr><th scope="row">VAT {{ vat.rate | format_number("en-GB") }}%</th><td>{{ vat.tax | format_currency(invoice.currency, "en-GB") }}</td></tr>
      {% endfor %}
      <tr class="total-due"><th scope="row">Total due</th><td>{{ render.invoice.totals.due_payable | format_currency(invoice.currency, "en-GB") }}</td></tr>
    </tbody>
  </table>
</div>

<div class="payment">
  <div>
    <h2>Pay by bank transfer</h2>
    <table class="facts">
      <tbody>
        <tr><th scope="row">Account name</th><td>{{ invoice.payment.credit_transfers[0].account_name }}</td></tr>
        {% if bank_name %}<tr><th scope="row">Bank</th><td>{{ bank_name }}</td></tr>{% endif %}
        <tr><th scope="row">IBAN</th><td><strong>{{ invoice.payment.credit_transfers[0].account_id }}</strong></td></tr>
        <tr><th scope="row">BIC</th><td>{{ invoice.payment.credit_transfers[0].bic }}</td></tr>
        <tr><th scope="row">Reference</th><td><strong>{{ invoice.payment.remittance_information }}</strong></td></tr>
      </tbody>
    </table>
  </div>
  {% if payment_link %}
  <div class="pay-link">
    <p class="qr">{{ payment_link | qrcode(size="25mm", color="#1b1c24", background="#fdf0eb", alt="QR code to pay by card online") }}</p>
    <p>Or scan to pay by card</p>
  </div>
  {% endif %}
</div>

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": "TR-2026-031",
      "issue_date": "2026-09-14",
      "due_date": "2026-10-14",
      "currency": "GBP",
      "order_reference": "PO-2291",
      "payment_terms": "Net 30 days",
      "invoice_period": {
        "start": "2026-08-17",
        "end": "2026-09-11"
      },
      "delivery": {
        "date": "2026-09-11"
      },
      "seller": {
        "name": "Tamsin Rook",
        "vat_id": "GB246813579",
        "electronic_address": {
          "id": "hello@tamsinrook.example.com",
          "scheme": "EM"
        },
        "address": {
          "line1": "Flat 3, 18 Wickham Rise",
          "city": "Brighton",
          "postcode": "BN1 4QX",
          "country": "GB"
        },
        "contact": {
          "name": "Tamsin Rook",
          "phone": "+44 20 7946 0418",
          "email": "hello@tamsinrook.example.com"
        }
      },
      "buyer": {
        "name": "Pebblestone Homeware Ltd",
        "vat_id": "GB864209753",
        "electronic_address": {
          "id": "accounts@pebblestone.example.com",
          "scheme": "EM"
        },
        "address": {
          "line1": "Unit 7, Ropewalk Yard",
          "line2": "12 Chandler'\''s Lane",
          "city": "Bristol",
          "postcode": "BS2 0QT",
          "country": "GB"
        },
        "contact": {
          "name": "Ollie Marchbank"
        }
      },
      "payment": {
        "means_code": "30",
        "remittance_information": "TR-2026-031",
        "credit_transfers": [
          {
            "account_id": "GB00EXMP40221812345678",
            "account_name": "Tamsin Rook",
            "bic": "EXMPGB2L"
          }
        ]
      },
      "lines": [
        {
          "quantity": "1",
          "unit": "LS",
          "net_amount": "1200.00",
          "price": {
            "net": "1200.00"
          },
          "tax": {
            "category": "S",
            "rate": "20"
          },
          "item": {
            "name": "Brand voice guide",
            "description": "Flat fee · a 12-page guide to your tone, vocabulary and style"
          }
        },
        {
          "quantity": "3",
          "unit": "DAY",
          "net_amount": "1260.00",
          "price": {
            "net": "420.00"
          },
          "tax": {
            "category": "S",
            "rate": "20"
          },
          "item": {
            "name": "Website copy",
            "description": "Day rate · Home, About, Shop, Care, FAQ and Contact pages"
          }
        }
      ]
    },
    "tagline": "Copywriting & brand voice",
    "website": "tamsinrook.example.com",
    "bank_name": "Harbourline Bank",
    "payment_link": "https://pay.example.com/tamsinrook/TR-2026-031",
    "thank_you_note": "Thank you, Ollie! It was a joy to find the words for the autumn range. If anything needs a small tweak before launch day, just drop me a line: little fixes are always on me."
  },
  "output": {
    "format": "pdf",
    "filename": "invoice-freelancer.pdf"
  }
}'