Documentation & getting started
How to integrate Validator, Creator and Reader into your own .NET application – from the NuGet package to the first working call, return values and error handling.
- .NET Framework 4.8
- .NET 8
- .NET 10
- ZUGFeRD 2.5.2 / Factur-X 1.09.2
- XRechnung 3.0 (CII & UBL)
Quick start
From PDF to compliance verdict in three steps. The example below mirrors the actual flow used by the live demo.
- Add the
Facturexa.ZugferdValidatorpackage via NuGet. The official rule sets (XML schema and Schematron) are included and found automatically. - Register the license key once at application startup. You receive it by email and can always find it in your customer account.
- For each invoice, validate the PDF (or the XML) with a single call.
using Facturexa.ZugferdValidator;
// Once at application startup: register the license key.
ZugferdValidatorLicense.RegisterLicense("…");
// Validate the invoice PDF: PDF container, XML schema and official Schematron in one call.
var result = ZugferdValidator.Validate("invoice.pdf", "INV-2026-0001");
Console.WriteLine(result.IsValid ? "Valid" : "Not compliant");
The complete flow with error handling follows in the Validator section.
Installation & requirements
Each library is a separate NuGet package and can be referenced on its own.
dotnet add package Facturexa.ZugferdValidator
Install-Package Facturexa.ZugferdValidator
dotnet add package Facturexa.ZugferdCreator
Install-Package Facturexa.ZugferdCreator
dotnet add package Facturexa.ZugferdReader
Install-Package Facturexa.ZugferdReader
Requirements
- .NET 10, .NET 8 or .NET Framework 4.8
- Windows, Linux or macOS
- Validator:
Official Schematron\folder next to the application (copied automatically by the package) - Validator: no trimming (
PublishTrimmed) and no Native AOT
Try it without code
The live demo runs the Validator right in your browser, without any integration into your own code.
Deploying the rule sets (Validator)
- Offline operation: all rule sets (XML schema, Schematron, code lists) ship with the package. No internet connection is needed at runtime and the Validator calls no external service – the license check is local as well. No firewall rule is required.
- The package copies
Official Schematron\(the Schematron rule sets and, underXSD\, the XML schema) next to your application automatically on build and publish – also for classic ASP.NET (underbin\), single-file, ClickOnce, and when you reference the Validator through your own library or your own NuGet package. - After downgrading the package, clean or rebuild the solution once so the older rule set files replace the newer ones in the output folder.
- Providing the folder yourself: set
<FacturexaContentAutoCopy>false</FacturexaContentAutoCopy>in the project, with PackageReference additionallyExcludeAssets="contentFiles"on the package reference, and setSchematronChecker.SchematronDirectoryto the folder.
Profiles & versions
ZUGFeRD defines several profiles with different levels of detail. The overview below shows which ones the Validator checks and the Creator generates.
| Profile | Description | Validator | Creator |
|---|---|---|---|
| MINIMUM | Header data only, not a valid e-invoice format on its own | ✔ Yes | ✔ Yes |
| BASIC WL | Header data without invoice lines | ✔ Yes | ✔ Yes |
| BASIC | Core information including invoice lines | ✔ Yes | ✔ Yes |
| EN 16931 / COMFORT | European core standard – valid e-invoice format | ✔ Yes | ✔ Yes |
| EXTENDED | Extended data set; from ZUGFeRD 2.5.2 including sub-lines, kits & bundles | ✔ Yes | ✔ Yes |
| XRechnung 3.0 (CIUS) | German B2G core variant, two-stage EN 16931 + CIUS | ✔ Yes (CII + UBL) | ✔ Yes (CII) |
| UBL generation | Output XRechnung as UBL instead of CII | n/a (already validated) | Roadmap |
Version
The Creator always writes the current specification: ZUGFeRD 2.5.2 / Factur-X 1.09.2
(effective from 1 September 2026), including the EXTENDED sub-lines for kits and bundles.
You do not choose a version in Save(…) – new specifications arrive with
a new package version.
Which specification the referenced DLL implements can be queried at runtime:
ZugferdCreatorInfo.SupportedSpecification.
Validator: validate a PDF
Register the license key once at application startup. The Validator finds the official rule
sets automatically next to the DLL (under bin\ for classic ASP.NET); after that, one
call per validation is enough. Pass the complete PDF: the Validator extracts the embedded XML itself,
checks the PDF container (PDF/A-3, Factur-X metadata) and then the XML against the XML schema and the
official Schematron. A plain XML file works the same way – detected from the content, not the extension.
IsValid is true if no stage reports an error; IsPdfValid and
IsSchemaValid give the partial verdicts.
using Facturexa.ZugferdValidator;
// Once at application startup.
ZugferdValidatorLicense.RegisterLicense("…");
// PDF or XML: PDF container, XML schema and official Schematron in one call.
var result = ZugferdValidator.Validate("invoice.pdf", "INV-2026-0001");
Console.WriteLine(result.IsValid ? "Valid" : "Not compliant");
Console.WriteLine($"PDF container: {result.IsPdfValid}"); // null for a plain XML
Console.WriteLine($"Rule set: {result.SchematronRuleSet}");
foreach (var error in result.Errors)
Console.WriteLine($"{error.Stage}: {error}"); // e.g. "Schematron: BR-CO-15 (BT-112): ..."
Further reading: Validator product page · Try the live demo
Creator: create an invoice
Register the license key once at application startup, then set the invoice header, parties, lines and totals, choose a profile and save. Output is currently CII (UBL is on the roadmap).
using Facturexa.ZugferdCreator;
// Once at application startup.
ZugferdCreatorLicense.RegisterLicense("…");
var invoice = new EInvoice
{
InvoiceNumber = "INV-2026-0001",
InvoiceDate = DateTime.Today
};
invoice.SetSellerTradeParty("Sample GmbH", "12345", "Berlin", "Musterstraße 1", CountryID.DE);
invoice.AddSellerSpecifiedTaxRegistration("DE123456789", TaxRegistrationSchemeID.VA);
invoice.SetBuyerTradeParty("Customer AG", "54321", "Hamburg", "Kundenweg 2", CountryID.DE);
invoice.AddIncludedSupplyChainTradeLineItem(
name: "Consulting services", netUnitPrice: 100.00m, unitCode: UnitCode.C62,
billedQuantity: 3m, lineTotalAmount: 300.00m, taxPercent: 19m);
invoice.AddApplicableTradeTax(300.00m, 19m, 57.00m, TaxTypeCode.VAT, TaxCategoryCode.S);
invoice.LineTotalAmount = 300.00m;
invoice.TaxBasisAmount = 300.00m;
invoice.TaxTotalAmount = 57.00m;
invoice.GrandTotalAmount = 357.00m;
invoice.DuePayableAmount = 357.00m;
using var xmlStream = new MemoryStream();
invoice.Save(xmlStream, InvoiceProfile.Comfort);
Further reading: Creator product page · Try the live demo
Reader: read an invoice
The Reader reads an invoice – as plain XML (CII or UBL) or as a PDF with embedded XML; the format is detected automatically – and returns the fields as an object. Optionally it renders a readable PDF view from it.
using Facturexa.ZugferdReader;
// Read a PDF or XML – the file name helps with format detection.
using var stream = File.OpenRead("invoice.pdf");
var invoice = ZugferdReader.Read(stream, "invoice.pdf");
Console.WriteLine(invoice.InvoiceNumber);
Console.WriteLine(invoice.InvoiceDate?.ToString("yyyy-MM-dd"));
Console.WriteLine(invoice.Seller?.Name);
Console.WriteLine($"{invoice.LineItems.Count} line(s), {invoice.GrandTotalAmount:N2} {invoice.CurrencyCode}");
// Optional: render a readable PDF view of the invoice.
byte[] viewPdf = ZugferdReader.CreatePdf(invoice);
File.WriteAllBytes("invoice-view.pdf", viewPdf);
Further reading: Reader product page · Try the live demo
Return values
The most important fields of the result objects at a glance.
ZugferdValidationResult – Validator.Validate(…)
| Member | Type | Meaning |
|---|---|---|
IsValid | bool | True if no stage reports an error (PDF container, XML schema, official Schematron) and the PDF check did not fail. |
IsPdfValid | bool? | Verdict of the PDF check; null if an XML was validated instead of a PDF. |
IsSchemaValid | bool | True if the XML schema (XSD) reports no error. |
PdfCheck | ZugferdPdfCheckResult | Result of the PDF check with its status lines (see below); null for a plain XML. |
PdfFindings / SchemaFindings / SchematronFindings | List<ValidationFinding> | Findings of one check stage; every finding states its stage in Stage. |
EmbeddedXml / EmbeddedXmlFileName | byte[] / string | The validated XML and, for a PDF, the attachment name, e.g. “factur-x.xml” – for example to pass it on to the Reader. |
Errors | List<ValidationFinding> | Blocking findings (severity Error). |
Warnings | List<ValidationFinding> | Warnings; they do not prevent sending. |
Findings | List<ValidationFinding> | All findings, unfiltered. |
SchematronRuleSet | string | Official rule set applied, e.g. “ZUGFeRD 2.5.2 / Factur-X 1.09.2, profile EXTENDED – release date 2026-08-04 (FACTUR-X_EXTENDED.xslt)”. Null if the profile is not covered or the Schematron could not run. |
ProfileInfo | InvoiceProfileInfo | Version/profile declared by the document itself (BT-24). |
GetErrorMessages() | List<string> | Errors as ready-made message texts including the invoice number. |
ZugferdPdfCheckResult – ZugferdValidationResult.PdfCheck
| Member | Type | Meaning |
|---|---|---|
OverallValid | bool | Overall verdict of the PDF check (same as IsPdfValid). |
Format | string | PDF/A identification from the XMP metadata, e.g. “PDFA_3_B”, otherwise “unknown”. |
FacturXVersion | string | Factur-X version from the XMP metadata, e.g. “1.0”. |
XmlExtractable / EmbeddingCompliant / FileNameCompliant / XmpCompliant | ZugferdPdfCheckStatus | Status lines: Yes, No or Unknown. |
Findings | List<ValidationFinding> | Findings of the PDF check (PDF-CHECK-01 to -16, PDF-XML-MISSING). |
Previous API: ZugferdPdfReader.ReadZugferdXml(…) and ZugferdPdfValidator.Validate(…) keep working until version 8.0 but are marked obsolete since 7.4.0. Pass the PDF directly to ZugferdValidator.Validate(…) instead.
InvoiceViewModel – ZugferdReader.Read(…)
| Member | Type | Meaning |
|---|---|---|
InvoiceNumber | string | Invoice number (BT-1). |
InvoiceDate | DateTime? | Invoice date (BT-2). |
Seller / Buyer | InvoicePartyViewModel | Seller/buyer including .Name and address. |
LineItems | List<…> | Invoice lines. |
GrandTotalAmount | decimal? | Invoice total amount with VAT (BT-112). |
CurrencyCode | string | Currency (BT-5), e.g. “EUR”. |
ProfileUrn | string | Profile URN from the CustomizationID. |
Error handling & troubleshooting
The most common pitfalls during integration and their cause.
| Symptom | Cause & solution |
|---|---|
ZugferdValidatorLicenseException or ZugferdCreatorLicenseException: “No license key found” |
The key was not registered. Call ZugferdValidatorLicense.RegisterLicense("…") or ZugferdCreatorLicense.RegisterLicense("…") once at application startup, before the first validation or creation. |
Finding XSD-ERROR: validation against the XML schema could not be performed |
The XSD files (Official Schematron\XSD\) were not deployed or the folder is not next to the DLL. Deploy the complete Official Schematron\ folder or set SchematronChecker.SchematronDirectory to its path once. A check that cannot be performed is deliberately reported as an error. |
Finding PDF-XML-MISSING, message “The PDF file contains no attachments” |
The PDF contains no embedded XML – it is not a ZUGFeRD invoice. Use a genuine Factur-X/ZUGFeRD PDF or validate the XML directly. |
IsValid == false although the invoice looks valid; the error mentions Saxon/Schematron |
The Saxon DLL or the Schematron artifacts were not deployed. A check that cannot be performed is deliberately reported as an error. Deploy the artifacts. |
After publishing with PublishTrimmed: finding SCHEMATRON-ERROR, message mentions DotNetLocaleHelper |
The Saxon engine supports neither trimming nor Native AOT. Publish without PublishTrimmed. |
ZugferdReaderException / UnsupportedFormatException |
The file is neither a PDF with embedded XML nor an XML in CII or UBL syntax. Use a supported format; wrap the call to ZugferdReader.Read(…) in try/catch. |