Documentation
The Invoice model
Afraid of the official paperwork? Don't be. EN-16931 defines a long list of fields, but you need a
handful. Fill in the few that are mandatory, add detail only where your case calls for it, and the
library computes every total and writes the conformant XML underneath. Each field maps to a real
business term (its BT- / BG- code lives in the type, for when you ever need it).
The smallest invoice
This is already a complete, conformant invoice. Everything else on this page is optional.
import { type Invoice } from "@jasy/zugferd";
const invoice: Invoice = {
number: "INV-001",
issueDate: "2026-06-21", // ISO date
currency: "EUR",
seller: {
name: "Northwind GmbH",
vatId: "DE265013614",
address: { city: "Berlin", postCode: "10115", country: "DE" },
},
buyer: {
name: "Globex Ltd",
address: { city: "Munich", postCode: "80331", country: "DE" },
},
lines: [
{
name: "Consulting",
quantity: 8,
unit: "HUR",
netUnitPrice: 120,
vat: { category: "S", ratePercent: 19 },
},
],
};
number, issueDate, currency, seller, buyer and at least one line - that is the whole
requirement. Hand it to renderZugferd and out come the PDF and the XML.
Seller and buyer
Both parties take the same shape. A name and an address (only the country is required) are
mandatory; everything else is opt-in.
seller: {
name: "Northwind GmbH", // registered legal name
vatId: "DE265013614", // needed whenever you charge VAT
address: { line1: "Hauptstrasse 1", city: "Berlin", postCode: "10115", country: "DE" },
contact: { name: "A. Schmidt", email: "billing@northwind.de", phone: "+49 30 123456" },
electronicAddress: "billing@northwind.de", // required for XRechnung / Peppol
},
Other handy fields: tradingName, taxNumber (Steuernummer), legalRegistrationId
(Handelsregisternummer) and additionalLegalInfo (the legal footer line). The buyer mirrors all of
it.
Lines
Each line names an item, a quantity in a unit, the net unit price and its VAT. The library multiplies and sums - you never add up a line yourself.
lines: [
{
name: "Consulting",
description: "On-site workshop", // optional
quantity: 8,
unit: "HUR", // UN/ECE Rec 20 - "HUR" hours, "C62" pieces, "DAY", "KGM" kg, "MTR" metre ...
netUnitPrice: 120,
vat: { category: "S", ratePercent: 19 },
},
{
name: "License",
quantity: 1,
unit: "C62",
netUnitPrice: 480,
vat: { category: "S", ratePercent: 19 },
},
],
More per line when you need it: sellerItemId / buyerItemId / standardItemId (a GTIN),
priceBaseQuantity (a price "per 100"), per-line allowancesCharges, and a free-text note.
VAT
VAT sits on the line (and on any allowance or charge): a category plus its rate.
| Category | Meaning | Rate |
|---|---|---|
S | Standard rate | the percent, e.g. 19 |
Z | Zero-rated | 0 |
E | Exempt from VAT | omit |
AE | Reverse charge | omit |
K | Intra-community supply (EU) | omit |
G | Export outside the EU | omit |
O | Outside the scope of VAT | omit |
For the non-standard categories EN-16931 wants a reason. Give it once per category:
const invoice: Invoice = {
// ... every line uses { category: "AE" } ...
vatExemptionReasons: {
AE: {
text: "Reverse charge - Steuerschuldnerschaft des Leistungsempfängers (§13b UStG)",
code: "VATEX-EU-AE",
},
},
};
The optional extras
Reach for these as your case calls for them. None are required.
Dates and references
dueDate: "2026-07-05",
buyerReference: "04011000-12345-34", // the Leitweg-ID - MANDATORY for XRechnung (B2G)
purchaseOrderRef: "PO-7782",
contractRef: "C-2026-09",
notes: ["Thank you for your business."],
Payment - so the buyer knows where and how to pay:
payment: {
meansCode: "58", // SEPA credit transfer (UNCL 4461); "30" is a plain credit transfer
iban: "DE89370400440532013000",
bic: "COBADEFFXXX",
accountName: "Northwind GmbH",
terms: "Payable within 14 days, net.",
},
Document-level discounts or charges - applied after the line sum, each with its own VAT:
allowancesCharges: [
{ isCharge: false, amount: 50, reason: "Loyalty discount", vat: { category: "S", ratePercent: 19 } },
{ isCharge: true, amount: 12, reason: "Shipping", vat: { category: "S", ratePercent: 19 } },
],
And a few more: delivery (a date and a deliver-to address), payeeName (when payment goes to
someone other than the seller), paidAmount (already paid, subtracted to give the amount due) and
type (380 a commercial invoice, 381 a credit note).
That is the whole model. Start from the smallest invoice and add only what you need - the totals and the XML stay correct underneath, every time.