Create an XRechnung invoice in C#
Convert the visible invoice to PDF/A-3, then call AddZugferdInvoice with ZugferdProfile.XRechnung: the XRechnung XML is embedded as xrechnung.xml and the document metadata marks it as an XRechnung invoice.
Compiled and run: Linux ARM64 · Linux x64 · macOS ARM64 · Windows x64
Validated by veraPDF: PDF/A-3b · PDF/A-3a
Build it step by step.
-
1Install the NuGet packages
SelectPdf.Universalis the library. The native package carries the Chromium engine for one platform: add the one for the platform you run on.dotnet add package SelectPdf.Universal dotnet add package SelectPdf.Universal.Native.win-x64
dotnet add package SelectPdf.Universal dotnet add package SelectPdf.Universal.Native.linux-x64
dotnet add package SelectPdf.Universal dotnet add package SelectPdf.Universal.Native.linux-arm64
dotnet add package SelectPdf.Universal dotnet add package SelectPdf.Universal.Native.osx-arm64
-
2Create a console app
Any .NET 8 or .NET 10 project works. To follow along, create a console app, run the install commands above inside its folder, then replace
Program.cswith the code below.dotnet new console -n PdfSample cd PdfSample
-
3Start from the XRechnung XML
// the invoice as XRechnung CII XML (shortened); in your application, your invoicing system produces it string xml = """ <?xml version="1.0" encoding="UTF-8"?> <rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"> <rsm:ExchangedDocumentContext><ram:GuidelineSpecifiedDocumentContextParameter> <ram:ID>urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0</ram:ID> </ram:GuidelineSpecifiedDocumentContextParameter></rsm:ExchangedDocumentContext> <rsm:ExchangedDocument> <ram:ID>RE-2026-0815</ram:ID><ram:TypeCode>380</ram:TypeCode> <ram:IssueDateTime><udt:DateTimeString format="102">20261013</udt:DateTimeString></ram:IssueDateTime> </rsm:ExchangedDocument> <rsm:SupplyChainTradeTransaction> <ram:IncludedSupplyChainTradeLineItem> <ram:AssociatedDocumentLineDocument><ram:LineID>1</ram:LineID></ram:AssociatedDocumentLineDocument> <ram:SpecifiedTradeProduct><ram:Name>Website maintenance, September 2026</ram:Name></ram:SpecifiedTradeProduct> <ram:SpecifiedLineTradeSettlement><ram:SpecifiedTradeSettlementLineMonetarySummation> <ram:LineTotalAmount>1000.00</ram:LineTotalAmount> </ram:SpecifiedTradeSettlementLineMonetarySummation></ram:SpecifiedLineTradeSettlement> </ram:IncludedSupplyChainTradeLineItem> <ram:ApplicableHeaderTradeAgreement> <ram:BuyerReference>04011000-12345-34</ram:BuyerReference> <ram:SellerTradeParty><ram:Name>Contoso GmbH</ram:Name></ram:SellerTradeParty> <ram:BuyerTradeParty><ram:Name>Stadt Musterstadt</ram:Name></ram:BuyerTradeParty> </ram:ApplicableHeaderTradeAgreement> <ram:ApplicableHeaderTradeDelivery/> <ram:ApplicableHeaderTradeSettlement> <ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode> <ram:SpecifiedTradeSettlementHeaderMonetarySummation> <ram:TaxBasisTotalAmount>1000.00</ram:TaxBasisTotalAmount> <ram:TaxTotalAmount currencyID="EUR">190.00</ram:TaxTotalAmount> <ram:GrandTotalAmount>1190.00</ram:GrandTotalAmount> <ram:DuePayableAmount>1190.00</ram:DuePayableAmount> </ram:SpecifiedTradeSettlementHeaderMonetarySummation> </ram:ApplicableHeaderTradeSettlement> </rsm:SupplyChainTradeTransaction> </rsm:CrossIndustryInvoice> """;The invoice data as an XRechnung document in the UN/CEFACT Cross Industry Invoice syntax, shortened for this guide. The guideline ID in
ExchangedDocumentContextnames XRechnung, andBuyerReferencecarries the buyer's reference. In your application, your invoicing system produces this XML; SelectPdf embeds it as it is and does not generate or validate it. -
4Write the visible invoice
// the visible invoice, with the same content as the XML string html = """ <h1>Invoice RE-2026-0815</h1> <p>13 October 2026 · Contoso GmbH to Stadt Musterstadt · Buyer reference 04011000-12345-34</p> <p>Website maintenance, September 2026: 1,000.00 EUR<br>VAT 19%: 190.00 EUR<br><b>Total: 1,190.00 EUR</b></p> """;The page a person reads. It shows the same invoice as the XML: number, date, parties, buyer reference, line and totals. The
Alternativerelationship used below states exactly that. -
5Convert to PDF/A-3
// the carrier: a PDF/A-3 document HtmlToPdf converter = new HtmlToPdf(); converter.Options.PdfStandard = PdfStandard.PdfA3B; converter.Options.PdfDocumentInformation.Title = "Invoice RE-2026-0815"; PdfDocument doc = converter.ConvertHtmlString(html);
Options.PdfStandard = PdfStandard.PdfA3Bmakes the converted invoice a PDF/A-3 document, the carrier format hybrid invoices require.PdfDocumentInformation.Titlerecords the invoice number in the document metadata. -
6Embed the XML with the XRechnung profile
// embed the XML as xrechnung.xml and mark the document as an XRechnung invoice using (MemoryStream invoiceXml = new MemoryStream(Encoding.UTF8.GetBytes(xml))) { doc.AddZugferdInvoice(invoiceXml, ZugferdProfile.XRechnung, PdfAttachmentRelationship.Alternative); }AddZugferdInvoicereads the stream immediately, embeds it as an associated file namedxrechnung.xmland writes the invoice metadata, withXRECHNUNGas the conformance level.PdfAttachmentRelationship.Alternativesays the XML and the page carry the same content. -
7Save
doc.Save("invoice-xrechnung.pdf"); doc.Close();Savewritesinvoice-xrechnung.pdfandClosereleases the document. The file passes veraPDF as PDF/A-3b and listsxrechnung.xmlas its embedded file. -
8Run it
dotnet run
The program writes
invoice-xrechnung.pdfto the working folder. Without a license key, every page carries a trial watermark; setGlobalProperties.LicenseKeybefore the first conversion to remove it.
The complete Program.cs.
This is the exact file our samples pipeline compiled and ran on Linux ARM64 and Linux x64 and macOS ARM64 and Windows x64 to produce the output on this page.
using System.Text;
using SelectPdf.Universal;
// the invoice as XRechnung CII XML (shortened); in your application, your invoicing system produces it
string xml = """
<?xml version="1.0" encoding="UTF-8"?>
<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
<rsm:ExchangedDocumentContext><ram:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter></rsm:ExchangedDocumentContext>
<rsm:ExchangedDocument>
<ram:ID>RE-2026-0815</ram:ID><ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime><udt:DateTimeString format="102">20261013</udt:DateTimeString></ram:IssueDateTime>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument><ram:LineID>1</ram:LineID></ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct><ram:Name>Website maintenance, September 2026</ram:Name></ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeSettlement><ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>1000.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation></ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:ApplicableHeaderTradeAgreement>
<ram:BuyerReference>04011000-12345-34</ram:BuyerReference>
<ram:SellerTradeParty><ram:Name>Contoso GmbH</ram:Name></ram:SellerTradeParty>
<ram:BuyerTradeParty><ram:Name>Stadt Musterstadt</ram:Name></ram:BuyerTradeParty>
</ram:ApplicableHeaderTradeAgreement>
<ram:ApplicableHeaderTradeDelivery/>
<ram:ApplicableHeaderTradeSettlement>
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:TaxBasisTotalAmount>1000.00</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="EUR">190.00</ram:TaxTotalAmount>
<ram:GrandTotalAmount>1190.00</ram:GrandTotalAmount>
<ram:DuePayableAmount>1190.00</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
</ram:ApplicableHeaderTradeSettlement>
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>
""";
// the visible invoice, with the same content as the XML
string html = """
<h1>Invoice RE-2026-0815</h1>
<p>13 October 2026 · Contoso GmbH to Stadt Musterstadt · Buyer reference 04011000-12345-34</p>
<p>Website maintenance, September 2026: 1,000.00 EUR<br>VAT 19%: 190.00 EUR<br><b>Total: 1,190.00 EUR</b></p>
""";
// the carrier: a PDF/A-3 document
HtmlToPdf converter = new HtmlToPdf();
converter.Options.PdfStandard = PdfStandard.PdfA3B;
converter.Options.PdfDocumentInformation.Title = "Invoice RE-2026-0815";
PdfDocument doc = converter.ConvertHtmlString(html);
// embed the XML as xrechnung.xml and mark the document as an XRechnung invoice
using (MemoryStream invoiceXml = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
{
doc.AddZugferdInvoice(invoiceXml, ZugferdProfile.XRechnung, PdfAttachmentRelationship.Alternative);
}
doc.Save("invoice-xrechnung.pdf");
doc.Close();
Open the project on GitHub → this program and the variations below, ready to dotnet run
The PDF it produces.
Download invoice-xrechnung.pdf ↓ the file this sample produced, unedited
Variations you will need next.
Each variation is a separate file in the same project, compiled and run with the program above.
An accessible XRechnung invoice (PDF/A-3A with PDF/UA-1)
PdfStandard.PdfA3A with AccessibilityStandard = PdfUAStandard.UA1 makes the carrier a tagged, accessible document, which the hybrid invoice standards recommend. PDF/UA needs a title and a language, so Options.Title and Options.Language are set. The XML is embedded the same way.
using System.Text;
using SelectPdf.Universal;
static class AccessibleXRechnung
{
public static void Run()
{
string xml = """
<?xml version="1.0" encoding="UTF-8"?>
<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
<rsm:ExchangedDocumentContext><ram:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter></rsm:ExchangedDocumentContext>
<rsm:ExchangedDocument>
<ram:ID>RE-2026-0816</ram:ID><ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime><udt:DateTimeString format="102">20261013</udt:DateTimeString></ram:IssueDateTime>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument><ram:LineID>1</ram:LineID></ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct><ram:Name>Hosting, October 2026</ram:Name></ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeSettlement><ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>500.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation></ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:ApplicableHeaderTradeAgreement>
<ram:BuyerReference>04011000-12345-34</ram:BuyerReference>
<ram:SellerTradeParty><ram:Name>Contoso GmbH</ram:Name></ram:SellerTradeParty>
<ram:BuyerTradeParty><ram:Name>Stadt Musterstadt</ram:Name></ram:BuyerTradeParty>
</ram:ApplicableHeaderTradeAgreement>
<ram:ApplicableHeaderTradeDelivery/>
<ram:ApplicableHeaderTradeSettlement>
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:TaxBasisTotalAmount>500.00</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="EUR">95.00</ram:TaxTotalAmount>
<ram:GrandTotalAmount>595.00</ram:GrandTotalAmount>
<ram:DuePayableAmount>595.00</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
</ram:ApplicableHeaderTradeSettlement>
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>
""";
HtmlToPdf converter = new HtmlToPdf();
// PDF/A-3A with PDF/UA-1: an archival carrier whose visible invoice is also accessible
converter.Options.PdfStandard = PdfStandard.PdfA3A;
converter.Options.AccessibilityStandard = PdfUAStandard.UA1;
converter.Options.Title = "Invoice RE-2026-0816";
converter.Options.Language = "en-US";
PdfDocument doc = converter.ConvertHtmlString("""
<h1>Invoice RE-2026-0816</h1>
<p>13 October 2026. Contoso GmbH to Stadt Musterstadt. Buyer reference 04011000-12345-34.</p>
<table>
<tr><th scope="col">Item</th><th scope="col">Amount</th></tr>
<tr><td>Hosting, October 2026</td><td>500.00 EUR</td></tr>
<tr><td>VAT 19%</td><td>95.00 EUR</td></tr>
<tr><td>Total</td><td>595.00 EUR</td></tr>
</table>
""");
using (MemoryStream invoiceXml = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
{
doc.AddZugferdInvoice(invoiceXml, ZugferdProfile.XRechnung, PdfAttachmentRelationship.Alternative);
}
doc.Save("invoice-xrechnung-pdfa3a.pdf");
doc.Close();
}
}
Turn an existing PDF invoice into an XRechnung invoice
An invoice that already exists as a PDF is loaded with new PdfDocument(path) and converted with ConvertToPdfA(PdfStandard.PdfA3B); a document that is already PDF/A-3 needs no conversion. This overload of AddZugferdInvoice takes the path of the XML file, reads it immediately and embeds it as xrechnung.xml.
using SelectPdf.Universal;
static class ExistingPdfToXRechnung
{
public static void Run()
{
// stands in for an invoice your system already produced as a PDF, and for its XML
HtmlToPdf converter = new HtmlToPdf();
PdfDocument plain = converter.ConvertHtmlString(
"<h1>Invoice RE-2026-0817</h1><p>13 October 2026. Contoso GmbH to Stadt Musterstadt. " +
"Buyer reference 04011000-12345-34.</p><p>Software licence: 2,000.00 EUR<br>" +
"VAT 19%: 380.00 EUR<br><b>Total: 2,380.00 EUR</b></p>");
plain.Save("invoice-0817.pdf");
plain.Close();
File.WriteAllText("invoice-0817.xml", """
<?xml version="1.0" encoding="UTF-8"?>
<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
<rsm:ExchangedDocumentContext><ram:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter></rsm:ExchangedDocumentContext>
<rsm:ExchangedDocument>
<ram:ID>RE-2026-0817</ram:ID><ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime><udt:DateTimeString format="102">20261013</udt:DateTimeString></ram:IssueDateTime>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument><ram:LineID>1</ram:LineID></ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct><ram:Name>Software licence</ram:Name></ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeSettlement><ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>2000.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation></ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:ApplicableHeaderTradeAgreement>
<ram:BuyerReference>04011000-12345-34</ram:BuyerReference>
<ram:SellerTradeParty><ram:Name>Contoso GmbH</ram:Name></ram:SellerTradeParty>
<ram:BuyerTradeParty><ram:Name>Stadt Musterstadt</ram:Name></ram:BuyerTradeParty>
</ram:ApplicableHeaderTradeAgreement>
<ram:ApplicableHeaderTradeDelivery/>
<ram:ApplicableHeaderTradeSettlement>
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:TaxBasisTotalAmount>2000.00</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="EUR">380.00</ram:TaxTotalAmount>
<ram:GrandTotalAmount>2380.00</ram:GrandTotalAmount>
<ram:DuePayableAmount>2380.00</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
</ram:ApplicableHeaderTradeSettlement>
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>
""");
// load the existing invoice and make it an archival PDF/A-3 document
PdfDocument doc = new PdfDocument("invoice-0817.pdf");
doc.ConvertToPdfA(PdfStandard.PdfA3B);
// embed the XML from its file; it is read immediately and embedded as xrechnung.xml
doc.AddZugferdInvoice("invoice-0817.xml", ZugferdProfile.XRechnung,
PdfAttachmentRelationship.Alternative);
doc.Save("invoice-0817-xrechnung.pdf");
doc.Close();
}
}
Add metadata of your own next to the invoice
A PDF/A document may only carry metadata from the schemas the standard predefines, unless the schema is described inside the document. AddXmpExtensionSchema declares a schema of your own and writes its values, here an order number and a department, so the document stays conformant.
using System.Text;
using SelectPdf.Universal;
static class XRechnungWithCustomMetadata
{
public static void Run()
{
string xml = """
<?xml version="1.0" encoding="UTF-8"?>
<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
<rsm:ExchangedDocumentContext><ram:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter></rsm:ExchangedDocumentContext>
<rsm:ExchangedDocument>
<ram:ID>RE-2026-0818</ram:ID><ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime><udt:DateTimeString format="102">20261013</udt:DateTimeString></ram:IssueDateTime>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument><ram:LineID>1</ram:LineID></ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct><ram:Name>Support contract, Q4 2026</ram:Name></ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeSettlement><ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>750.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation></ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:ApplicableHeaderTradeAgreement>
<ram:BuyerReference>04011000-12345-34</ram:BuyerReference>
<ram:SellerTradeParty><ram:Name>Contoso GmbH</ram:Name></ram:SellerTradeParty>
<ram:BuyerTradeParty><ram:Name>Stadt Musterstadt</ram:Name></ram:BuyerTradeParty>
</ram:ApplicableHeaderTradeAgreement>
<ram:ApplicableHeaderTradeDelivery/>
<ram:ApplicableHeaderTradeSettlement>
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:TaxBasisTotalAmount>750.00</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="EUR">142.50</ram:TaxTotalAmount>
<ram:GrandTotalAmount>892.50</ram:GrandTotalAmount>
<ram:DuePayableAmount>892.50</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
</ram:ApplicableHeaderTradeSettlement>
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>
""";
HtmlToPdf converter = new HtmlToPdf();
converter.Options.PdfStandard = PdfStandard.PdfA3B;
PdfDocument doc = converter.ConvertHtmlString(
"<h1>Invoice RE-2026-0818</h1><p>13 October 2026. Contoso GmbH to Stadt Musterstadt. " +
"Buyer reference 04011000-12345-34.</p><p>Support contract, Q4 2026: 750.00 EUR<br>" +
"VAT 19%: 142.50 EUR<br><b>Total: 892.50 EUR</b></p>");
using (MemoryStream invoiceXml = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
{
doc.AddZugferdInvoice(invoiceXml, ZugferdProfile.XRechnung, PdfAttachmentRelationship.Alternative);
}
// metadata of your own, declared as an XMP extension schema so the document stays PDF/A
Dictionary<string, string> properties = new Dictionary<string, string>();
properties["OrderNumber"] = "PO-4711";
properties["Department"] = "Accounts receivable";
doc.AddXmpExtensionSchema("contoso", "urn:contoso:pdfa:invoice:1p0#",
"Contoso invoice schema", properties);
doc.Save("invoice-0818-xrechnung.pdf");
doc.Close();
}
}
Common problems and fixes.
Could not add the electronic invoice: PDF/A-3 required
AddZugferdInvoice throws a PdfDocumentException on a document that is not PDF/A-3. Set Options.PdfStandard to PdfA3B, PdfA3U or PdfA3A before converting, create the document with new PdfDocument(PdfStandard.PdfA3B), or convert a loaded document with ConvertToPdfA(PdfStandard.PdfA3B).
The embedded file is named factur-x.xml
The file name follows the profile. Pass ZugferdProfile.XRechnung to get xrechnung.xml; the other profiles embed factur-x.xml, or zugferd-invoice.xml with the ZUGFeRD 2.0 schema.
The recipient rejects the invoice data
SelectPdf does not generate or validate the XML: it embeds what you pass. Check the XML against the XRechnung rules with your invoicing tools, and make sure the visible page shows the same content, as the Alternative relationship states.
Which relationship to use
For XRechnung use PdfAttachmentRelationship.Alternative: the XML and the visible page carry exactly the same invoice content, which is mandatory in Germany for this profile. Data is for a page that carries more than the XML, and Source for a page generated from the XML.
Good to know.
- ZugferdProfile.XRechnung is the German public-sector reference profile; with it the embedded XML file is named xrechnung.xml instead of factur-x.xml. Source
- The document must be PDF/A-3 (PdfA3B, PdfA3U or PdfA3A), which the hybrid invoice standards require as the carrier format. Source
- The Alternative relationship, meaning the XML and the visible page carry exactly the same invoice content, is mandatory in Germany for the XRECHNUNG profile. Source
- SelectPdf embeds and identifies the invoice XML you supply; producing it, and making sure it matches the visible invoice, is your application's job. Source
- Electronic invoices are available only in the full commercial SelectPdf library, not in the free Community Edition. Source
Questions, answered.
Short answers about this guide. The SelectPdf.Universal documentation covers every class and option.