@lucaapp/zugferd-ts
v0.1.0
Published
Pure-TypeScript ZUGFeRD 2.x / Factur-X + XRechnung e-invoice library — generate, embed (PDF/A-3b), parse, and validate (XSD + EN16931 Schematron) with zero native/JVM/subprocess dependencies
Readme
ZUGFeRD-ts
A pure-TypeScript / Node.js library for the German/EU eRechnung (e-invoice) family: ZUGFeRD 2.x / Factur-X (hybrid PDF/A-3 + CII XML) and XRechnung (XML-only B2G, UBL and CII syntaxes). Generates compliant invoice XML, embeds it into PDFs (PDF/A-3b), parses it back, and validates — with zero native, JVM, subprocess, or commercial-SDK dependencies in the shipped package.
Install
npm install @lucaapp/zugferd-tsSelf-contained: zero native build steps, no JVM, no subprocess, no commercial SDK. Dual ESM + CJS with native TypeScript types. Node 20+.
Usage
import { Decimal } from 'decimal.js';
import {
serializeToXml, serializeToUbl, serializeCiiXrechnung, // generate
ZugferdProfile, InvoiceType, TaxCategoryCode,
embedXml, extractXml, // PDF/A-3b embed / extract
parseCiiXml, parseUblXml, receiveInvoice, // parse / unified receive
validateXml, validateUblXml, validatePdfA, // validate
} from '@lucaapp/zugferd-ts';
import type { Invoice } from '@lucaapp/zugferd-ts';
// A complete, EN16931-valid invoice (standard-rated, 19% VAT)
const invoice: Invoice = {
header: {
id: 'RE-2026-000777',
typeCode: InvoiceType.INVOICE,
issueDate: new Date('2026-06-09'),
deliveryDate: new Date('2026-06-09'), // BT-72 (required by BR-FX-EN-04)
currency: 'EUR',
},
seller: {
name: 'culture4life GmbH',
address: { street: 'Charlottenstrasse 59', city: 'Berlin', zip: '10117', countryCode: 'DE' },
vatId: 'DE321285217',
electronicAddress: { value: '[email protected]', scheme: 'EM' },
bankDetails: { iban: 'DE02120300000000202051', bic: 'BYLADEM1001' },
},
buyer: {
name: 'Hotel Beispiel GmbH',
address: { street: 'Hotelstrasse 15', city: 'Muenchen', zip: '80333', countryCode: 'DE' },
vatId: 'DE123456789',
electronicAddress: { value: '[email protected]', scheme: 'EM' },
},
lines: [{
id: '1',
product: { name: 'luca Service Fees', unitCode: 'C62', vatCategoryCode: TaxCategoryCode.S, vatRatePercent: new Decimal('19') },
quantity: new Decimal('1'),
unitPrice: new Decimal('1000.00'),
}],
taxBreakdowns: [{
categoryCode: TaxCategoryCode.S, ratePercent: new Decimal('19'),
basisAmount: new Decimal('1000.00'), calculatedAmount: new Decimal('190.00'),
}],
paymentMeans: { typeCode: '30', payeeIban: 'DE02120300000000202051', payeeBic: 'BYLADEM1001' },
paymentTerms: { description: 'Zahlbar 14 Tage netto', dueDate: new Date('2026-06-23') }, // BT-9 (BR-CO-25)
};
// Generate CII (Factur-X / ZUGFeRD) for any profile
const ciiXml = serializeToXml(invoice, ZugferdProfile.EN16931);
// Generate XRechnung (UBL 2.1 or dedicated CII variant)
const ublXml = serializeToUbl(invoice);
// Embed into an existing PDF → PDF/A-3b, then read it back
const pdf = await embedXml(existingPdfBytes, ciiXml);
// Unified receive: a ZUGFeRD PDF or a standalone XRechnung XML → typed Invoice
const parsed = await receiveInvoice(pdf); // or receiveInvoice(xmlString)
// Validate
const xml = await validateXml(ciiXml); // CII XSD + EN16931 Schematron
const ubl = await validateUblXml(ublXml); // UBL 2.1 XSD
const pdfa = await validatePdfA(pdf); // PDF/A-3b structural (verapdf-lite)
// → { valid: boolean, issues: [{ ruleId, severity, message, ... }] }Validation
The shipped library validates with pure-JS / pure-WASM tooling only:
| Layer | Tool | Bundled |
|---|---|---|
| XSD (Factur-X 1.08, all profiles + UBL 2.1) | xmllint-wasm (libxml2 → WASM) | yes |
| EN16931 Schematron | node-schematron (pure JS) | yes |
| PDF/A-3b structural (ZUGFeRD ~22-rule subset) | verapdf-lite (in-house, pdf-lib) | yes |
All five CII profiles (MINIMUM, BASICWL, BASIC, EN16931, EXTENDED) are XSD-compliant against the vendored Factur-X 1.08 schema set; the EN16931 profile additionally passes the EN16931 Schematron.
KoSIT XRechnung BR-DE validation (dev/CI only)
KoSIT's XRechnung BR-DE business rules are distributed as Schematron compiled to a Saxon stylesheet. Running them requires saxon-js, which is proprietary (Saxonica) and therefore cannot be bundled with this Apache-2.0 library.
BR-DE validation is consequently a development / CI-only gate. saxon-js and
xslt3 are devDependencies only and are never imported by src/. Run it with:
node scripts/validate-xrechnung-ci.mjs [path/to/cii-xrechnung.xml]It defaults to the dedicated CII XRechnung golden
(tests/golden/cii-xrechnung/invoice.xml), runs the compiled KoSIT Schematron in
scripts/ci-assets/, prints every failed assertion (BR-DE / PEPPOL-EN16931
rule id + message), and exits non-zero when any fatal assert fails.
The KoSIT Schematron source and compiled SEF vendored under scripts/ci-assets/
are attributed in NOTICE.
Compliance evidence
Output is checked against independent reference validators, not just the bundled pure-JS tooling:
| Validator | Engine | Result on generated EN16931 output |
|---|---|---|
| validateXml (bundled) | node-schematron + libxml2/WASM | 0 errors |
| Mustangproject CLI 2.23.1 | Java (KoSIT + veraPDF) | XML:valid, PDF/A-3b isCompliant=true |
| EU ITB / EN16931 reference validator | European Commission, hosted | SUCCESS, 0 errors |
The embedded PDF/A-3b container validates as flavour=3b, isCompliant=true; the
CII payload passes the EN16931 Schematron across all three engines.
