factur-x

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.

Profiles
ProfileLine itemsTypical use
MINIMUM–Booking aid; totals only
BASIC WL–Document level with VAT and payment
BASICYesStandard commercial invoices
EN 16931YesThe full European standard
EXTENDEDYesComplex cross-industry scenarios
Flavors
FlavorRegionOutput
Factur-XFrance / EUPDF/A-3 with XML
ZUGFeRDGermanyPDF/A-3 with XML
XRechnungGermany, public sectorXML only
Chrono ProBelgiumPDF/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