Peppol BIS Billing 3.0 UBL 2.1 E-Invoice Validator & Parser
Validate and extract structured JSON from Peppol BIS Billing 3.0 OASIS UBL 2.1 electronic invoices and credit notes. This specification documents the exact field layout, checksum rules, and validation behavior so your integration matches Peppol BIS Billing 3.0 / EN 16931 without reading the source standard.
⚡ Live Peppol BIS Billing 3.0 UBL 2.1 E-Invoice Validator & Parser Interactive Workbench
Test real-time validation and schema parsing for Peppol BIS Billing 3.0 UBL 2.1 E-Invoice Validator & Parser directly in your browser. Runs in sub-5ms with zero setup.
{
"status": "Click RUN VALIDATION to execute on the Cloudflare edge..."
}
Quick Summary: Validate and extract structured JSON from Peppol BIS Billing 3.0 OASIS UBL 2.1 electronic invoices and credit notes. Validates strictly against Peppol BIS Billing 3.0 / EN 16931 with sub-5ms in-memory response times.
Specification & Structural Breakdown
Technical Summary: Validates strictly against Peppol BIS Billing 3.0 / EN 16931. Payloads are parsed in memory and return clean, typed JSON in milliseconds with zero data logged.
Peppol BIS Billing 3.0 is the official Core Invoice Usage Specification (CIUS) across European public procurement and international B2B invoicing networks.
Deterministic validation of CustomizationID (urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0) and ProfileID.
Extracts supplier, customer, tax representative, and payee parties with postal address and ISO 6523 Electronic Address Scheme (EAS) endpoints.
| UBL 2.1 Node | Field Name | Mandatory | Standard Rule |
|---|---|---|---|
| cbc:CustomizationID | Specification ID | Yes | BR-01 & PEPPOL-EN16931-R001 |
| cbc:ID | Invoice Identifier | Yes | BR-02 (Max 500 chars) |
| cbc:IssueDate | Issue Date | Yes | BR-03 (YYYY-MM-DD) |
| cac:LegalMonetaryTotal | Monetary Totals | Yes | BR-CO-10 / 11 / 12 / 14 |
| cac:TaxTotal | VAT Breakdown | Yes | BR-CO-15 / 17 / 18 |
Parsed JSON Response Model
The edge microservice transforms input payloads into strongly-typed hierarchical JSON envelopes with sub-5ms latency:
{
"valid": true,
"syntax": "UBL_INVOICE",
"profile": "PEPPOL_BIS_BILLING_3_0",
"summary": {
"status": "COMPLIANT",
"fatalCount": 0,
"warningCount": 0
},
"rulesChecked": 24
}
Copy-Paste Integration Code (6 Languages)
Integrate Peppol BIS Billing 3.0 UBL 2.1 E-Invoice Validator & Parser directly into your production application with native, zero-dependency code snippets in cURL, Node.js, Python, Go, C#, and a ready-to-paste Claude prompt. Get a free API key → (no credit card required):
curl --request POST \
--url "https://api.stanzaapi.com/peppol-validator/api/v1/validate" \
--header "Content-Type: application/json" \
--header "x-api-key: YOUR_API_KEY" \
--data '{
"xml": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Invoice xmlns=\"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\"><cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0</cbc:CustomizationID><cbc:ID>INV-01</cbc:ID><cbc:IssueDate>2026-08-10</cbc:IssueDate><cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode><cac:AccountingSupplierParty><cac:Party><cac:PostalAddress><cac:Country><cbc:IdentificationCode>DE</cbc:IdentificationCode></cac:Country></cac:PostalAddress><cac:PartyLegalEntity><cbc:RegistrationName>Supplier</cbc:RegistrationName></cac:PartyLegalEntity></cac:Party></cac:AccountingSupplierParty><cac:AccountingCustomerParty><cac:Party><cac:PostalAddress><cac:Country><cbc:IdentificationCode>FR</cbc:IdentificationCode></cac:Country></cac:PostalAddress><cac:PartyLegalEntity><cbc:RegistrationName>Buyer</cbc:RegistrationName></cac:PartyLegalEntity></cac:Party></cac:AccountingCustomerParty><cac:TaxTotal><cbc:TaxAmount currencyID=\"EUR\">19.00</cbc:TaxAmount><cac:TaxSubtotal><cbc:TaxableAmount currencyID=\"EUR\">100.00</cbc:TaxableAmount><cbc:TaxAmount currencyID=\"EUR\">19.00</cbc:TaxAmount><cac:TaxCategory><cbc:ID>S</cbc:ID><cbc:Percent>19</cbc:Percent></cac:TaxCategory></cac:TaxSubtotal></cac:TaxTotal><cac:LegalMonetaryTotal><cbc:LineExtensionAmount currencyID=\"EUR\">100.00</cbc:LineExtensionAmount><cbc:TaxExclusiveAmount currencyID=\"EUR\">100.00</cbc:TaxExclusiveAmount><cbc:TaxInclusiveAmount currencyID=\"EUR\">119.00</cbc:TaxInclusiveAmount><cbc:PayableAmount currencyID=\"EUR\">119.00</cbc:PayableAmount></cac:LegalMonetaryTotal><cac:InvoiceLine><cbc:ID>1</cbc:ID><cbc:InvoicedQuantity unitCode=\"C62\">1</cbc:InvoicedQuantity><cbc:LineExtensionAmount currencyID=\"EUR\">100.00</cbc:LineExtensionAmount><cac:Item><cbc:Name>Item</cbc:Name><cac:ClassifiedTaxCategory><cbc:ID>S</cbc:ID><cbc:Percent>19</cbc:Percent></cac:ClassifiedTaxCategory></cac:Item><cac:Price><cbc:PriceAmount currencyID=\"EUR\">100.00</cbc:PriceAmount></cac:Price></cac:InvoiceLine></Invoice>"
}'const response = await fetch("https://api.stanzaapi.com/peppol-validator/api/v1/validate", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": process.env.API_KEY || "YOUR_API_KEY"
},
body: JSON.stringify({
"xml": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Invoice xmlns=\"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\"><cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0</cbc:CustomizationID><cbc:ID>INV-01</cbc:ID><cbc:IssueDate>2026-08-10</cbc:IssueDate><cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode><cac:AccountingSupplierParty><cac:Party><cac:PostalAddress><cac:Country><cbc:IdentificationCode>DE</cbc:IdentificationCode></cac:Country></cac:PostalAddress><cac:PartyLegalEntity><cbc:RegistrationName>Supplier</cbc:RegistrationName></cac:PartyLegalEntity></cac:Party></cac:AccountingSupplierParty><cac:AccountingCustomerParty><cac:Party><cac:PostalAddress><cac:Country><cbc:IdentificationCode>FR</cbc:IdentificationCode></cac:Country></cac:PostalAddress><cac:PartyLegalEntity><cbc:RegistrationName>Buyer</cbc:RegistrationName></cac:PartyLegalEntity></cac:Party></cac:AccountingCustomerParty><cac:TaxTotal><cbc:TaxAmount currencyID=\"EUR\">19.00</cbc:TaxAmount><cac:TaxSubtotal><cbc:TaxableAmount currencyID=\"EUR\">100.00</cbc:TaxableAmount><cbc:TaxAmount currencyID=\"EUR\">19.00</cbc:TaxAmount><cac:TaxCategory><cbc:ID>S</cbc:ID><cbc:Percent>19</cbc:Percent></cac:TaxCategory></cac:TaxSubtotal></cac:TaxTotal><cac:LegalMonetaryTotal><cbc:LineExtensionAmount currencyID=\"EUR\">100.00</cbc:LineExtensionAmount><cbc:TaxExclusiveAmount currencyID=\"EUR\">100.00</cbc:TaxExclusiveAmount><cbc:TaxInclusiveAmount currencyID=\"EUR\">119.00</cbc:TaxInclusiveAmount><cbc:PayableAmount currencyID=\"EUR\">119.00</cbc:PayableAmount></cac:LegalMonetaryTotal><cac:InvoiceLine><cbc:ID>1</cbc:ID><cbc:InvoicedQuantity unitCode=\"C62\">1</cbc:InvoicedQuantity><cbc:LineExtensionAmount currencyID=\"EUR\">100.00</cbc:LineExtensionAmount><cac:Item><cbc:Name>Item</cbc:Name><cac:ClassifiedTaxCategory><cbc:ID>S</cbc:ID><cbc:Percent>19</cbc:Percent></cac:ClassifiedTaxCategory></cac:Item><cac:Price><cbc:PriceAmount currencyID=\"EUR\">100.00</cbc:PriceAmount></cac:Price></cac:InvoiceLine></Invoice>"
})
});
const data = await response.json();
console.log(data);import requests
import json
url = "https://api.stanzaapi.com/peppol-validator/api/v1/validate"
headers = {
"Content-Type": "application/json",
"x-api-key": "YOUR_API_KEY"
}
payload = {
"xml": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Invoice xmlns=\"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\"><cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0</cbc:CustomizationID><cbc:ID>INV-01</cbc:ID><cbc:IssueDate>2026-08-10</cbc:IssueDate><cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode><cac:AccountingSupplierParty><cac:Party><cac:PostalAddress><cac:Country><cbc:IdentificationCode>DE</cbc:IdentificationCode></cac:Country></cac:PostalAddress><cac:PartyLegalEntity><cbc:RegistrationName>Supplier</cbc:RegistrationName></cac:PartyLegalEntity></cac:Party></cac:AccountingSupplierParty><cac:AccountingCustomerParty><cac:Party><cac:PostalAddress><cac:Country><cbc:IdentificationCode>FR</cbc:IdentificationCode></cac:Country></cac:PostalAddress><cac:PartyLegalEntity><cbc:RegistrationName>Buyer</cbc:RegistrationName></cac:PartyLegalEntity></cac:Party></cac:AccountingCustomerParty><cac:TaxTotal><cbc:TaxAmount currencyID=\"EUR\">19.00</cbc:TaxAmount><cac:TaxSubtotal><cbc:TaxableAmount currencyID=\"EUR\">100.00</cbc:TaxableAmount><cbc:TaxAmount currencyID=\"EUR\">19.00</cbc:TaxAmount><cac:TaxCategory><cbc:ID>S</cbc:ID><cbc:Percent>19</cbc:Percent></cac:TaxCategory></cac:TaxSubtotal></cac:TaxTotal><cac:LegalMonetaryTotal><cbc:LineExtensionAmount currencyID=\"EUR\">100.00</cbc:LineExtensionAmount><cbc:TaxExclusiveAmount currencyID=\"EUR\">100.00</cbc:TaxExclusiveAmount><cbc:TaxInclusiveAmount currencyID=\"EUR\">119.00</cbc:TaxInclusiveAmount><cbc:PayableAmount currencyID=\"EUR\">119.00</cbc:PayableAmount></cac:LegalMonetaryTotal><cac:InvoiceLine><cbc:ID>1</cbc:ID><cbc:InvoicedQuantity unitCode=\"C62\">1</cbc:InvoicedQuantity><cbc:LineExtensionAmount currencyID=\"EUR\">100.00</cbc:LineExtensionAmount><cac:Item><cbc:Name>Item</cbc:Name><cac:ClassifiedTaxCategory><cbc:ID>S</cbc:ID><cbc:Percent>19</cbc:Percent></cac:ClassifiedTaxCategory></cac:Item><cac:Price><cbc:PriceAmount currencyID=\"EUR\">100.00</cbc:PriceAmount></cac:Price></cac:InvoiceLine></Invoice>"
}
response = requests.post(url, json=payload, headers=headers)
print(response.json())package main
import (
"bytes"
"fmt"
"io"
"net/http"
"os"
)
func main() {
url := "https://api.stanzaapi.com/peppol-validator/api/v1/validate"
payload := []byte(`{"xml":"<?xml version=\"1.0\" encoding=\"UTF-8\"?><Invoice xmlns=\"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\"><cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0</cbc:CustomizationID><cbc:ID>INV-01</cbc:ID><cbc:IssueDate>2026-08-10</cbc:IssueDate><cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode><cac:AccountingSupplierParty><cac:Party><cac:PostalAddress><cac:Country><cbc:IdentificationCode>DE</cbc:IdentificationCode></cac:Country></cac:PostalAddress><cac:PartyLegalEntity><cbc:RegistrationName>Supplier</cbc:RegistrationName></cac:PartyLegalEntity></cac:Party></cac:AccountingSupplierParty><cac:AccountingCustomerParty><cac:Party><cac:PostalAddress><cac:Country><cbc:IdentificationCode>FR</cbc:IdentificationCode></cac:Country></cac:PostalAddress><cac:PartyLegalEntity><cbc:RegistrationName>Buyer</cbc:RegistrationName></cac:PartyLegalEntity></cac:Party></cac:AccountingCustomerParty><cac:TaxTotal><cbc:TaxAmount currencyID=\"EUR\">19.00</cbc:TaxAmount><cac:TaxSubtotal><cbc:TaxableAmount currencyID=\"EUR\">100.00</cbc:TaxableAmount><cbc:TaxAmount currencyID=\"EUR\">19.00</cbc:TaxAmount><cac:TaxCategory><cbc:ID>S</cbc:ID><cbc:Percent>19</cbc:Percent></cac:TaxCategory></cac:TaxSubtotal></cac:TaxTotal><cac:LegalMonetaryTotal><cbc:LineExtensionAmount currencyID=\"EUR\">100.00</cbc:LineExtensionAmount><cbc:TaxExclusiveAmount currencyID=\"EUR\">100.00</cbc:TaxExclusiveAmount><cbc:TaxInclusiveAmount currencyID=\"EUR\">119.00</cbc:TaxInclusiveAmount><cbc:PayableAmount currencyID=\"EUR\">119.00</cbc:PayableAmount></cac:LegalMonetaryTotal><cac:InvoiceLine><cbc:ID>1</cbc:ID><cbc:InvoicedQuantity unitCode=\"C62\">1</cbc:InvoicedQuantity><cbc:LineExtensionAmount currencyID=\"EUR\">100.00</cbc:LineExtensionAmount><cac:Item><cbc:Name>Item</cbc:Name><cac:ClassifiedTaxCategory><cbc:ID>S</cbc:ID><cbc:Percent>19</cbc:Percent></cac:ClassifiedTaxCategory></cac:Item><cac:Price><cbc:PriceAmount currencyID=\"EUR\">100.00</cbc:PriceAmount></cac:Price></cac:InvoiceLine></Invoice>"}`)
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(payload))
req.Header.Add("Content-Type", "application/json")
req.Header.Add("x-api-key", os.Getenv("API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", Environment.GetEnvironmentVariable("API_KEY") ?? "YOUR_API_KEY");
var json = @"{""xml"":""<?xml version=\""1.0\"" encoding=\""UTF-8\""?><Invoice xmlns=\""urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\""><cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0</cbc:CustomizationID><cbc:ID>INV-01</cbc:ID><cbc:IssueDate>2026-08-10</cbc:IssueDate><cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode><cac:AccountingSupplierParty><cac:Party><cac:PostalAddress><cac:Country><cbc:IdentificationCode>DE</cbc:IdentificationCode></cac:Country></cac:PostalAddress><cac:PartyLegalEntity><cbc:RegistrationName>Supplier</cbc:RegistrationName></cac:PartyLegalEntity></cac:Party></cac:AccountingSupplierParty><cac:AccountingCustomerParty><cac:Party><cac:PostalAddress><cac:Country><cbc:IdentificationCode>FR</cbc:IdentificationCode></cac:Country></cac:PostalAddress><cac:PartyLegalEntity><cbc:RegistrationName>Buyer</cbc:RegistrationName></cac:PartyLegalEntity></cac:Party></cac:AccountingCustomerParty><cac:TaxTotal><cbc:TaxAmount currencyID=\""EUR\"">19.00</cbc:TaxAmount><cac:TaxSubtotal><cbc:TaxableAmount currencyID=\""EUR\"">100.00</cbc:TaxableAmount><cbc:TaxAmount currencyID=\""EUR\"">19.00</cbc:TaxAmount><cac:TaxCategory><cbc:ID>S</cbc:ID><cbc:Percent>19</cbc:Percent></cac:TaxCategory></cac:TaxSubtotal></cac:TaxTotal><cac:LegalMonetaryTotal><cbc:LineExtensionAmount currencyID=\""EUR\"">100.00</cbc:LineExtensionAmount><cbc:TaxExclusiveAmount currencyID=\""EUR\"">100.00</cbc:TaxExclusiveAmount><cbc:TaxInclusiveAmount currencyID=\""EUR\"">119.00</cbc:TaxInclusiveAmount><cbc:PayableAmount currencyID=\""EUR\"">119.00</cbc:PayableAmount></cac:LegalMonetaryTotal><cac:InvoiceLine><cbc:ID>1</cbc:ID><cbc:InvoicedQuantity unitCode=\""C62\"">1</cbc:InvoicedQuantity><cbc:LineExtensionAmount currencyID=\""EUR\"">100.00</cbc:LineExtensionAmount><cac:Item><cbc:Name>Item</cbc:Name><cac:ClassifiedTaxCategory><cbc:ID>S</cbc:ID><cbc:Percent>19</cbc:Percent></cac:ClassifiedTaxCategory></cac:Item><cac:Price><cbc:PriceAmount currencyID=\""EUR\"">100.00</cbc:PriceAmount></cac:Price></cac:InvoiceLine></Invoice>""}";
var payload = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://api.stanzaapi.com/peppol-validator/api/v1/validate", payload);
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine(content);
}
}Integrate the StanzaAPI peppol-validator micro-API.
Endpoint: POST https://api.stanzaapi.com/peppol-validator/api/v1/validate
Auth header: x-api-key: YOUR_API_KEY
Content-Type: application/json
Request body:
{
"xml": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Invoice xmlns=\"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\"><cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0</cbc:CustomizationID><cbc:ID>INV-01</cbc:ID><cbc:IssueDate>2026-08-10</cbc:IssueDate><cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode><cac:AccountingSupplierParty><cac:Party><cac:PostalAddress><cac:Country><cbc:IdentificationCode>DE</cbc:IdentificationCode></cac:Country></cac:PostalAddress><cac:PartyLegalEntity><cbc:RegistrationName>Supplier</cbc:RegistrationName></cac:PartyLegalEntity></cac:Party></cac:AccountingSupplierParty><cac:AccountingCustomerParty><cac:Party><cac:PostalAddress><cac:Country><cbc:IdentificationCode>FR</cbc:IdentificationCode></cac:Country></cac:PostalAddress><cac:PartyLegalEntity><cbc:RegistrationName>Buyer</cbc:RegistrationName></cac:PartyLegalEntity></cac:Party></cac:AccountingCustomerParty><cac:TaxTotal><cbc:TaxAmount currencyID=\"EUR\">19.00</cbc:TaxAmount><cac:TaxSubtotal><cbc:TaxableAmount currencyID=\"EUR\">100.00</cbc:TaxableAmount><cbc:TaxAmount currencyID=\"EUR\">19.00</cbc:TaxAmount><cac:TaxCategory><cbc:ID>S</cbc:ID><cbc:Percent>19</cbc:Percent></cac:TaxCategory></cac:TaxSubtotal></cac:TaxTotal><cac:LegalMonetaryTotal><cbc:LineExtensionAmount currencyID=\"EUR\">100.00</cbc:LineExtensionAmount><cbc:TaxExclusiveAmount currencyID=\"EUR\">100.00</cbc:TaxExclusiveAmount><cbc:TaxInclusiveAmount currencyID=\"EUR\">119.00</cbc:TaxInclusiveAmount><cbc:PayableAmount currencyID=\"EUR\">119.00</cbc:PayableAmount></cac:LegalMonetaryTotal><cac:InvoiceLine><cbc:ID>1</cbc:ID><cbc:InvoicedQuantity unitCode=\"C62\">1</cbc:InvoicedQuantity><cbc:LineExtensionAmount currencyID=\"EUR\">100.00</cbc:LineExtensionAmount><cac:Item><cbc:Name>Item</cbc:Name><cac:ClassifiedTaxCategory><cbc:ID>S</cbc:ID><cbc:Percent>19</cbc:Percent></cac:ClassifiedTaxCategory></cac:Item><cac:Price><cbc:PriceAmount currencyID=\"EUR\">100.00</cbc:PriceAmount></cac:Price></cac:InvoiceLine></Invoice>"
}
Rules:
- Send the request with a 2-second timeout.
- Parse the standard envelope { success, data, meta: { latency_ms, version } }.
- On failure, read { success: false, error, code } and branch on the code.
- Do not retry 4xx responses; surface the error code to the caller.
- Treat invalid-but-well-formed payloads as HTTP 200 with data.valid === false.Frequently Asked Questions & Technical Notes
Peppol BIS Billing 3.0 is a CIUS (Core Invoice Usage Specification) that extends the base EN 16931 standard with Peppol network-specific rules, such as requiring ISO 6523 Electronic Address Scheme (EAS) endpoints for participant routing.
Related Peppol BIS Billing 3.0 & EN 16931 E-Invoice Engine Formats
Explore sibling specifications and standards in the same developer cluster:
Factur-X / ZUGFeRD 2.2 UN/CEFACT CII E-Invoice Parser & Validator
Parse and validate UN/CEFACT CrossIndustryInvoice XML files (Factur-X / ZUGFeRD 2.2 EN 16931 profile) into structured JSON.
View Format →ISO 6523 Electronic Address Scheme (EAS) Participant Registry
Query active ISO 6523 Electronic Address Scheme (EAS) codes and participant identifier validation formats across all Peppol jurisdictions.
View Format →Complementary Enterprise APIs
Seamlessly orchestrate data pipelines across adjacent financial, regulatory, and supply-chain protocols:
European VIES VAT Validator →
Ensure e-invoice supplier and customer tax IDs match European VIES registrations.
ISO 20022 Financial Messaging →
Bridge structured Peppol billing lines directly into ISO 20022 credit transfer orders.
EU CBAM Carbon Importer Reporting →
Calculate embedded emissions and customs reporting requirements for cross-border shipments.
Factur-X & ZUGFeRD 2.3 →
Extract and validate hybrid PDF/A-3 Factur-X and ZUGFeRD invoices with profile-aware EN 16931 rules.