npm library
@conformo/toolkit is the whole of Conformo as functions: create, validate, convert, parse, explain a rule, look up a country's requirements. It runs in Node 20+ and in the browser, with no account and no server. The CLI, the MCP server and the HTTP API are thin layers over it.
npm install @conformo/toolkitCreate and check an XRechnung
The invoice is the EN 16931 model. XRechnung adds a buyer reference (BT-10, the Leitweg-ID for public authorities), a seller contact (BG-6) and electronic addresses.
import { createXml, createPdf, validate, convert, parse, explainRule, getRequirements, InvoiceInputError } from '@conformo/toolkit';
const invoice = {
number: 'RE-2027-0001', issueDate: '2027-01-15', currency: 'EUR', buyerReference: '04011000-1234512345-06',
seller: { name: 'Muster Software GmbH', vatId: 'DE123456789', street: 'Hauptstrasse 1', postcode: '10115', city: 'Berlin', country: 'DE',
electronicAddress: 'rechnung@muster.example', contact: { name: 'Erika Mustermann', phone: '+49 30 1234567', email: 'erika@muster.example' } },
buyer: { name: 'Stadt Beispielhausen', street: 'Rathausplatz 1', postcode: '50667', city: 'Beispielhausen', country: 'DE',
electronicAddress: '04011000-1234512345-06', electronicAddressScheme: '0204' },
payment: { meansCode: '58', iban: 'DE89370400440532013000' },
lines: [{ name: 'Wartung Dezember', quantity: 8, unitCode: 'HUR', unitPriceMinor: 9500, taxCategory: 'S', taxRate: 19 }],
};
const { xml } = createXml(invoice, 'xrechnung-cii');
const checked = await validate(xml);
console.log(checked.valid, checked.ruleSets.map((r) => r.id)); // true [ 'en16931-cii', 'xrechnung-cii' ]A ZUGFeRD / Factur-X PDF
A PDF/A-3 with the XML embedded. Byte-for-byte deterministic: the same invoice always gives the same file.
const { pdf, xmlFilename, conformanceLevel } = await createPdf(invoice, { profile: 'xrechnung', template: 'modern', language: 'de' });
console.log(xmlFilename, conformanceLevel, (await validate(pdf)).valid); // xrechnung.xml XRECHNUNG trueConvert, parse, explain
const ubl = await convert(xml, 'xrechnung-ubl'); // CII to UBL; totals are checked, never silently changed
const read = await parse(ubl.xml); // back into the model
console.log(read.invoice.number, read.totalsCheck.matches); // RE-2027-0001 true
console.log(explainRule('BR-DE-15').official[0]?.text); // the KoSIT wording of the rule
console.log(getRequirements('DE').conformoSupport.xrechnung); // { generate: true, read: true, validate: true, note: '...' }Mistakes are reported, not thrown as TypeErrors
try {
createXml({ ...invoice, seller: { ...invoice.seller, country: 'Germany' } }, 'cii');
} catch (err) {
if (!(err instanceof InvoiceInputError)) throw err;
console.log(err.issues[0]); // { path: 'seller.country', bt: 'BT-40', severity: 'error', message: '...' }
}Formats for createXml: cii, cii-extended, ubl, xrechnung-cii, xrechnung-ubl, peppol-ubl. Profiles for createPdf: en16931, xrechnung, extended. Lower-level packages (@conformo/core, @conformo/formats, @conformo/validate, @conformo/parse, @conformo/pdf) are published separately for people who need only one part.