Open source · TypeScript · EUPL-1.2
Factur-X, ZUGFeRD and XRechnung invoices in TypeScript.
Turn any PDF into a compliant e-invoice. Generate EN 16931 XML from a typed object, validate it against the official schemas and embed it into PDF/A-3 – or read it back out. For Node.js and Deno.
$ npm install @stackforge-eu/factur-x- 5 profiles, MINIMUM to EXTENDED
- XSD validation via WebAssembly
- 2 runtime dependencies
invoice.ts
import { embedFacturX, Profile, Flavor } from "@stackforge-eu/factur-x";
const { pdf } = await embedFacturX({
pdf: await readFile("invoice.pdf"),
input: {
document: { id: "INV-2026-0042", issueDate: "2026-11-14" },
seller: { name: "Musterfirma GmbH", /* … */ },
buyer: { name: "Beispiel AG", /* … */ },
lines: [{ id: "1", name: "Consulting", quantity: 10,
unitPrice: 150, vatRatePercent: 19 }],
totals: { taxBasisTotal: 1500, taxTotal: 285,
grandTotal: 1785, currency: "EUR", /* … */ },
},
profile: Profile.EN16931,
flavor: Flavor.ZUGFERD,
});
await writeFile("invoice-zugferd.pdf", pdf);Live demo
Create, read and validate an e-invoice right here.
The demo runs the npm package inside this browser tab. Nothing is uploaded – your PDF and invoice data never leave your device.
Loading the demo…
Features
Everything between your invoice data and a compliant file.
Typed input, no XML by hand
Describe the invoice as a plain TypeScript object. The library writes UN/CEFACT Cross Industry Invoice XML for Factur-X 1.09 / ZUGFeRD 2.5.
Profile-aware validation
Missing a field that EN 16931 requires? You get the exact path, such as seller.address.country, before any XML is written.
Official XSD schemas included
Validate generated or received XML against the Factur-X schemas with libxml2 compiled to WebAssembly. No Java, no native build.
PDF/A-3 embedding
Attaches the XML to your existing PDF with the required XMP metadata, AF relationship and sRGB output intent, and warns about fonts that are not embedded.
Extraction
Read the XML back out of any Factur-X or ZUGFeRD PDF, including the detected profile – the starting point for processing incoming invoices.
XRechnung for German B2G
The same input object produces standalone XRechnung XML with Leitweg-ID and PEPPOL business process, ready for ZRE or OZG-RE.
Quick start
Three calls cover most use cases.
Read an incoming invoice
import { extractXml } from
"@stackforge-eu/factur-x";
const { xml, filename, profile } =
await extractXml(pdfBytes);
// "factur-x.xml", "EN16931"Validate before sending
const check = validateInput(
invoice, Profile.EN16931);
const xml = buildXml(
invoice, Profile.EN16931);
const xsd = await validateXsd(
xml, Profile.EN16931);XRechnung without a PDF
import { toXRechnung } from
"@stackforge-eu/factur-x";
const { xml } = toXRechnung({
document: {
id: "INV-2026-0042",
buyerReference: "04011000-12345-67",
}, /* … */
});Deno: import { embedFacturX } from "jsr:@stackforge-eu/factur-x"; · Full reference in the README and the input object specification.
Profiles and flavors
One input object, every level of the standard.
| Profile | Line items | Typical use |
|---|---|---|
| MINIMUM | – | Booking aid; totals only |
| BASIC WL | – | Document level with VAT and payment |
| BASIC | Yes | Standard commercial invoices |
| EN 16931 | Yes | The full European standard |
| EXTENDED | Yes | Complex cross-industry scenarios |
| Flavor | Region | Output |
|---|---|---|
| Factur-X | France / EU | PDF/A-3 with XML |
| ZUGFeRD | Germany | PDF/A-3 with XML |
| XRechnung | Germany, public sector | XML only |
| Chrono Pro | Belgium | PDF/A-3 with XML |
FAQ
Common questions
What is the difference between Factur-X, ZUGFeRD and XRechnung?
Factur-X (France) and ZUGFeRD (Germany) are the same hybrid format: a PDF/A-3 that a person can read, with a UN/CEFACT CII XML file embedded for machines. XRechnung is the German public-sector format and consists of the XML alone, without a PDF. All three implement the European standard EN 16931.
Is my invoice uploaded when I use the demo?
No. The demo runs the library inside your browser tab. PDFs, XML and form data are processed in memory and never sent to a server. The page sets no cookies and loads nothing from other companies; visits are counted with a self-hosted, cookieless Umami.
Which validation does the library perform?
It checks your input against the requirements of the chosen profile before generating XML, and it can validate the generated XML against the official Factur-X XSD schemas using libxml2 compiled to WebAssembly. The demo additionally checks the EN 16931 calculation rules for totals.
Does it produce PDF/A-3 files?
The library attaches the XML, writes the Factur-X XMP metadata and adds an sRGB output intent. The source PDF must itself be PDF/A-capable, for example with all fonts embedded. The library warns when it detects fonts that are not embedded.
Does the library run in the browser?
It targets Node.js 18+ and Deno 2+. This page bundles it for the browser with a few small shims for Node built-ins; the source of this website is public and shows how.
Under which licence is the library published?
EUPL-1.2, the European Union Public Licence. It is free to use, including in commercial products.
More in the privacy policy and the source of this website.
Add e-invoicing to your app today.
One install, no Java, no native build. A star helps others find it.
$ npm install @stackforge-eu/factur-x