Paperbolt is now live on the Shopify App Store Browse the listing
Belgium / EU Validator-passing

Peppol BIS Billing 3.0

Validator-passing UBL 2.1 invoice XML for the EU Peppol network. The Belgium B2B mandate (effective 2026-01-01) is the immediate use case; every other Peppol member state shares the schema.

Live preview Rendered through the same Chromium pipeline that ships the PDF
Invoice INV-2026-0042
Peppol BIS Billing 3.0
Issue 15 Jan 2026
Due 14 Feb 2026
Buyer ref PO-77821
From
Atelier Lumen BVBA
Rue de la Loi 42
1000 Brussels
BE
VAT BE0123456749
Peppol ID 0123456749
To
Koffiehuis De Maan NV
Korenmarkt 9
9000 Ghent
BE
VAT BE0987654394
Peppol ID 0987654394
DescriptionQtyUnitVATAmount
Brand identity design (logo, colour system, typography pack)1.002400.0021%2400.00
Web design — landing page + 4 inner pages1.001800.0021%1800.00
Photography day rate2.00650.0021%1300.00
SubtotalEUR 5500.00
VATEUR 1155.00
Total dueEUR 6655.00
IBAN BE68539007547034    BIC BBRUBEBB
Net 30 days from issue date.
Sample structured output UBL 2.1
<?xml version="1.0" encoding="UTF-8"?>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2">
  <cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0</cbc:CustomizationID>
  <cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>
  <cbc:ID>INV-2026-0042</cbc:ID>
  <cbc:IssueDate>2026-01-15</cbc:IssueDate>
  <cbc:DueDate>2026-02-14</cbc:DueDate>
  <cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
  <cbc:Note>Payment under 30-day net terms; reference invoice number on transfer.</cbc:Note>
  <cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
  <cbc:BuyerReference>PO-77821</cbc:BuyerReference>
  <cac:AccountingSupplierParty>
    <cac:Party>
      <cbc:EndpointID schemeID="0208">0123456749</cbc:EndpointID>
      <cac:PartyName>
        <cbc:Name>Atelier Lumen BVBA</cbc:Name>
      </cac:PartyName>
      <cac:PostalAddress>
        <cbc:StreetName>Rue de la Loi 42</cbc:StreetName>
        <cbc:CityName>Brussels</cbc:CityName>
        <cbc:PostalZone>1000</cbc:PostalZone>
        <cac:Country>
          <cbc:IdentificationCode>BE</cbc:IdentificationCode>
        </cac:Country>
      </cac:PostalAddress>
      <cac:PartyTaxScheme>
        <cbc:CompanyID>BE0123456749</cbc:CompanyID>
        <cac:TaxScheme>
          <cbc:ID>VAT</cbc:ID>
        </cac:TaxScheme>
      </cac:PartyTaxScheme>
      <cac:PartyLegalEntity>
        <cbc:RegistrationName>Atelier Lumen BVBA</cbc:RegistrationName>
      </cac:PartyLegalEntity>
    </cac:Party>
  </cac:AccountingSupplierParty>
  <cac:AccountingCustomerParty>
    <cac:Party>
      <cbc:EndpointID schemeID="0208">0987654394</cbc:EndpointID>
      <cac:PartyName>
        <cbc:Name>Koffiehuis De Maan NV</cbc:Name>
      </cac:PartyName>
      <cac:PostalAddress>
        <cbc:StreetName>Korenmarkt 9</cbc:StreetName>
        <cbc:CityName>Ghent</cbc:CityName>
        <cbc:PostalZone>9000</cbc:PostalZone>
        <cac:Country>
          <cbc:IdentificationCode>BE</cbc:IdentificationCode>
        </cac:Country>
      </cac:PostalAddress>
      <cac:PartyTaxScheme>
        <cbc:CompanyID>BE0987654394</cbc:CompanyID>
        <cac:TaxScheme>
          <cbc:ID>VAT</cbc:ID>
        </cac:TaxScheme>
      </cac:PartyTaxScheme>
      <cac:PartyLegalEntity>
        <cbc:RegistrationName>Koffiehuis De Maan NV</cbc:RegistrationName>
      </cac:PartyLegalEntity>
    </cac:Party>
  </cac:AccountingCustomerParty>
  <cac:PaymentMeans>
    <cbc:PaymentMeansCode>30</cbc:PaymentMeansCode>
    <cac:PayeeFinancialAccount>
      <cbc:ID>BE68539007547034</cbc:ID>
      <cac:FinancialInstitutionBranch>
        <cbc:ID>BBRUBEBB</cbc:ID>
      </cac:FinancialInstitutionBranch>
    </cac:PayeeFinancialAccount>
  </cac:PaymentMeans>
  <cac:PaymentTerms>
    <cbc:Note>Net 30 days from issue date.</cbc:Note>
  </cac:PaymentTerms>
  <cac:TaxTotal>
    <cbc:TaxAmount currencyID="EUR">1155.00</cbc:TaxAmount>
    <cac:TaxSubtotal>
      <cbc:TaxableAmount currencyID="EUR">5500.00</cbc:TaxableAmount>
      <cbc:TaxAmount currencyID="EUR">1155.00</cbc:TaxAmount>
      <cac:TaxCategory>
        <cbc:ID>S</cbc:ID>
        <cbc:Percent>21</cbc:Percent>
        <cac:TaxScheme>
          <cbc:ID>VAT</cbc:ID>
        </cac:TaxScheme>
      </cac:TaxCategory>
    </cac:TaxSubtotal>
  </cac:TaxTotal>
  <cac:LegalMonetaryTotal>
    <cbc:LineExtensionAmount currencyID="EUR">5500.00</cbc:LineExtensionAmount>
    <cbc:TaxExclusiveAmount currencyID="EUR">5500.00</cbc:TaxExclusiveAmount>
    <cbc:TaxInclusiveAmount currencyID="EUR">6655.00</cbc:TaxInclusiveAmount>
    <cbc:PayableAmount currencyID="EUR">6655.00</cbc:PayableAmount>
  </cac:LegalMonetaryTotal>
  <cac:InvoiceLine>
    <cbc:ID>1</cbc:ID>
    <cbc:InvoicedQuantity unitCode="EA">1.00</cbc:InvoicedQuantity>
    <cbc:LineExtensionAmount currencyID="EUR">2400.00</cbc:LineExtensionAmount>
    <cac:Item>
      <cbc:Name>Brand identity design (logo, colour system, typography pack)</cbc:Name>
      <cac:ClassifiedTaxCategory>
        <cbc:ID>S</cbc:ID>
        <cbc:Percent>21</cbc:Percent>
        <cac:TaxScheme>
          <cbc:ID>VAT</cbc:ID>
        </cac:TaxScheme>
      </cac:ClassifiedTaxCategory>
    </cac:Item>
    <cac:Price>
      <cbc:PriceAmount currencyID="EUR">2400.00</cbc:PriceAmount>
    </cac:Price>
  </cac:InvoiceLine>
  <cac:InvoiceLine>
    <cbc:ID>2</cbc:ID>
    <cbc:InvoicedQuantity unitCode="EA">1.00</cbc:InvoicedQuantity>
    <cbc:LineExtensionAmount currencyID="EUR">1800.00</cbc:LineExtensionAmount>
    <cac:Item>
      <cbc:Name>Web design — landing page + 4 inner pages</cbc:Name>
      <cac:ClassifiedTaxCategory>
        <cbc:ID>S</cbc:ID>
        <cbc:Percent>21</cbc:Percent>
        <cac:TaxScheme>
          <cbc:ID>VAT</cbc:ID>
        </cac:TaxScheme>
      </cac:ClassifiedTaxCategory>
    </cac:Item>
    <cac:Price>
      <cbc:PriceAmount currencyID="EUR">1800.00</cbc:PriceAmount>
    </cac:Price>
  </cac:InvoiceLine>
  <cac:InvoiceLine>
    <cbc:ID>3</cbc:ID>
    <cbc:InvoicedQuantity unitCode="DAY">2.00</cbc:InvoicedQuantity>
    <cbc:LineExtensionAmount currencyID="EUR">1300.00</cbc:LineExtensionAmount>
    <cac:Item>
      <cbc:Name>Photography day rate</cbc:Name>
      <cac:ClassifiedTaxCategory>
        <cbc:ID>S</cbc:ID>
        <cbc:Percent>21</cbc:Percent>
        <cac:TaxScheme>
          <cbc:ID>VAT</cbc:ID>
        </cac:TaxScheme>
      </cac:ClassifiedTaxCategory>
    </cac:Item>
    <cac:Price>
      <cbc:PriceAmount currencyID="EUR">650.00</cbc:PriceAmount>
    </cac:Price>
  </cac:InvoiceLine>
