eliDocs
Format Reference

Peppol BIS Billing 3.0

Generate and validate UBL invoices ready for the Peppol Network with Beliq.

Peppol BIS Billing 3.0 is the Core Invoice Usage Specification (CIUS) of EN 16931 used by the Peppol Network to exchange invoices and credit notes between businesses and public authorities across Europe.

It is the format you need when:

  • Your buyer requires an invoice on Peppol (Belgium B2B, the Netherlands, the Nordics, and a growing number of EU public-sector procurement portals)
  • You sell cross-border in the EU and want a single UBL format that is accepted in most member states
  • Your ERP or Access Point speaks UBL and uses the Peppol BIS 3.0 customization identifier

To generate Peppol-compliant XML with Beliq, set:

{
  "standard": "peppol-bis",
  "profile": "peppol",
  "output": "xml"
}

profile is optional — if omitted, Beliq picks peppol automatically when standard: "peppol-bis".

What Beliq emits

What Beliq emits

When you request standard: "peppol-bis", Beliq generates a UBL 2.1 invoice with the elements that Peppol requires beyond plain EN 16931:

Element Value Source
cbc:CustomizationID urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0 Fixed by Peppol BIS Billing 3.0
cbc:ProfileID urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 (Billing 3.0 default) Beliq default; can be overridden
cbc:BuyerReference or cac:OrderReference Your buyerReference / orderReference field Required by PEPPOL-EN16931-R003
cac:AccountingSupplierPartycbc:EndpointID Seller Peppol electronic-address with @schemeID Required by PEPPOL-EN16931-R020
cac:AccountingCustomerPartycbc:EndpointID Buyer Peppol electronic-address with @schemeID Required by PEPPOL-EN16931-R010

Everything else (party names, addresses, VAT IDs, invoice lines, tax breakdown, totals) follows the standard UBL 2.1 / EN 16931 layout.

Peppol electronic-address

Peppol electronic-address

Every party on the Peppol Network has an electronic-address — a pair of values that uniquely identifies them on the network. You provide it on each party as:

"peppol": {
  "schemeId": "9930",
  "id": "DE123456789"
}

schemeId comes from the official Peppol EAS code list. The most common entries are:

Countries with vatId fallback

For these 11 countries, providing vatId and address.countryCode is enough — Beliq picks the canonical EAS scheme automatically, because the VAT number is itself a valid identifier under that country’s scheme:

Country schemeId Scheme name What id is
Austria 9914 AT:VAT VAT number (ATU…)
Belgium 9925 BE:VAT VAT number (BE…)
France 9957 FR:VAT VAT number (FR…)
Germany 9930 DE:VAT VAT number (DE…)
Ireland 9935 IE:VAT VAT number (IE…)
Italy 0211 IT:PARTITA IVA VAT number (IT…)
Luxembourg 9938 LU:VAT VAT number (LU…)
Netherlands 9944 NL:VAT VAT number (NL…B01)
Poland 9945 PL:VAT VAT number (PL…)
Portugal 9946 PT:VAT VAT number (PT…)
Spain 9920 ES:VAT VAT number (ES…)

Countries that require an explicit peppol block

For these countries the VAT number is not a valid identifier under the country’s Peppol scheme. Beliq does not silently transform values, so you must supply both peppol.schemeId and peppol.id for parties registered in:

Country schemeId Scheme name What id is Example
Denmark 0184 DK:CVR CVR number, 8 digits, without the DK prefix your VAT id carries 12345678
Finland 0216 FI:OVT2 OVT identifier: 0037 + the 8-digit business id 003712345678
Norway 0192 NO:ORG.NR Enhetsregisteret organisasjonsnummer (9 digits) 123456789
Sweden 0007 SE:ORG Organisationsnummer (10 digits) 5567123456
"buyer": {
  "name": "Eksempel AS",
  "vatId": "NO123456789MVA",
  "peppol": { "schemeId": "0192", "id": "123456789" },
  "address": { "city": "Oslo", "postalCode": "0150", "countryCode": "NO" }
}

If a recipient in one of these countries is supplied with vatId only, the engine fails closed with a clear error — silently stripping the MVA suffix or the DK prefix, or pivoting to a different scheme, would risk producing an endpoint that validates but cannot be reached.

Denmark is the one to watch: a Danish endpoint spelled DK12345678 passes Peppol validation (PEPPOL-COMMON-R042 accepts both spellings) and then fails to resolve, because Danish participants are registered under the bare CVR.

Finland’s old 0213 scheme was removed from the Peppol network on 2024-12-31. Beliq rejects it, and any other removed scheme, at build time.

Other countries

For countries outside both tables (or for any party identified by a non-VAT scheme such as GLN 0088 or Leitweg-ID 0204), set peppol.schemeId and peppol.id explicitly using a value from the official Peppol EAS code list. The full snapshot of the codelist Beliq accepts is pinned in the engine and unknown codes are rejected at build time.

What Beliq validates

What Beliq validates

Every invoice you generate is validated against three layered Schematron rule sets, in this order:

  1. XSD — UBL 2.1 structural validity
  2. EN 16931 — common European business rules (BR-01, BR-CO-, BR-S-, etc.)
  3. OpenPeppol BIS Billing 3.0 Schematron — Peppol-specific cross-border rules (PEPPOL-EN16931-R*) and country-specific rules (PEPPOL-COMMON-R*, national *-R-*)

If any rule fires with severity error or fatal, the response is 422 INVALID_INVOICE with the failing rule IDs in validationResult.errors. The most common Peppol rules to watch for:

Rule Trigger
PEPPOL-EN16931-R003 Missing both buyerReference and orderReference
PEPPOL-EN16931-R010 Buyer party has no Peppol EndpointID
PEPPOL-EN16931-R020 Seller party has no Peppol EndpointID
PEPPOL-EN16931-R030 BuyerReference or OrderReference.ID is empty
BR-CO-15 Sum of line/tax/total amounts is inconsistent

