← Back to all articles

What is Peppol BIS 3.0? A practical developer introduction

SealDoc Team · · 5 min read

If you build invoicing software in Europe, you will eventually run into Peppol.

For many developers, the first encounter is confusing: XML everywhere, strange identifiers, SMP and SML discovery, UBL invoices, EN16931 rules, validation failures with cryptic messages.

This article explains Peppol BIS Billing 3.0 from a practical engineering perspective. No corporate buzzwords. Just the parts developers actually need to understand.

What is Peppol?

Peppol is a European interoperability network for exchanging electronic business documents. The most common use case is electronic invoicing.

Instead of sending PDFs by email, suppliers send structured invoice documents directly between systems. A Peppol invoice is machine-readable, standardized, validated, and automatically processable.

This allows accounting systems and ERP platforms to process invoices with minimal manual work.

What does BIS 3.0 mean?

BIS stands for Business Interoperability Specifications. Peppol BIS Billing 3.0 defines:

  • invoice structure
  • required fields
  • validation rules
  • allowed code lists
  • transport expectations

The syntax is based on UBL 2.1 and EN16931. In practice: EN16931 defines the semantic invoice model, UBL defines the XML syntax, and Peppol adds interoperability rules on top. You can read more about the EN16931 semantic model in Understanding EN16931.

Why Europe is moving toward mandatory e-invoicing

Multiple EU countries are moving toward mandatory electronic invoicing. Examples include Belgium, Germany, France, Poland, and Italy. Governments want VAT fraud reduction, automated tax processing, interoperable procurement, and standardized invoice exchange.

This means Peppol knowledge is becoming infrastructure knowledge.

What does a Peppol invoice look like?

A Peppol invoice is a UBL 2.1 XML document.

<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
         xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
         xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">

  <cbc:CustomizationID>
    urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1
  </cbc:CustomizationID>
  <cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>
  <cbc:ID>INV-2025-001</cbc:ID>
  <cbc:IssueDate>2025-11-12</cbc:IssueDate>

  <cac:AccountingSupplierParty>
    <!-- seller details -->
  </cac:AccountingSupplierParty>

  <cac:AccountingCustomerParty>
    <!-- buyer details -->
  </cac:AccountingCustomerParty>

  <cac:LegalMonetaryTotal>
    <!-- totals -->
  </cac:LegalMonetaryTotal>
</Invoice>

Unlike PDFs, these documents are meant to be consumed by software. A single invalid field can cause rejection.

The role of EN16931

EN16931 is the European semantic invoice standard. It defines concepts like invoice number, VAT amount, buyer identifier, payment terms, and tax breakdowns. Peppol BIS 3.0 builds on top of this semantic model.

This is why developers often see references like BT-10, BT-49, and BR-CO-10. These are business terms and business rules defined by EN16931.

Common developer pain points

Most Peppol implementations eventually hit the same issues.

Namespace problems. UBL uses many XML namespaces. Getting the declarations wrong produces cryptic parser errors before any business logic runs.

Validation errors. Schematron validation failures can be difficult to debug. The error messages reference BR codes that require the EN16931 spec to interpret.

Identifier formats. Participant IDs and endpoint IDs are strict. A Belgian company using enterprise number scheme 0208 must prefix with exactly that scheme code.

XML signatures. Canonicalization issues often break signature validation. This is a particularly nasty category of bugs because the XML looks correct when you read it, and the signature is valid, but they do not verify against each other. See XML signature validation pitfalls in Peppol for details.

Country-specific profiles. Germany, Belgium, and France each apply additional requirements on top of the base Peppol BIS 3.0 spec. A document valid for one country may be invalid for another.

SMP and SML discovery

Peppol uses a discovery mechanism similar to DNS. The flow roughly works like this:

  1. Hash the participant identifier
  2. Construct a DNS hostname from the hash
  3. Query the SML (Service Metadata Locator) to find the participant’s SMP
  4. Query the SMP (Service Metadata Publisher) to retrieve service metadata
  5. Determine supported document types and endpoint URLs
  6. Deliver the document through an Access Point

The SMP response itself is a signed XML document. That signature is what causes the canonicalization issues mentioned above.

Why PDF invoices are not enough

Traditional PDF invoices are human-readable. Peppol invoices are machine-readable. Many modern systems combine both: PDF/A-3 for visual representation, embedded XML for automation.

This is the foundation of Factur-X and ZUGFeRD. See Factur-X vs ZUGFeRD vs XRechnung vs Peppol for a comparison of how these formats relate to each other.

The difficult part

Generating valid UBL XML is not the hard part. The difficult part is generating XML that survives real-world interoperability:

  • Schematron validation across multiple national rule sets
  • SMP discovery with dynamic namespace prefixes
  • XML signature verification on documents that have been re-serialized
  • Country-specific mandatory fields that are not in the base spec
  • Rounding rules that produce different results depending on whether you round per line or per document

In upcoming articles we will cover: EN16931 in detail, UBL vs CII, SMP discovery internals, XML signature pitfalls, and common Peppol validation errors.

The real cost of the difficult part is not the spec reading. It is the operational overhead: keeping Schematron rule sets up to date with each Peppol BIS release, handling SMP discovery failures gracefully, maintaining country-specific rule variations across Germany, Belgium, France, and Poland.

SealDoc is an API that handles this layer. You submit your invoice data as a JSON payload. The API generates the UBL document, runs EN16931 and Peppol BIS 3.0 Schematron validation, performs SMP discovery, wraps the document in an AS4 envelope, and delivers it to the receiver’s Access Point. If the receiver is not reachable or the document fails validation, you get a structured error indicating exactly which step failed and why.

For testing and debugging, the SealDoc public validator accepts UBL and CII invoice files and returns a plain-English report of every violated EN16931 and Peppol BIS 3.0 rule, with the BT number and business rule code. No account required.


← Back to all articles