</Invoice>

What this template emits

A single invoice goes through two legs at once.

Leg 1, UBL 2.1 XML. The structured leg. It carries the CustomizationID urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0 and the ProfileID urn:fdc:peppol.eu:2017:poacc:billing:01:1.0. That combination is what the Belgian tax authority and every other Peppol BIS Billing 3.0 endpoint validates against. The fields rolled into the XML cover the EN 16931 mandatory set: supplier and customer Peppol Participant IDs, VAT registration IDs, the postal addresses, the line-item invoiced quantities and unit prices, the VAT subtotals broken out by tax category, the legal monetary totals, and the payment means (IBAN + BIC for SEPA credit transfer).

Leg 2, print-ready PDF. The same data renders as a normal PDF invoice your customer can read. The visual layout is built in HTML and CSS so you can rebrand it in the designer. The rendering pipeline is Chromium, which means Arabic, Hindi, Hebrew, Thai, and CJK render the same way they do in your browser. No font packages to install, no DOMPDF fallback.

Why the Belgian mandate matters first

Belgium published the Royal Decree mandating Peppol BIS Billing 3.0 for all B2B transactions between Belgian VAT-registered entities, effective 2026-01-01. There is a three-month tolerance window during which non-conformant invoices are accepted while the receiver complains, but from 2026-04-01 onward a non-conformant invoice can be legally rejected.

