Documentation

API Reference

Our comprehensive API reference documentation.

Visit API Reference
Back to documentation

Understanding Peppol UBL Format

Peppol Fundamentals

This guide explains the Universal Business Language (UBL) format used in Peppol document exchange.

What is UBL?

UBL (Universal Business Language) is an XML-based standard for electronic business documents. In the Peppol network, UBL serves as the foundation for standardized document exchange between businesses across borders and systems.

UBL in Peppol

Peppol uses specific UBL document formats defined by the EN16931 European standard for electronic invoicing. Documents sent through Peppol must comply with these standards to ensure interoperability across the network.

The most common UBL document type in Peppol is:

urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1
text

This identifier specifies that the document is:

  • A UBL Invoice document (version 2)
  • Compliant with EN16931:2017 standard
  • Following Peppol BIS Billing 3.0 specifications
  • Using syntax version 2.1

Document Structure

A UBL invoice in Peppol contains several key sections:

  1. Header Information

Contains basic invoice details like number, dates, and references:

<cbc:ID>INV-2025-001</cbc:ID>
<cbc:IssueDate>2024-05-15</cbc:IssueDate>
<cbc:DueDate>2024-06-15</cbc:DueDate>
<cbc:Note>Thank you for your business</cbc:Note>
<cbc:BuyerReference>PO-2024-001</cbc:BuyerReference>
xml
  1. Parties

Defines seller and buyer information:

<cac:AccountingSupplierParty>
  <cac:Party>
    <cac:PartyLegalEntity>
      <cbc:RegistrationName>Your Company</cbc:RegistrationName>
      <cbc:CompanyID schemeID="0208">0123456789</cbc:CompanyID>
    </cac:PartyLegalEntity>
    <cac:PostalAddress>
      <cbc:StreetName>Your Street 1</cbc:StreetName>
      <cbc:CityName>Brussels</cbc:CityName>
      <cbc:PostalZone>1000</cbc:PostalZone>
      <cac:Country>
        <cbc:IdentificationCode>BE</cbc:IdentificationCode>
      </cac:Country>
    </cac:PostalAddress>
  </cac:Party>
</cac:AccountingSupplierParty>
xml
  1. Payment Information

Contains payment terms and bank details:

<cac:PaymentMeans>
  <cbc:PaymentMeansCode>30</cbc:PaymentMeansCode>
  <cbc:PaymentID>INV-2025-001</cbc:PaymentID>
  <cac:PayeeFinancialAccount>
    <cbc:ID>BE1234567890</cbc:ID>
  </cac:PayeeFinancialAccount>
</cac:PaymentMeans>
xml
  1. Invoice lines

Each product or service line item:

<cac:InvoiceLine>
  <cbc:ID>1</cbc:ID>
  <cbc:InvoicedQuantity unitCode="HUR">10.00</cbc:InvoicedQuantity>
  <cbc:LineExtensionAmount currencyID="EUR">1000.00</cbc:LineExtensionAmount>
  <cac:Item>
    <cbc:Name>Consulting Services</cbc:Name>
    <cbc:Description>Professional consulting services</cbc:Description>
    <cac:SellersItemIdentification>
      <cbc:ID>CS-001</cbc:ID>
    </cac:SellersItemIdentification>
    <cac:ClassifiedTaxCategory>
      <cbc:ID>S</cbc:ID>
      <cbc:Percent>21.00</cbc:Percent>
      <cac:TaxScheme>
        <cbc:ID>VAT</cbc:ID>
      </cac:TaxScheme>
    </cac:ClassifiedTaxCategory>
  </cac:Item>
  <cac:Price>
    <cbc:PriceAmount currencyID="EUR">100.00</cbc:PriceAmount>
  </cac:Price>
</cac:InvoiceLine>
xml
  1. Tax Information

VAT breakdowns and totals:

<cac:TaxTotal>
  <cbc:TaxAmount currencyID="EUR">210.00</cbc:TaxAmount>
  <cac:TaxSubtotal>
    <cbc:TaxableAmount currencyID="EUR">1000.00</cbc:TaxableAmount>
    <cbc:TaxAmount currencyID="EUR">210.00</cbc:TaxAmount>
    <cac:TaxCategory>
      <cbc:ID>S</cbc:ID>
      <cbc:Percent>21.00</cbc:Percent>
      <cac:TaxScheme>
        <cbc:ID>VAT</cbc:ID>
      </cac:TaxScheme>
    </cac:TaxCategory>
  </cac:TaxSubtotal>
