Home/Blog/How to map your ERP data to PEPPOL BIS Billing 3.0 fields

How to map your ERP data to PEPPOL BIS Billing 3.0 fields

A mapping guide from common ERP master data fields to their corresponding PEPPOL BIS Billing 3.0 XML elements.

Moving from generating PDF invoices to generating PEPPOL-conformant XML means taking data your ERP already has and putting it into the right XML elements with the right formats and codes. This sounds straightforward until you run into the first Schematron error, discover that your tax totals do not add up the way the standard expects, or find that your customer identifiers are in the wrong format.

This guide maps the most common invoice fields from a typical ERP system to their PEPPOL BIS Billing 3.0 XML equivalents. It focuses on the fields that cause the most confusion in practice.

Document-level fields

ERP conceptPEPPOL BIS elementXPathNotes
Invoice numberInvoice IDcbc:IDFree text, max 200 chars. Must be unique per biller.
Invoice dateIssue datecbc:IssueDateISO 8601: YYYY-MM-DD
Due datePayment due datecbc:DueDateIn cac:PaymentTerms/cbc:Note or as cbc:PaymentDueDate
CurrencyDocument currencycbc:DocumentCurrencyCodeISO 4217 code: CHF, EUR, etc.
PO referenceOrder referencecac:OrderReference/cbc:IDOptional but expected by many buyers
Buyer referenceBuyer referencecbc:BuyerReferenceOften a cost centre code or contract number. Mandatory when the buyer requires it.

The CustomizationID and ProfileID must also be set at the document level and cannot be left to whatever your ERP generates. For a Swiss SwissDIGIN invoice:

<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0#conformant#urn:fdc:swissdigin.ch:2018:invoicing:1.0</cbc:CustomizationID>
<cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:3.0</cbc:ProfileID>

Supplier (seller) fields

Your ERP's company or legal entity settings feed the supplier block:

<cac:AccountingSupplierParty>
  <cac:Party>
    <cac:PartyName>
      <cbc:Name>Muster AG</cbc:Name>
    </cac:PartyName>
    <cac:PostalAddress>
      <cbc:StreetName>Bahnhofstrasse 12</cbc:StreetName>
      <cbc:CityName>Zürich</cbc:CityName>
      <cbc:PostalZone>8001</cbc:PostalZone>
      <cac:Country>
        <cbc:IdentificationCode>CH</cbc:IdentificationCode>
      </cac:Country>
    </cac:PostalAddress>
    <cac:PartyTaxScheme>
      <cbc:CompanyID>CHE-116.281.710 MWST</cbc:CompanyID>
      <cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme>
    </cac:PartyTaxScheme>
    <cac:PartyLegalEntity>
      <cbc:RegistrationName>Muster AG</cbc:RegistrationName>
      <cbc:CompanyID schemeID="CHE">CHE-116.281.710</cbc:CompanyID>
    </cac:PartyLegalEntity>
  </cac:Party>
</cac:AccountingSupplierParty>

Key points:

  • PartyTaxScheme/CompanyID carries the UID with the MWST suffix (e.g. CHE-116.281.710 MWST)
  • PartyLegalEntity/CompanyID carries the UID without the suffix, with schemeID="CHE"
  • Country code is ISO 3166-1 alpha-2 (CH not CHE or Switzerland)
  • If you are not VAT-registered (below CHF 100,000 revenue), omit the PartyTaxScheme block entirely

Customer (buyer) fields

The buyer block mirrors the supplier block. The fields your ERP stores for a customer:

ERP conceptPEPPOL BIS elementNotes
Customer nameAccountingCustomerParty/Party/PartyName/NameLegal name, not a trading name
Billing addressAccountingCustomerParty/Party/PostalAddressStreet, city, postal code, country
Customer UIDAccountingCustomerParty/Party/PartyLegalEntity/CompanyIDWith schemeID="CHE" for Swiss customers
Customer VAT numberAccountingCustomerParty/Party/PartyTaxScheme/CompanyIDFor non-Swiss EU buyers: their VAT number
PEPPOL participant IDAccountingCustomerParty/Party/EndpointIDRequired for PEPPOL delivery. Format: 0209:CHE1162817100

The endpoint ID (EndpointID) is what the PEPPOL network uses to route the invoice. For Swiss participants, the scheme is 0209 and the identifier is the UID digits without separators. Your access point provider handles the routing — you just need to include the correct endpoint ID so they know where to send it.

Payment details

This is where Swiss invoices differ most from generic PEPPOL invoices:

<cac:PaymentMeans>
  <cbc:PaymentMeansCode>58</cbc:PaymentMeansCode>
  <cbc:PaymentID>210000000003139471430009017</cbc:PaymentID>
  <cac:PayeeFinancialAccount>
    <cbc:ID>CH4431999123000889012</cbc:ID>
    <cbc:Name>Muster AG</cbc:Name>
    <cac:FinancialInstitutionBranch>
      <cbc:ID>RAIFCH22</cbc:ID>
    </cac:FinancialInstitutionBranch>
  </cac:PayeeFinancialAccount>
