Build invoice data into a Belgian Peppol BIS B2B E-Invoice (UBL)
Skill: Convert invoice data into a Peppol BIS Billing 3.0 UBL Invoice for Belgium's mandatory B2B regime
Region: Belgium (België / Belgique)
Category: E-Invoicing — Peppol BIS Billing 3.0 (EN 16931) / Belgian B2B mandate
Does: Takes invoice data (seller, buyer, lines, VAT, payment terms) and produces a UBL 2.1 Invoice that conforms to the EN 16931 semantic model and the Peppol BIS Billing 3.0 customisation, carrying the Belgian CBE/KBO enterprise number as the Peppol endpoint, Belgian VAT category codes, and the structured +++/+++ payment reference — the document a Belgian supplier sends over the Peppol network to a B2B customer.
Standard: OpenPeppol BIS Billing 3.0 — CustomizationID urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0, ProfileID urn:fdc:peppol.eu:2017:poacc:billing:01:1.0, UBL 2.1 Invoice (OASIS UBL-Invoice-2.1.xsd)
From 1 January 2026 structured electronic invoicing is mandatory for most domestic B2B transactions between Belgian VAT-registered taxpayers, and the Peppol network is the default channel. This skill builds the invoice document only — the AI does not transmit it. You must send it through a certified Peppol Access Point and validate it against the official EN 16931 + Peppol BIS schematron rules before sending. Codes, mandate scope, and exemptions can change — verify against the current Peppol BIS Billing 3.0 release and the FOD Financiën / SPF Finances guidance.
When this applies
- A Belgian VAT-registered supplier issues an invoice to another Belgian VAT-registered business (domestic B2B). From 1 Jan 2026 these must be structured Peppol-BIS-compliant e-invoices, not PDF or paper.
- Out of scope: B2C invoices, transactions with non-established parties (handled via other rules), and entities benefiting from a specific exemption (e.g. bankruptcy, certain flat-rate or exempt-only taxpayers) — confirm the recipient is in scope before sending.
- If the recipient is not reachable on Peppol (no registered participant), Belgium provides the Hermes fallback: the invoice is sent to Hermes (a government-run Peppol participant), which delivers it by email as a PDF. Build the same UBL; addressing/fallback is handled by the Access Point.
Conversion procedure
- Read the source. Accept the invoice as PDF text, CSV/JSON line data, or pasted key-value fields. Identify the seller, buyer, invoice number, issue date, due date, currency, each line (description, quantity, unit, net unit price, VAT category + rate), and payment details (IBAN, structured communication).
- Extract identifiers. Pull both parties' CBE/KBO enterprise numbers (10 digits, formatted
0XXX.XXX.XXX) and Belgian VAT numbers (BE+ 10 digits, where the 10 digits equal the enterprise number). If a required identifier is missing or ambiguous, stop and ask — never invent a VAT or enterprise number. - Normalize.
- Enterprise number → digits only for the Peppol endpoint (scheme
0208); VAT number →BE0XXXXXXXXX(no dots) forcac:PartyTaxScheme/cbc:CompanyID. - Dates →
YYYY-MM-DD. - Currency → ISO 4217
EUR; amounts to 2 decimals with a dot separator, no thousands separator. - VAT rate → numeric percentage (
21, not21%); map to a UNCL5305 VAT category code (see code tables). - Structured communication → the 12-digit OGM/VCS reference wrapped as
+++XXX/XXXX/XXXXX+++.
- Enterprise number → digits only for the Peppol endpoint (scheme
- Compute line, tax-subtotal, and document totals per the calculation rules; recompute every total — never copy a printed figure blindly.
- Emit the UBL
Invoicefollowing the document structure and the worked example as the template. SetCustomizationIDandProfileIDexactly. Include onecac:TaxSubtotalper VAT category/rate and onecac:InvoiceLineper line. - Validate against the checklist and the EN 16931 + Peppol BIS schematron before handing the file to the Access Point.
Source → UBL field map
| From the source | → Target element / field |
|---|---|
| (fixed) Peppol customisation | cbc:CustomizationID |
| (fixed) Peppol profile | cbc:ProfileID |
| Invoice number | cbc:ID |
| Issue date → YYYY-MM-DD | cbc:IssueDate |
| Payment due date | cbc:DueDate |
| Invoice type (commercial = 380) | cbc:InvoiceTypeCode |
| Currency (EUR) | cbc:DocumentCurrencyCode |
| Buyer's order / PO reference | cac:OrderReference/cbc:ID |
| Seller endpoint = CBE number, scheme 0208 | cac:AccountingSupplierParty/cac:Party/cbc:EndpointID@schemeID="0208" |
| Seller name | …/cac:Party/cac:PartyName/cbc:Name |
| Seller address (street, city, post code, BE) | …/cac:Party/cac:PostalAddress/*, cac:Country/cbc:IdentificationCode |
| Seller VAT number (BE…) | …/cac:Party/cac:PartyTaxScheme/cbc:CompanyID + cac:TaxScheme/cbc:ID=VAT |
| Seller legal name + enterprise no. | …/cac:Party/cac:PartyLegalEntity/cbc:RegistrationName, cbc:CompanyID@schemeID="0208" |
| Buyer endpoint = CBE number, scheme 0208 | cac:AccountingCustomerParty/cac:Party/cbc:EndpointID@schemeID="0208" |
| Buyer name / address / VAT / legal entity | cac:AccountingCustomerParty/cac:Party/* (mirror seller) |
| IBAN | cac:PaymentMeans/cac:PayeeFinancialAccount/cbc:ID |
| Payment means (credit transfer = 30) | cac:PaymentMeans/cbc:PaymentMeansCode |
Structured communication +++/+++ |
cac:PaymentMeans/cbc:PaymentID |
| VAT category total | cac:TaxTotal/cac:TaxSubtotal/* |
| Total VAT amount | cac:TaxTotal/cbc:TaxAmount |
| Sum of line nets | cac:LegalMonetaryTotal/cbc:LineExtensionAmount |
| Total excl. VAT | cac:LegalMonetaryTotal/cbc:TaxExclusiveAmount |
| Total incl. VAT | cac:LegalMonetaryTotal/cbc:TaxInclusiveAmount |
| Amount due | cac:LegalMonetaryTotal/cbc:PayableAmount |
| Line description / qty / unit price / VAT | cac:InvoiceLine/* |
Every required output field appears above. Repeat cac:TaxSubtotal once per VAT category/rate and cac:InvoiceLine once per line.
Document structure
Invoice (UBL 2.1, root)
├── cbc:CustomizationID urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0
├── cbc:ProfileID urn:fdc:peppol.eu:2017:poacc:billing:01:1.0
├── cbc:ID (invoice number — BT-1)
├── cbc:IssueDate (BT-2, YYYY-MM-DD)
├── cbc:DueDate (BT-9, optional)
├── cbc:InvoiceTypeCode (BT-3, 380 commercial)
├── cbc:DocumentCurrencyCode (BT-5, EUR)
├── cac:OrderReference (optional, buyer PO)
├── cac:AccountingSupplierParty (seller)
│ └── cac:Party
│ ├── cbc:EndpointID schemeID="0208" (CBE/KBO number — Peppol address)
│ ├── cac:PostalAddress (+ cac:Country IdentificationCode=BE)
│ ├── cac:PartyTaxScheme (CompanyID=BE…, TaxScheme ID=VAT)
│ └── cac:PartyLegalEntity (RegistrationName + CompanyID schemeID="0208")
├── cac:AccountingCustomerParty (buyer — mirrors seller)
├── cac:PaymentMeans (optional but typical)
│ ├── cbc:PaymentMeansCode (30 credit transfer)
│ ├── cbc:PaymentID (+++/+++ structured communication)
│ └── cac:PayeeFinancialAccount/cbc:ID (IBAN)
├── cac:PaymentTerms (optional, free text)
├── cac:TaxTotal (once; one TaxSubtotal per rate)
│ ├── cbc:TaxAmount (BT-110, total VAT)
│ └── cac:TaxSubtotal (repeatable)
│ ├── cbc:TaxableAmount
│ ├── cbc:TaxAmount
│ └── cac:TaxCategory (ID + Percent + TaxScheme ID=VAT)
├── cac:LegalMonetaryTotal (document totals)
│ ├── cbc:LineExtensionAmount
│ ├── cbc:TaxExclusiveAmount
│ ├── cbc:TaxInclusiveAmount
│ └── cbc:PayableAmount
└── cac:InvoiceLine (repeatable)
├── cbc:ID / cbc:InvoicedQuantity unitCode / cbc:LineExtensionAmount
├── cac:Item (Name + cac:ClassifiedTaxCategory ID+Percent)
└── cac:Price/cbc:PriceAmount
Mandatory: CustomizationID, ProfileID, ID, IssueDate, InvoiceTypeCode, DocumentCurrencyCode, both parties with VAT identifiers, TaxTotal, LegalMonetaryTotal, and at least one InvoiceLine. PaymentMeans is optional in EN 16931 but expected for Belgian B2B with structured communication.
Code tables
cbc:InvoiceTypeCode (UNCL1001, common values)
| Code | Meaning |
|---|---|
380 |
Commercial invoice (standard) |
381 |
Credit note (use a CreditNote document, not Invoice) |
384 |
Corrected invoice |
389 |
Self-billed invoice |
Peppol/EAS electronic-address scheme IDs (schemeID on EndpointID / legal CompanyID)
| Scheme | Meaning |
|---|---|
0208 |
Belgian enterprise number (CBE / KBO — Banque-Carrefour des Entreprises / Kruispuntbank van Ondernemingen) — the standard Belgian Peppol address |
9925 |
Belgian VAT number (BE…) — legacy/alternate scheme; 0208 is preferred for Belgium |
0192 |
(Norway) — example of a non-BE scheme, do not use for Belgium |
VAT category codes (UNCL5305) — Belgian usage
| Code | Meaning | Typical Belgian rate(s) |
|---|---|---|
S |
Standard rate | 21% (also 12%, 6% reduced rates use S with their Percent) |
Z |
Zero-rated goods/services | 0% |
E |
Exempt from VAT | — (give an exemption reason, BT-120) |
AE |
VAT reverse charge | — (BTW verlegd / autoliquidation; buyer accounts for VAT) |
K |
Intra-Community supply (goods/services) | 0% |
G |
Export outside the EU | 0% |
O |
Outside scope of VAT | — |
cbc:PaymentMeansCode (UNCL4461, common)
| Code | Meaning |
|---|---|
30 |
Credit transfer |
58 |
SEPA credit transfer |
48 |
Bank card |
49 |
Direct debit |
Belgian structured communication (OGM / VCS)
A 12-digit reference rendered as +++DDD/DDDD/DDDDD+++: the first 10 digits are free, the last 2 are a check = the 10-digit number mod 97 (if the remainder is 0, use 97). Placed in cbc:PaymentID.
Calculation rules
- Line net (
LineExtensionAmount) = invoiced quantity × net unit price, rounded to 2 decimals. - Taxable amount per category (
TaxSubtotal/TaxableAmount) = Σ line nets sharing that VAT category + rate, 2 decimals. - VAT per category (
TaxSubtotal/TaxAmount) = taxable amount × (Percent ÷ 100), rounded to 2 decimals. ForAE/K/G/Zthe amount is0.00. - Total VAT (
TaxTotal/TaxAmount) = Σ of everyTaxSubtotal/TaxAmount. - LineExtensionAmount (document) = Σ line nets.
- TaxExclusiveAmount = Σ line nets − allowances + charges (here = Σ line nets).
- TaxInclusiveAmount = TaxExclusiveAmount + Total VAT.
- PayableAmount = TaxInclusiveAmount − any prepaid amount (here = TaxInclusiveAmount).
- Structured communication check digits = first-10-digits mod 97 (0 → 97), zero-padded to 2.
- Recompute every total from the lines; flag any mismatch with a printed source total rather than silently accepting it.
Worked example (end-to-end)
Input — pasted invoice
Seller: Voorbeeld Diensten BV — Kerkstraat 12, 9000 Gent, Belgium
Enterprise no. 0888.222.333, VAT BE 0888.222.333, IBAN BE68 5390 0754 7034
Buyer: Klant Industrie NV — Industrieweg 5, 2000 Antwerpen, Belgium
Enterprise no. 0455.111.222, VAT BE 0455.111.222
Invoice F2026-0042, issued 12 March 2026, due 11 April 2026, PO 4500098765
Line 1: Consultancy services, 10 hours @ 90.00 EUR — VAT 21%
Line 2: Printed manuals, 50 units @ 8.00 EUR — VAT 6%
Structured communication: +++090/9337/55493+++
After extraction + normalization (intermediate)
{
"invoiceNumber": "F2026-0042",
"issueDate": "2026-03-12",
"dueDate": "2026-04-11",
"currency": "EUR",
"orderRef": "4500098765",
"seller": { "endpoint0208": "0888222333", "vat": "BE0888222333", "name": "Voorbeeld Diensten BV",
"street": "Kerkstraat 12", "city": "Gent", "post": "9000", "country": "BE", "iban": "BE68539007547034" },
"buyer": { "endpoint0208": "0455111222", "vat": "BE0455111222", "name": "Klant Industrie NV",
"street": "Industrieweg 5", "city": "Antwerpen", "post": "2000", "country": "BE" },
"paymentId": "+++090/9337/55493+++",
"lines": [
{ "id": "1", "desc": "Consultancy services", "qty": 10, "unit": "HUR", "price": 90.00, "net": 900.00, "vatCat": "S", "vatPct": 21 },
{ "id": "2", "desc": "Printed manuals", "qty": 50, "unit": "C62", "price": 8.00, "net": 400.00, "vatCat": "S", "vatPct": 6 }
],
"taxSubtotals": [
{ "cat": "S", "pct": 21, "base": 900.00, "vat": 189.00 },
{ "cat": "S", "pct": 6, "base": 400.00, "vat": 24.00 }
],
"totals": { "lineExt": 1300.00, "taxExcl": 1300.00, "taxAmt": 213.00, "taxIncl": 1513.00, "payable": 1513.00 }
}
Output — Peppol BIS Billing 3.0 UBL Invoice
<?xml version="1.0" encoding="UTF-8"?>
<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</cbc:CustomizationID>
<cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>
<cbc:ID>F2026-0042</cbc:ID>
<cbc:IssueDate>2026-03-12</cbc:IssueDate>
<cbc:DueDate>2026-04-11</cbc:DueDate>
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
<cac:OrderReference>
<cbc:ID>4500098765</cbc:ID>
</cac:OrderReference>
<cac:AccountingSupplierParty>
<cac:Party>
<cbc:EndpointID schemeID="0208">0888222333</cbc:EndpointID>
<cac:PartyName>
<cbc:Name>Voorbeeld Diensten BV</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>Kerkstraat 12</cbc:StreetName>
<cbc:CityName>Gent</cbc:CityName>
<cbc:PostalZone>9000</cbc:PostalZone>
<cac:Country>
<cbc:IdentificationCode>BE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>BE0888222333</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Voorbeeld Diensten BV</cbc:RegistrationName>
<cbc:CompanyID schemeID="0208">0888222333</cbc:CompanyID>
</cac:PartyLegalEntity>
</cac:Party>
</cac:AccountingSupplierParty>
<cac:AccountingCustomerParty>
<cac:Party>
<cbc:EndpointID schemeID="0208">0455111222</cbc:EndpointID>
<cac:PartyName>
<cbc:Name>Klant Industrie NV</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>Industrieweg 5</cbc:StreetName>
<cbc:CityName>Antwerpen</cbc:CityName>
<cbc:PostalZone>2000</cbc:PostalZone>
<cac:Country>
<cbc:IdentificationCode>BE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>BE0455111222</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Klant Industrie NV</cbc:RegistrationName>
<cbc:CompanyID schemeID="0208">0455111222</cbc:CompanyID>
</cac:PartyLegalEntity>
</cac:Party>
</cac:AccountingCustomerParty>
<cac:PaymentMeans>
<cbc:PaymentMeansCode>30</cbc:PaymentMeansCode>
<cbc:PaymentID>+++090/9337/55493+++</cbc:PaymentID>
<cac:PayeeFinancialAccount>
<cbc:ID>BE68539007547034</cbc:ID>
</cac:PayeeFinancialAccount>
</cac:PaymentMeans>
<cac:PaymentTerms>
<cbc:Note>Payment within 30 days, structured communication +++090/9337/55493+++</cbc:Note>
</cac:PaymentTerms>
<cac:TaxTotal>
<cbc:TaxAmount currencyID="EUR">213.00</cbc:TaxAmount>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="EUR">900.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">189.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:TaxSubtotal>
<cbc:TaxableAmount currencyID="EUR">400.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">24.00</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>6</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
</cac:TaxTotal>
<cac:LegalMonetaryTotal>
<cbc:LineExtensionAmount currencyID="EUR">1300.00</cbc:LineExtensionAmount>
<cbc:TaxExclusiveAmount currencyID="EUR">1300.00</cbc:TaxExclusiveAmount>
<cbc:TaxInclusiveAmount currencyID="EUR">1513.00</cbc:TaxInclusiveAmount>
<cbc:PayableAmount currencyID="EUR">1513.00</cbc:PayableAmount>
</cac:LegalMonetaryTotal>
<cac:InvoiceLine>
<cbc:ID>1</cbc:ID>
<cbc:InvoicedQuantity unitCode="HUR">10</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">900.00</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Consultancy services</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">90.00</cbc:PriceAmount>
</cac:Price>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>2</cbc:ID>
<cbc:InvoicedQuantity unitCode="C62">50</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">400.00</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Printed manuals</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>6</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">8.00</cbc:PriceAmount>
</cac:Price>
</cac:InvoiceLine>
</Invoice>
Normalisations shown: VAT BE 0888.222.333 → BE0888222333 (dots stripped); enterprise no. → 0888222333 on EndpointID schemeID="0208"; dates 12 March 2026 → 2026-03-12; rate 21% → 21; line 1 net recomputed 10 × 90.00 = 900.00; line 2 net 50 × 8.00 = 400.00; VAT recomputed 900.00 × 21% = 189.00 and 400.00 × 6% = 24.00; total VAT 189.00 + 24.00 = 213.00; TaxInclusiveAmount 1300.00 + 213.00 = 1513.00. The structured communication 090/9337/55493 checks out: 0909337554 mod 97 = 93. The Access Point routes by the buyer EndpointID (0208:0455111222); if that participant is not registered, the same UBL is delivered through Hermes to the buyer by email.
Validation checklist
- All required fields extracted; AI asked about anything missing or ambiguous (no invented VAT or enterprise numbers, dates, or amounts)
-
CustomizationID=urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0andProfileID=urn:fdc:peppol.eu:2017:poacc:billing:01:1.0, exactly - Both parties carry
EndpointID schemeID="0208"(CBE/KBO number) and aPartyTaxScheme/CompanyID=BE+ 10 digits -
InvoiceTypeCode=380for a commercial invoice (credit notes use aCreditNotedocument) - Dates in
YYYY-MM-DD;DocumentCurrencyCode=EUR; amounts 2dp dot-decimal withcurrencyID="EUR" - Each VAT category uses a valid UNCL5305 code (
S/Z/E/AE/K/G/O) with the correctPercent - One
cac:TaxSubtotalper VAT category+rate;TaxAmount=TaxableAmount × Percent/100(2dp) -
TaxTotal/TaxAmount= Σ subtotals;LineExtensionAmount= Σ line nets;TaxInclusiveAmount=TaxExclusiveAmount + TaxAmount;PayableAmountcorrect - Structured communication formatted
+++XXX/XXXX/XXXXX+++with valid mod-97 check digits, placed incbc:PaymentID - At least one
cac:InvoiceLine; lineLineExtensionAmount= quantity ×PriceAmount - Document validated against the OASIS UBL 2.1
InvoiceXSD and the EN 16931 + Peppol BIS Billing 3.0 schematron before sending via a certified Access Point (or Hermes fallback)
Last updated: 2026-06-13 — verify the active Peppol BIS Billing 3.0 CustomizationID/ProfileID, the EAS/scheme code (0208), the Belgian B2B mandate scope and exemptions, and the Hermes fallback rules against the current OpenPeppol release and FOD Financiën / SPF Finances guidance before use.