UBL 2.1 XML Format

The technical format behind PEPPOL invoices. Understand how your invoice data is structured for machine-to-machine communication.

What is UBL?

UBL (Universal Business Language) is an international standard for structuring business documents like invoices. Think of it as a precise template that tells computers exactly where to find each piece of information - the invoice number, amounts, VAT, seller details, and so on.

When you create an invoice in aiDoks, we automatically convert your data into this UBL XML format. This ensures any system receiving your invoice can read it correctly, regardless of what software they use.

You don't need to write XML

aiDoks generates perfect UBL XML automatically from your input. This page is for those who want to understand what happens behind the scenes or need to work with the raw files.

Invoice Structure at a Glance

Every PEPPOL invoice contains these main sections, in this order:

Header InfoInvoice number, dates, currency, and PEPPOL identifiers
Seller (Supplier)Your company name, address, VAT number, PEPPOL ID
Buyer (Customer)Customer's company details and PEPPOL ID
Payment InfoBank account, payment method, payment terms
Tax SummaryVAT breakdown by category and rate
TotalsLine total, tax total, and amount due
Line ItemsEach product/service with quantity, price, and VAT

Key Elements Explained

Here are the most important parts of a UBL invoice and what they contain:

PEPPOL Identifiers
<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>

These identifiers tell receiving systems that this is a PEPPOL BIS 3.0 compliant invoice. They're always the same for standard invoices - aiDoks adds them automatically.

Invoice Details
<cbc:ID>INV-2025-001</cbc:ID> <cbc:IssueDate>2025-01-29</cbc:IssueDate> <cbc:DueDate>2025-02-28</cbc:DueDate> <cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode> <cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>

Your invoice number, issue date, due date, type (380 = standard invoice), and currency. Dates must be in YYYY-MM-DD format.

Seller Information
<cac:AccountingSupplierParty> <cac:Party> <cbc:EndpointID schemeID="0191">EE123456789</cbc:EndpointID> <cac:PartyName> <cbc:Name>Your Company OÜ</cbc:Name> </cac:PartyName> <!-- Address, VAT number, registration... --> </cac:Party> </cac:AccountingSupplierParty>

Your company details. The EndpointID with schemeID is your PEPPOL participant identifier - this is how the network knows where to deliver responses.

Invoice Line
<cac:InvoiceLine> <cbc:ID>1</cbc:ID> <cbc:InvoicedQuantity unitCode="HUR">40</cbc:InvoicedQuantity> <cbc:LineExtensionAmount currencyID="EUR">3000.00</cbc:LineExtensionAmount> <cac:Item> <cbc:Name>Web Development Services</cbc:Name> </cac:Item> <cac:Price> <cbc:PriceAmount currencyID="EUR">75.00</cbc:PriceAmount> </cac:Price> </cac:InvoiceLine>

Each item you're billing for. Includes line number, quantity (with unit code like HUR for hours), line total, item description, and unit price. You can have multiple InvoiceLine elements.

Common Codes Reference

PEPPOL Participant ID Schemes

Scheme IDCountryDescription
0191EstoniaVAT number (EE + 9 digits)
0192EstoniaBusiness registry code (8 digits)
0193LatviaVAT number (LV + 11 digits)
0200LithuaniaVAT number (LT + 9-12 digits)
9915AustriaVAT number
9930ItalyVAT number

Payment Method Codes

30Bank Transfer (most common)
58SEPA Credit Transfer
49Direct Debit
48Credit Card

How Validation Works

Before an invoice can be sent via PEPPOL, it must pass multiple validation checks:

XML Schema (XSD)Automatic

Checks that the XML structure is correct - all required elements are present, properly nested, and use the right data types.

Schematron RulesAutomatic

Validates business rules - for example, that VAT amounts match the calculated values, required fields are filled based on context, and code values are valid.

PEPPOL Code ListsAutomatic

Verifies that all codes (currency, country, unit, VAT category) are from the official PEPPOL-approved lists.

Calculation CheckAutomatic

Confirms that line totals add up correctly, VAT is calculated properly, and the final payable amount is accurate.

Validation in aiDoks

aiDoks runs all these validations before sending. If there are errors, you'll see specific messages explaining what needs to be fixed - usually a missing field or incorrect value.

Sample Invoice File

Want to see a complete example? Here's a minimal valid PEPPOL invoice:

XML
<?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>INV-2025-001</cbc:ID>
  <cbc:IssueDate>2025-01-29</cbc:IssueDate>
  <cbc:DueDate>2025-02-28</cbc:DueDate>
  <cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
  <cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>

  <cac:AccountingSupplierParty>
    <cac:Party>
      <cbc:EndpointID schemeID="0191">EE123456789</cbc:EndpointID>
      <cac:PartyName><cbc:Name>Seller Company OÜ</cbc:Name></cac:PartyName>
      <cac:PostalAddress>
        <cbc:StreetName>Main Street 1</cbc:StreetName>
        <cbc:CityName>Tallinn</cbc:CityName>
        <cbc:PostalZone>10001</cbc:PostalZone>
        <cac:Country><cbc:IdentificationCode>EE</cbc:IdentificationCode></cac:Country>
      </cac:PostalAddress>
      <cac:PartyTaxScheme>
        <cbc:CompanyID>EE123456789</cbc:CompanyID>
        <cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme>
      </cac:PartyTaxScheme>
      <cac:PartyLegalEntity>
        <cbc:RegistrationName>Seller Company OÜ</cbc:RegistrationName>
        <cbc:CompanyID>12345678</cbc:CompanyID>
      </cac:PartyLegalEntity>
    </cac:Party>
  </cac:AccountingSupplierParty>

  <cac:AccountingCustomerParty>
    <cac:Party>
      <cbc:EndpointID schemeID="0192">87654321</cbc:EndpointID>
      <cac:PartyName><cbc:Name>Buyer Company AS</cbc:Name></cac:PartyName>
      <cac:PostalAddress>
        <cbc:CityName>Tallinn</cbc:CityName>
        <cac:Country><cbc:IdentificationCode>EE</cbc:IdentificationCode></cac:Country>
      </cac:PostalAddress>
      <cac:PartyLegalEntity>
        <cbc:RegistrationName>Buyer Company AS</cbc:RegistrationName>
      </cac:PartyLegalEntity>
    </cac:Party>
  </cac:AccountingCustomerParty>

  <cac:TaxTotal>
    <cbc:TaxAmount currencyID="EUR">220.00</cbc:TaxAmount>
    <cac:TaxSubtotal>
      <cbc:TaxableAmount currencyID="EUR">1000.00</cbc:TaxableAmount>
      <cbc:TaxAmount currencyID="EUR">220.00</cbc:TaxAmount>
      <cac:TaxCategory>
        <cbc:ID>S</cbc:ID>
        <cbc:Percent>22</cbc:Percent>
        <cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme>
      </cac:TaxCategory>
    </cac:TaxSubtotal>
  </cac:TaxTotal>

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

  <cac:InvoiceLine>
    <cbc:ID>1</cbc:ID>
    <cbc:InvoicedQuantity unitCode="C62">10</cbc:InvoicedQuantity>
    <cbc:LineExtensionAmount currencyID="EUR">1000.00</cbc:LineExtensionAmount>
    <cac:Item>
      <cbc:Name>Consulting Services</cbc:Name>
      <cac:ClassifiedTaxCategory>
        <cbc:ID>S</cbc:ID>
        <cbc:Percent>22</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>
</Invoice>