</cac:TaxTotal>
xml
  1. Monetary Totals

Summary of invoice amounts:

<cac:LegalMonetaryTotal>
  <cbc:LineExtensionAmount currencyID="EUR">1000.00</cbc:LineExtensionAmount>
  <cbc:TaxExclusiveAmount currencyID="EUR">1000.00</cbc:TaxExclusiveAmount>
  <cbc:TaxInclusiveAmount currencyID="EUR">1210.00</cbc:TaxInclusiveAmount>
  <cbc:PayableAmount currencyID="EUR">1210.00</cbc:PayableAmount>
</cac:LegalMonetaryTotal>
xml

VAT Categories

Peppol UBL supports various VAT categories, including:

CodeDescription
SStandard rate
ZZero rated goods
EExempt from tax
AEVAT Reverse Charge
KVAT exempt for EEA intra-community supply
GFree export item, VAT not charged
OServices outside scope of tax
LCanary Islands general indirect tax
MTax for production, services and importation in Ceuta and Melilla
BTransferred (VAT), In Italy

Unit Codes

Common unit codes in Peppol UBL include:

CodeDescription
C62One (unit)
DAYDay
HURHour
MINMinute
MONMonth
WEEWeek
KGMKilogram
LTRLiter
MTRMeter
KWHKilowatt hour

The complete list of unit codes can be found in the UN/ECE Recommendation 20.

Document Types

Common document types in Peppol:

TypeDescription
InvoiceStandard invoice
CreditNoteCredit note correcting an invoice
OrderPurchase order
OrderResponseResponse to a purchase order
CatalogueProduct catalogue
DespatchAdviceShipping notice

Attachments

UBL documents can include attachments embedded as base64-encoded content:

<cac:AdditionalDocumentReference>
  <cbc:ID>ATT-001</cbc:ID>
  <cbc:DocumentType>Commercial invoice</cbc:DocumentType>
  <cac:Attachment>
    <cbc:EmbeddedDocumentBinaryObject mimeCode="application/pdf" filename="invoice.pdf">
      <!-- Base64 encoded content -->
    </cbc:EmbeddedDocumentBinaryObject>
  </cac:Attachment>
</cac:AdditionalDocumentReference>
xml

Validation Rules

Peppol documents must pass several validation layers:

  1. XML Schema Validation: Basic XML structure validation
  2. Schematron Validation: Business rule validation specific to document type
  3. Peppol Validation Artifacts: Additional Peppol-specific rules

The Recommand API handles these validations automatically when sending documents.

Simplified Approach with Recommand

Instead of constructing complex UBL XML manually, you can use Recommand's simplified JSON structure, which is automatically converted to valid UBL. Furthermore, if not provided, Recommand will automatically calculate any necessary totals.

// Simple JSON structure
const invoice = {
  invoiceNumber: "INV-2025-001",
  issueDate: "2024-05-15",
  buyer: {
    vatNumber: "BE0987654321",
    name: "Customer Company",
    // ...
  },
  // ...
};

// Send to Recommand API which converts to proper UBL
await fetch("https://peppol.recommand.eu/api/peppol/{companyId}/sendDocument", {
  method: "POST",
  // ...
  body: JSON.stringify({
    recipient: "0208:987654321",
    documentType: "invoice",
    document: invoice,
  }),
});
javascript

Working with Raw UBL

If you need to work with raw UBL XML:

  1. You can send pre-formed XML directly using the sendDocument endpoint:
await fetch("https://peppol.recommand.eu/api/peppol/{companyId}/sendDocument", {
  method: "POST",
  // ...
  body: JSON.stringify({
    recipient: "0208:987654321",
    documentType: "xml",
    document: "<Invoice>...(UBL XML)...</Invoice>",
    doctypeId:
      "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1",
  }),
});
javascript
  1. You can retrieve the UBL XML of sent and received documents using the get document endpoint:
const response = await fetch(
  "https://peppol.recommand.eu/api/peppol/{teamId}/documents/{documentId}",
  {
    // ...
  }
);
const data = await response.json();
const ublXml = data.document.xml;
javascript

Further Resources