Skip to content

Create a Factur-X invoice PDF in C#

Since 1.1View as Markdown

Turn an invoice PDF and its XML into one Factur-X or ZUGFeRD hybrid invoice.

Draw or convert the invoice, attach its XML with PdfInvoice.Attach and the profile it follows, then save as PDF/A-3b. The XML is checked for well formedness and embedded as factur-x.xml with the relationship the profile calls for, and saving writes the Factur-X XMP metadata with its extension schema.

PdfFont font = PdfOpenTypeFont.Load("fonts/Inter-Regular.woff2"); // PDF/A needs embedded fonts
PdfDocument doc = PdfDocument.Create();
doc.Info.Title = "Invoice 42";
doc.Language = "en";
PdfPage page = doc.Pages.Add(PdfRectangle.A4);
using (PdfGraphics g = page.CreateGraphics())
{
g.DrawString("Invoice 42", font, 24, PdfColor.Black, 72, 100);
g.DrawString("Total: 1,210.00 EUR", font, 12, PdfColor.Black, 72, 130);
}
// The invoice XML from your billing system, in Cross Industry Invoice syntax.
byte[] xml = File.ReadAllBytes("invoice-42.xml");
PdfInvoice.Attach(doc, xml, PdfInvoiceProfile.EN16931); // embedded as factur-x.xml
doc.Save("invoice-42.pdf", new PdfSaveOptions { Conformance = PdfConformance.PdfA3B });
PdfDocument check = PdfDocument.Open("invoice-42.pdf");
Console.WriteLine(string.Join(", ", check.Attachments.Select(a => a.Name)));
  • PDF/A needs embedded fonts, so the sample draws with an OpenType font rather than one of the standard 14. An invoice made with HTML to PDF works the same way when its fonts are embedded.
  • Profiles: Minimum, BasicWL, Basic, EN16931, Extended and XRechnung. PdfNetStack does not validate the XML against the profile’s rules; check the invoice data before you attach it.
  • To sign the invoice, sign the saved bytes last, see Signatures.