The exact Schematron version Beliq runs is published on the validation artifacts page.

Schematron 3.0.21 is in force: OpenPEPPOL made it mandatory on the network on 2026-08-17, so it took effect without a notice period and latest resolves to it now. 3.0.20 stays selectable on the previous channel until 2027-03-03, which is how you reproduce an earlier verdict. Note that a document 3.0.20 passes may still be rejected by the receiving access point, since the mandate is the network’s, not ours.

When validation passes, the /v1/validate response includes:

{
  "valid": true,
  "format": "ubl",
  "profileDetected": "peppol",
  "schematronVersion": "1.3.16",
  "ciusVersion": "PeppolBIS-Billing-3.0.21",
  "peppolVersion": "PeppolBIS-Billing-3.0.21",
  "errors": [],
  "warnings": []
}
Getting the document onto the network

Getting the document onto the network

Beliq generates and validates Peppol-compliant XML. Today it does not put that document on the Peppol Network: to reach a buyer’s Access Point, hand the generated XML to your own Access Point provider. What a Peppol Access Point is covers how the network routes a document and how to pick a provider; OpenPeppol publishes the certified list.

Managed delivery over Peppol is in build, targeting Q4 2026 and subject to certification. Either way the correctness layer is the same, and your choice of Access Point is never dictated by us.

Credit notes

Credit notes

Peppol BIS Billing 3.0 emits CreditNote documents using the UBL CreditNote root element with cbc:CreditNoteTypeCode = 381. Beliq also supports CreditNote round-trip on XRechnung (UBL and CII), ZUGFeRD 2.x, Factur-X 1.09.2 and Slovenia’s e-SLOG 2.0 (document type code 381 on the same e-SLOG message shape): see the format overview and DOCUMENT_TYPE_STANDARD_MISMATCH. Italy FatturaPA and Spain Facturae accept invoices only; setting documentType: "creditnote" on either returns a 422 with a clear error.

To emit a CreditNote, set documentType: "creditnote" on the invoice payload and provide a precedingInvoiceReference linking back to the original invoice:

{
  "standard": "peppol-bis",
  "profile": "peppol",
  "output": "xml",
  "invoice": {
    "documentType": "creditnote",
    "precedingInvoiceReference": {
      "id": "INV-2026-001",
      "issueDate": "2026-04-12"
    },
    "number": "CN-2026-001",
    "issueDate": "2026-04-25",
    "currencyCode": "EUR",
    "buyerReference": "NL-PO-7711",
    "seller": {
      "name": "Test Verkoper B.V.",
      "vatId": "NL123456789B01",
      "peppol": { "schemeId": "9944", "id": "NL123456789B01" },
      "address": { "street": "Damrak 1", "city": "Amsterdam", "postalCode": "1012 LG", "countryCode": "NL" }
    },
    "buyer": {
      "name": "Test Koper B.V.",
      "vatId": "NL987654321B02",
      "peppol": { "schemeId": "9944", "id": "NL987654321B02" },
      "address": { "street": "Coolsingel 2", "city": "Rotterdam", "postalCode": "3011 AA", "countryCode": "NL" }
    },
    "lines": [
      {
        "description": "Credit for returned licences",
        "quantity": 1,
        "unitCode": "C62",
        "unitPrice": 100.00,
        "lineTotal": 100.00,
        "vatRate": 21,
        "vatCategoryCode": "S"
      }
    ],
    "taxSummary": [
      { "vatCategoryCode": "S", "vatRate": 21, "taxableAmount": 100.00, "taxAmount": 21.00 }
    ],
    "totalNetAmount": 100.00,
    "totalTaxAmount": 21.00,
    "totalGrossAmount": 121.00
  }
}

precedingInvoiceReference.id becomes the UBL cac:BillingReference / cac:InvoiceDocumentReference / cbc:ID element. issueDate is optional but recommended — when present it is emitted as cbc:IssueDate on the same reference block.

Validation runs the same three layers as for an Invoice (XSD → EN 16931 → Peppol BIS Schematron). The relevant Peppol rule for a Peppol CreditNote is PEPPOL-EN16931-P0101 — when the document’s root element is CreditNote, the Peppol-declared invoice type must stay 381. Use documentType plus /v1/generate; the same discriminator applies on the other CreditNote-capable generators (xrechnung, facturx, zugferd, eslog) via the route CREDITNOTE_CAPABLE_STANDARDS — see format overview.

Common patterns

Common patterns

B2G in Belgium

For invoices to Belgian public-sector buyers (mandatory via Peppol since January 2026), the buyer typically publishes its Peppol identifier as a Belgian VAT number under schemeId: "9925":

"buyer": {
  "name": "Federale Overheidsdienst Voorbeeld",
  "vatId": "BE0123456789",
  "peppol": { "schemeId": "9925", "id": "BE0123456789" },
  "address": { ... }
}

Cross-border B2B

For an EU-cross-border invoice (FR seller, NL buyer), provide each party’s local EAS:

"seller": {
  "name": "Acme SARL",
  "vatId": "FR12345678901",
  "peppol": { "schemeId": "9957", "id": "FR12345678901" },
  ...
},
"buyer": {
  "name": "Voorbeeld B.V.",
  "vatId": "NL123456789B01",
  "peppol": { "schemeId": "9944", "id": "NL123456789B01" },
  ...
}

Reusing a Peppol invoice for an XRechnung buyer

If your buyer is a German B2G recipient that requires XRechnung, switch the request to standard: "xrechnung" (Beliq picks profile: "xrechnung" by default). The invoice payload is otherwise identical.

Related