Belgium chose Peppol BIS Billing 3.0 because the network is already live across the Nordics, the Netherlands, Italy, and parts of Germany. The same schema works against the German ZUGFeRD 2.1 / Factur-X profile (same EN 16931 base) and the Italian SDI (with a different syntax binding). Building the Peppol BIS Billing 3.0 emitter once gets you ready for the wider EU ViDA rollout.

What the validator checks

The official Peppol Schematron checks rules grouped under CEN/EN 16931 (BR-* business rules, BR-CL-* code-list rules) and Peppol-specific extensions (PEPPOL-EN16931-*). Common rejections this template avoids:

  • Missing or invalid CustomizationID (the most common rejection when teams hand-roll the XML).
  • VAT category code that does not match the percentage (S with 0% fails; use Z for zero-rated, E for exempt).
  • Line totals that do not sum to the document totals within 0.02 currency units of rounding tolerance.
  • Endpoint IDs without a scheme prefix (0208:0123456789 for the Belgian Crossroads Bank for Enterprises; the leading 0208: is required).

The emitter computes the rolled-up totals from the line items, so the rounding-tolerance class of failures is impossible by construction. The other rules are enforced at the Go API surface so an invalid invoice never reaches the XML encoder.

How to use it

  1. Sign up for a free LightningPDF account (100 PDFs/month, no card).
  2. Click Customize in LightningPDF to fork the template into the designer.
  3. Replace the supplier block with your company details (Peppol Participant ID, VAT registration, legal entity name, postal address).
  4. POST your invoice JSON to /api/v1/pdf/download?format=peppol-bis-3. The response is the PDF; the matching UBL XML is available at /api/v1/einvoice/peppol/<id>.xml.
  5. Send the PDF to the customer over your usual channel; send the XML to the Peppol Access Point.

Frequently asked questions

Is this PDF/A-3 conformant?

The PDF leg is rendered through the same Chromium engine that ships the rest of LightningPDF's PDFs. On the Pro tier, the engine is configured for PDF/A-3 conformance: embedded ICC profile, font subsetting, XMP metadata identifying the conformance level, and the UBL XML attached with AFRelationship="Alternative". On the Free and Starter tiers the PDF prints as a normal PDF and the XML is delivered as a separate file. Both are still validator-passing on the structured leg, but the Free/Starter PDFs are not certified as PDF/A-3.

Validation status

On 2026-06-03 our sample invoice (pkg/einvoice/SamplePeppolInvoice) was run through the official OpenPEPPOL Schematron compiled with Saxon-HE 12.7. Both rule packs returned clean:

  • CEN EN 16931 ruleset: 0 errors, 0 warnings
  • Peppol BIS Billing 3.0 ruleset: 0 errors, 0 warnings

The raw SVRL outputs live under test-results/validators/peppol/reports/ in the repository. Reproduce with bash scripts/run_peppol_validator.sh <invoice>.

Do you publish the validator reports?

Yes. The Peppol Schematron output against this template's sample invoice is published at lightningpdf.dev/proof, refreshed on each release.

Can I extend this template to ZUGFeRD or Factur-X?

The German ZUGFeRD 2.1 BASIC profile and the French Factur-X 1.0 BASIC profile are both CEN/EN 16931 compliant subsets of UBL or CII syntax. The same line-item model the Peppol emitter consumes drives a separate CII-syntax emitter; both target the same EN 16931 semantics. The other Phase 1 templates (ZATCA, India GST, Japan qualified invoice) reuse the line-item model with format-specific emitters.

What if my buyer is not Peppol-registered yet?

You can still send the PDF leg over email; that is a normal invoice. Belgian mandate compliance specifically requires the structured XML leg over Peppol, so a non-registered buyer is the buyer's compliance problem, not yours. Many Belgian Access Point providers offer a free receiving-only registration that takes under an hour.