Creating ZUGFeRD Compliant PDF Invoices in C#
ZUGFeRD / Factur-X documents can be created and extracted using TX Text Control X19. This article shows how to create a valid ZUGFeRD compliant invoice PDF document from scratch.

The ZUGFeRD / Factur-X standard is a hybrid electronic invoice format that consists of two parts:
-
A PDF visual, human-readable representation of the invoice.
-
An XML file that contains invoice data in a structured form that can be processed automatically.
TX Text Control X19 supports the embedding of attachments in PDF/A-3b documents and also the extraction of an attachment. This sample shows 3 steps of the creation process using TX Text Control:
- Creating the required ZUGFeRD XML.
- Creating the visual representation.
- Export both to a valid PDF/A-3b document.
Embedding Existing XML
In case, you already have a valid XML representation created by a third-party tool or an ERP system, you can easily embed this XML to a PDF document using the Save method by specifying an Embedded
string xmlZugferd = ""; // your XML
string metaData = ""; // required RDF meta data
TXTextControl.SaveSettings saveSettings = new TXTextControl.SaveSettings();
// create a new embedded file
var zugferdInvoice = new TXTextControl.EmbeddedFile(
"ZUGFeRD-invoice.xml",
Encoding.UTF8.GetBytes(xmlZugferd),
metaData);
zugferdInvoice.Description = "ZUGFeRD-invoice";
zugferdInvoice.Relationship = "Alternative";
zugferdInvoice.MIMEType = "application/xml";
zugferdInvoice.LastModificationDate = DateTime.Now;
// set the embedded files
saveSettings.EmbeddedFiles = new TXTextControl.EmbeddedFile[] {
new TXTextControl.EmbeddedFile(
"ZUGFeRD-invoice.xml",
Encoding.UTF8.GetBytes(xmlZugferd),
metadata) };
// export the PDF
textControl1.Save("test.pdf", TXTextControl.StreamType.AdobePDFA, saveSettings);
Create ZUGFeRD XML
For demo purposes, we implemented the helper class TXTextControl.DocumentServer.PDF.Zugferd.Invoice that creates a valid ZUGFeRD XML. The method CreateSampleInvoice returns the required XML that is embedded into the created PDF document.
private Invoice CreateSampleInvoice() {
// new zugferd invoice
Invoice invoice = new Invoice("A12345", DateTime.Now, CurrencyCode.USD);
invoice.Type = InvoiceType.Invoice;
invoice.Profile = Profile.Comfort;
// buyer
invoice.Buyer = new TradeParty {
ID = "TX_1",
Name = "Text Control GmbH",
ContactName = "Peter Paulsen",
City = "Bremen",
Postcode = "28217",
Country = CountryCode.DE,
Street = "Überseetor 18"
};
// seller
invoice.Seller = new TradeParty {
ID = "TX_2",
Name = "Text Control, LLC",
ContactName = "Jack Jackson",
City = "Charlotte, NC",
Postcode = "28210",
Country = CountryCode.US,
Street = "6926 Shannon Willow Rd, Suite 400",
};
// add tax id's
invoice.Seller.SpecifiedTaxRegistrations.Add(
new TaxID() { ID = "US12367623", Scheme = TaxScheme.VA });
// add products
List<LineItem> lineItems = new List<LineItem>();
lineItems.Add(new LineItem() {
Price = 200,
ProductID = "A123",
Name = "Product A",
Quantity = 5,
Total = 1000,
UnitCode = QuantityCodes.C62
});
// add line items to invoice
foreach (LineItem item in lineItems)
invoice.LineItems.Add(item);
// set the total amount
invoice.TotalAmount = 1000;
return invoice;
}
In the sample application, a very simple template is used to create the visual representation of the invoice:
The following code loads the template into a TextControl and uses Mail
TXTextControl.DocumentServer.MailMerge mm = new TXTextControl.DocumentServer.MailMerge();
mm.TextComponent = textControl1;
textControl1.Load("invoice.tx", TXTextControl.StreamType.InternalUnicodeFormat);
Invoice invoice = CreateSampleInvoice();
// merge data into template
mm.MergeJsonData(JsonConvert.SerializeObject(invoice));
// create the XML
string xmlZugferd = invoice.CreateXml();
// get the required meta data
string metaData = MetaData.GetMetaData();
TXTextControl.SaveSettings saveSettings = new TXTextControl.SaveSettings();
// create a new embedded file
var zugferdInvoice = new TXTextControl.EmbeddedFile(
"ZUGFeRD-invoice.xml",
Encoding.UTF8.GetBytes(xmlZugferd),
metaData);
zugferdInvoice.Description = "ZUGFeRD-invoice";
zugferdInvoice.Relationship = "Alternative";
zugferdInvoice.MIMEType = "application/xml";
zugferdInvoice.LastModificationDate = DateTime.Now;
// set the embedded files
saveSettings.EmbeddedFiles = new TXTextControl.EmbeddedFile[] {
new TXTextControl.EmbeddedFile(
"ZUGFeRD-invoice.xml",
Encoding.UTF8.GetBytes(xmlZugferd),
metaData) };
// export the PDF
textControl1.Save("test.pdf", TXTextControl.StreamType.AdobePDFA, saveSettings);
The ZUGFeRD XML
The XML document that is embedded in the PDF is listed below:
<?xml version="1.0" encoding="utf-8"?>
<rsm:CrossIndustryInvoice xmlns:a="urn:un:unece:uncefact:data:standard:QualifiedDataType:100" xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:10" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
<rsm:ExchangedDocumentContext>
<ram:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:cen.eu:en16931:2017#compliant#urn:zugferd.de:2p0:comfort</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter>
</rsm:ExchangedDocumentContext>
<rsm:ExchangedDocument>
<ram:ID>A12345</ram:ID>
<ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime>
<udt:DateTimeString format="102">20210203</udt:DateTimeString>
</ram:IssueDateTime>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>1</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Product A</ram:Name>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>200</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="C62">5</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>1000.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:ApplicableHeaderTradeAgreement>
<ram:SellerTradeParty>
<ram:Name>Text Control, LLC</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>28210</ram:PostcodeCode>
<ram:LineOne>Jack Jackson</ram:LineOne>
<ram:LineTwo>6926 Shannon Willow Rd, Suite 400</ram:LineTwo>
<ram:CityName>Charlotte, NC</ram:CityName>
<ram:CountryID>US</ram:CountryID>
</ram:PostalTradeAddress>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">US12367623</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:SellerTradeParty>
<ram:BuyerTradeParty>
<ram:Name>Text Control GmbH</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>28217</ram:PostcodeCode>
<ram:LineOne>Peter Paulsen</ram:LineOne>
<ram:LineTwo>Überseetor 18</ram:LineTwo>
<ram:CityName>Bremen</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
</ram:BuyerTradeParty>
</ram:ApplicableHeaderTradeAgreement>
<ram:ApplicableHeaderTradeDelivery>
<ram:ActualDeliverySupplyChainEvent>
<ram:OccurrenceDateTime>
<udt:DateTimeString format="102">20210203</udt:DateTimeString>
</ram:OccurrenceDateTime>
</ram:ActualDeliverySupplyChainEvent>
</ram:ApplicableHeaderTradeDelivery>
<ram:ApplicableHeaderTradeSettlement>
<ram:InvoiceCurrencyCode>USD</ram:InvoiceCurrencyCode>
<ram:ApplicableTradeTax>
<ram:CalculatedAmount>190.00</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount>1000.00</ram:BasisAmount>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradePaymentTerms>
<ram:DueDateDateTime>
<udt:DateTimeString format="102">20210305</udt:DateTimeString>
</ram:DueDateDateTime>
</ram:SpecifiedTradePaymentTerms>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:LineTotalAmount>1000.00</ram:LineTotalAmount>
<ram:ChargeTotalAmount>0.00</ram:ChargeTotalAmount>
<ram:AllowanceTotalAmount>0.00</ram:AllowanceTotalAmount>
<ram:TaxBasisTotalAmount>1000.00</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="USD">190.00</ram:TaxTotalAmount>
<ram:GrandTotalAmount>1190.00</ram:GrandTotalAmount>
<ram:DuePayableAmount>1190.00</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
</ram:ApplicableHeaderTradeSettlement>
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>
In Acrobat Reader
When the resulting PDF document is opened in Acrobat Reader, you can check the PDF/A-3b conformance using the Standards tab:
Additionally, you can verify the attachments:
Validating the Conformance
After validating the ZUGFeRD document using validation services such as the ZF/FX Validation (https://www.zugferd-community.net/de/dashboard/validation), you can see that the created document passes all tests:
You can download the sample project from our GitHub repository that contains the ZUGFeRD helper classes to create a valid XML document from scratch.
Also See
This post references the following in the documentation:
- TXText
Control. Document Server. Mail Merge Class - TXText
Control. Embedded File Class - TXText
Control. Server Text Control. Save Method
Download and Fork This Sample on GitHub
We proudly host our sample code on github.com/TextControl.
Please fork and contribute.
Requirements for this sample
- TX Text Control .NET for Windows Forms X19 (trial)
- Visual Studio 2019
Related Posts
Electronic Invoicing will Become Mandatory in Germany in 2025
The German government has decided to make the ability to receive electronic invoices mandatory for all B2B transactions. This article explains what this means for you and how you can prepare for…
Extract Text and Data from PDF Documents in C#
TX Text Control can be used to create and edit Adobe PDF documents programmatically. But it is also possible to import PDF documents to read, extract and manipulate them. This article shows…
Creating PDF Files using TX Text Control .NET in C#
TX Text Control allows developers to create PDF files programmatically using C#. This article shows various ways to create Adobe PDF documents.
ASP.NETJavaScriptWindows Forms
Generating Interactive PDF Forms by Injecting JavaScript
Using TX Text Control, it is possible to export documents with form fields to fillable PDFs. This article shows how to inject JavaScript to add interaction to form fields.
Form Field Handling in PDF Documents
Since TX Text Control supports form fields, it is possible to either export form fields in the PDF document or to flatten the form fields to export text only without the field functionality. This…