Create and read Peppol BIS Billing 3.0 from .NET.
Peppol BIS Billing 3.0 is a CIUS on top of EN 16931 – technically the same UBL structure as XRechnung, told apart by the specification identifier (BT-24). With FactoorSharp both come out of the same invoice model, in C# and VB.NET.
This page is about the document level: creating, reading, identifying. Sending invoices across the Peppol network is an access point's job – what that means is spelled out below.
FacturXInvoice.SetLicense("YOUR-LICENSE-KEY");
var invoice = FacturXInvoice.CreateInvoice(
"RE-2025-0042",
new DateTime(2025, 9, 3),
CurrencyCodes.EUR);
invoice.SetSeller("BikeTech GmbH", "10115", "Berlin", "Radweg 12", CountryCodes.DE);
invoice.SetBuyer("City Bikes AG", "20457", "Hamburg", "Hafenstraße 45", CountryCodes.DE);
// flag the invoice as Peppol BIS Billing 3.0 instead of XRechnung (BT-24)
invoice.SpecificationIdentifier = SpecificationIdentifiers.PeppolBisBilling30;
// Peppol has no CII syntax, so UBL is stated explicitly
invoice.Save("peppol-invoice.xml", ZUGFeRDVersion.Version25, Profile.XRechnung, ZUGFeRDFormats.UBL);
FacturXInvoice.SetLicense("YOUR-LICENSE-KEY")
Dim invoice = FacturXInvoice.CreateInvoice(
"RE-2025-0042",
New DateTime(2025, 9, 3),
CurrencyCodes.EUR)
invoice.SetSeller("BikeTech GmbH", "10115", "Berlin", "Radweg 12", CountryCodes.DE)
invoice.SetBuyer("City Bikes AG", "20457", "Hamburg", "Hafenstraße 45", CountryCodes.DE)
' flag the invoice as Peppol BIS Billing 3.0 instead of XRechnung (BT-24)
invoice.SpecificationIdentifier = SpecificationIdentifiers.PeppolBisBilling30
' Peppol has no CII syntax, so UBL is stated explicitly
invoice.Save("peppol-invoice.xml", ZUGFeRDVersion.Version25, Profile.XRechnung, ZUGFeRDFormats.UBL)
Peppol BIS Billing 3.0
Specification identifier (BT-24), business process (BT-23) and UBL output – from the same invoice model as ZUGFeRD and XRechnung.
Electronic addresses
Endpoint identifiers for seller and buyer (BT-34 / BT-49) with their scheme – VAT number, GLN and the other EAS codes.
XRechnung and Peppol side by side
One invoice object, three target formats: XRechnung, XRechnung with the KoSIT extension, and Peppol BIS Billing 3.0.
Incoming invoices
Read UBL invoices, recognise the rule set from BT-24 and evaluate the endpoint identifiers.
XRechnung or Peppol BIS Billing 3.0? Same core, different identifier
Both are CIUS (Core Invoice Usage Specification) on top of EN 16931 and use the same UBL
structure. What tells them apart is the specification identifier BT-24, which appears as
cbc:CustomizationID in the XML.
In practice that means: if you already produce XRechnung documents, Peppol needs no second invoice model and no second library – just a different identifier when saving.
BT-24 is not a closed code list: CIUS of other EU countries can be set through
SpecificationIdentifier as a URN as well.
// The same invoice model, three target formats – told apart by BT-24 alone:
// 1. XRechnung (the default for the XRechnung profile, identifier set automatically)
invoice.Save("xrechnung.xml", ZUGFeRDVersion.Version25, Profile.XRechnung);
// 2. XRechnung with the KoSIT extension
invoice.SpecificationIdentifier = SpecificationIdentifiers.XRechnung30Extension;
invoice.Save("xrechnung-extension.xml", ZUGFeRDVersion.Version25, Profile.XRechnung);
// 3. Peppol BIS Billing 3.0
invoice.SpecificationIdentifier = SpecificationIdentifiers.PeppolBisBilling30;
invoice.Save("peppol-invoice.xml", ZUGFeRDVersion.Version25, Profile.XRechnung, ZUGFeRDFormats.UBL);
' The same invoice model, three target formats – told apart by BT-24 alone:
' 1. XRechnung (the default for the XRechnung profile, identifier set automatically)
invoice.Save("xrechnung.xml", ZUGFeRDVersion.Version25, Profile.XRechnung)
' 2. XRechnung with the KoSIT extension
invoice.SpecificationIdentifier = SpecificationIdentifiers.XRechnung30Extension
invoice.Save("xrechnung-extension.xml", ZUGFeRDVersion.Version25, Profile.XRechnung)
' 3. Peppol BIS Billing 3.0
invoice.SpecificationIdentifier = SpecificationIdentifiers.PeppolBisBilling30
invoice.Save("peppol-invoice.xml", ZUGFeRDVersion.Version25, Profile.XRechnung, ZUGFeRDFormats.UBL)
What Peppol additionally requires
The specification identifier alone does not turn an XRechnung into a valid Peppol invoice. Peppol BIS Billing 3.0 requires two things that stay optional in a plain XRechnung.
For XRechnung documents sent to German public authorities, BT-10 usually already holds the Leitweg-ID – so that requirement tends to be met already.
// Electronic addresses of seller and buyer (BT-34 / BT-49).
// Common choices are the VAT number (scheme 9930 for Germany) or a GLN (scheme 0088).
invoice.SetSellerElectronicAddress("DE123456789", ElectronicAddressSchemeIdentifiers.GermanyVatNumber);
invoice.SetBuyerElectronicAddress("DE987654321", ElectronicAddressSchemeIdentifiers.GermanyVatNumber);
// Peppol BIS Billing 3.0 requires at least one of these two fields
invoice.ReferenceOrderNo = "PROJ-4711"; // buyer reference, BT-10
// or alternatively:
invoice.OrderNo = "PO-2026-0042"; // purchase order reference, BT-13
' Electronic addresses of seller and buyer (BT-34 / BT-49).
' Common choices are the VAT number (scheme 9930 for Germany) or a GLN (scheme 0088).
invoice.SetSellerElectronicAddress("DE123456789", ElectronicAddressSchemeIdentifiers.GermanyVatNumber)
invoice.SetBuyerElectronicAddress("DE987654321", ElectronicAddressSchemeIdentifiers.GermanyVatNumber)
' Peppol BIS Billing 3.0 requires at least one of these two fields
invoice.ReferenceOrderNo = "PROJ-4711" ' buyer reference, BT-10
' or alternatively:
invoice.OrderNo = "PO-2026-0042" ' purchase order reference, BT-13
Processing incoming Peppol invoices
Reading works exactly as it does for ZUGFeRD and XRechnung. Which rule set the sender used is recorded in BT-24; the endpoint identifiers sit on the parties.
Electronic addresses are not limited to seller and buyer – the data model provides for them at 19 business terms, wherever a party appears in the document.
var invoice = FacturXInvoice.Load("peppol-invoice.xml");
// Which rule set was it? BT-24 appears as cbc:CustomizationID in the document.
if (invoice.SpecificationIdentifier == SpecificationIdentifiers.PeppolBisBilling30)
{
var sellerEndpoint = invoice.Seller.ElectronicAddress; // BT-34
var buyerEndpoint = invoice.Buyer.ElectronicAddress; // BT-49
}
Dim invoice = FacturXInvoice.Load("peppol-invoice.xml")
' Which rule set was it? BT-24 appears as cbc:CustomizationID in the document.
If invoice.SpecificationIdentifier = SpecificationIdentifiers.PeppolBisBilling30 Then
Dim sellerEndpoint = invoice.Seller.ElectronicAddress ' BT-34
Dim buyerEndpoint = invoice.Buyer.ElectronicAddress ' BT-49
End If
Where FactoorSharp stops: the access point
Peppol consists of two parts that are often lumped together: the document and the network. FactoorSharp covers the first – it creates, reads and identifies Peppol BIS Billing 3.0 documents. The second part, transport across the Peppol network over AS4, is handled by an access point.
With FactoorSharp
- Create and read Peppol BIS Billing 3.0 (UBL)
- Set and evaluate the specification identifier BT-24
- Business process BT-23 – set automatically on save
- Endpoint identifiers BT-34 / BT-49 with their EAS scheme
- Fill the mandatory fields BT-10 / BT-13
- ZUGFeRD, Factur-X and XRechnung from the same model
What an access point is for
- Sending and receiving across the Peppol network (AS4)
- Registration as a Peppol participant
- Recipient lookup via SMP and SML
- Certificates and delivery receipts
That division of labour is both common and practical: the access point transports what your application produces. FactoorSharp makes sure the document you hand over follows the rules before it leaves the building.
Typical scenarios
- Invoicing business partners elsewhere in the EU who receive via Peppol
- Feeding an existing access point as the document source
- Extending an existing XRechnung integration to Peppol
- Processing incoming UBL invoices from the Peppol network
A good fit for
- ERP and inventory management systems
- E-commerce and SaaS platforms
- Invoice portals and middleware
- Custom .NET business applications
What you gain
- One invoice model for ZUGFeRD, XRechnung and Peppol
- No second library for UBL
- Validation before sending instead of rejection by the recipient
- A clear .NET API instead of bespoke XML logic
Frequently asked questions
No. FactoorSharp works at the document level: it creates, reads and validates Peppol BIS Billing 3.0 documents. Sending across the Peppol network runs over AS4 and requires an access point as well as registration as a Peppol participant.
In practice this is a clean division of labour: your application produces the document with FactoorSharp, the access point transports it.
Both are CIUS on top of EN 16931 and use the same UBL structure. What tells them apart is the specification identifier BT-24 (cbc:CustomizationID). XRechnung is the German standard for public authorities; Peppol BIS Billing 3.0 is the rule set for exchange across the Peppol network.
Peppol additionally requires endpoint identifiers for both parties (BT-34 / BT-49) and at least one of the fields BT-10 or BT-13.
ZUGFeRDFormats.UBL when saving. For Peppol that is mandatory, because Peppol BIS Billing 3.0 has no CII syntax.ElectronicAddressSchemeIdentifiers; electronic addresses are not limited to seller and buyer.Peppol BIS Billing 3.0 in your .NET application?
Get started with FactoorSharp in a few minutes, or go straight to the licences and pricing.