</cac:PaymentMeans>
  • PaymentMeansCode 58 = SEPA credit transfer (used for Swiss IBAN-based transfers too)
  • PaymentID = the 27-digit QR reference from your QR-bill. Use the SCOR reference here if you use ISO 11649 creditor references instead.
  • PayeeFinancialAccount/ID = QR-IBAN (without spaces). Use standard IBAN if you do not use QR references.
  • BIC in FinancialInstitutionBranch/ID is optional but recommended

Tax totals

Tax is where most mapping projects produce their first Schematron errors. The PEPPOL BIS tax model requires:

  1. One or more TaxSubtotal blocks — one per distinct VAT rate
  2. A TaxTotal that sums all subtotals
  3. Each subtotal carries a TaxableAmount, a TaxAmount, and a TaxCategory block
<cac:TaxTotal>
  <cbc:TaxAmount currencyID="CHF">81.00</cbc:TaxAmount>
  <cac:TaxSubtotal>
    <cbc:TaxableAmount currencyID="CHF">1000.00</cbc:TaxableAmount>
    <cbc:TaxAmount currencyID="CHF">81.00</cbc:TaxAmount>
    <cac:TaxCategory>
      <cbc:ID>S</cbc:ID>
      <cbc:Percent>8.1</cbc:Percent>
      <cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme>
    </cac:TaxCategory>
  </cac:TaxSubtotal>
</cac:TaxTotal>

Common mistakes:

  • Calculating TaxAmount by multiplying TaxableAmount × Percent / 100 at the subtotal level and rounding each one independently, then summing. Rounding errors accumulate. Calculate line-level tax, sum without rounding, then round once at the subtotal level.
  • Including a TaxSubtotal per invoice line rather than per distinct tax rate. You must consolidate: all lines at 8.1% share one subtotal.
  • Setting TaxCategory/ID to the rate value instead of the category code. The category code for standard-rate Swiss VAT is always S regardless of whether the rate is 8.1%, 2.6%, or 3.8%.

Line items

Each invoice line maps to a cac:InvoiceLine:

<cac:InvoiceLine>
  <cbc:ID>1</cbc:ID>
  <cbc:InvoicedQuantity unitCode="HUR">10</cbc:InvoicedQuantity>
  <cbc:LineExtensionAmount currencyID="CHF">500.00</cbc:LineExtensionAmount>
  <cac:Item>
    <cbc:Description>Software development services</cbc:Description>
    <cbc:Name>Development</cbc:Name>
    <cac:ClassifiedTaxCategory>
      <cbc:ID>S</cbc:ID>
      <cbc:Percent>8.1</cbc:Percent>
      <cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme>
    </cac:ClassifiedTaxCategory>
  </cac:Item>
  <cac:Price>
    <cbc:PriceAmount currencyID="CHF">50.00</cbc:PriceAmount>
  </cac:Price>
</cac:InvoiceLine>
  • InvoicedQuantity requires a unitCode — use UN/ECE Recommendation 20 codes (HUR for hours, C62 for pieces, KGM for kilograms, DAY for days)
  • LineExtensionAmount = quantity × price, before VAT. This is what feeds the tax calculation.
  • Tax category at line level must match what is in the header TaxSubtotal

Document totals

The LegalMonetaryTotal block summarises the invoice:

<cac:LegalMonetaryTotal>
  <cbc:LineExtensionAmount currencyID="CHF">1000.00</cbc:LineExtensionAmount>
  <cbc:TaxExclusiveAmount currencyID="CHF">1000.00</cbc:TaxExclusiveAmount>
  <cbc:TaxInclusiveAmount currencyID="CHF">1081.00</cbc:TaxInclusiveAmount>
  <cbc:PayableAmount currencyID="CHF">1081.00</cbc:PayableAmount>
</cac:LegalMonetaryTotal>
  • LineExtensionAmount = sum of all line LineExtensionAmount values
  • TaxExclusiveAmount = net total after header-level allowances/charges, before VAT
  • TaxInclusiveAmount = TaxExclusiveAmount + total VAT
  • PayableAmount = what the buyer owes (may differ from TaxInclusiveAmount if a prepayment has been made)

The Schematron checks that these figures are internally consistent. If LineExtensionAmount does not equal the sum of your line amounts, or TaxInclusiveAmount does not equal TaxExclusiveAmount + TaxTotal/TaxAmount, you will get a BR-CO-1x error.

For a full walkthrough of the XML structure including allowances and charges, see the PEPPOL BIS Billing 3.0 line-by-line walkthrough. For the Swiss-specific extensions on top of this mapping, see the post on how SwissDIGIN extends PEPPOL BIS Billing 3.0.