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. 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 Factur-X / ZUGFeRD 2.2 UN/CEFACT CII E-Invoice Parser & Validator Interactive Workbench
Test real-time validation and schema parsing for Factur-X / ZUGFeRD 2.2 UN/CEFACT CII E-Invoice Parser & Validator directly in your browser. Runs in sub-5ms with zero setup.
{
"status": "Click RUN VALIDATION to execute on the Cloudflare edge..."
}
Quick Summary: Parse and validate UN/CEFACT CrossIndustryInvoice XML files (Factur-X / ZUGFeRD 2.2 EN 16931 profile) into structured JSON. 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.
Factur-X and ZUGFeRD 2.2 are identical Franco-German hybrid e-invoice standards utilizing UN/CEFACT CrossIndustryInvoice XML syntax.
Extracts SupplyChainTradeTransaction, ApplicableHeaderTradeAgreement, ApplicableHeaderTradeSettlement, and IncludedSupplyChainTradeLineItem.
Full validation of trade tax breakdowns, payment means (SEPA Credit Transfer 30/58), and SIREN/SIRET French participant identifiers.
| CII XML Node | Field Name | Target JSON Property | Specification |
|---|---|---|---|
| rsm:ExchangedDocument/ram:ID | Invoice Number | invoice.id | Mandatory string |
| rsm:ExchangedDocument/ram:TypeCode | Document Type Code | invoice.documentType | 380 (Invoice) / 381 (CreditNote) |
| ram:ApplicableTradeTax | Tax Breakdown | invoice.taxSubtotals | UNTDID 5305 Tax Category |
| ram:SpecifiedTradeSettlementHeaderMonetarySummation | Totals | invoice.totals | Line extension, Tax basis, Payable |
Parsed JSON Response Model
The edge microservice transforms input payloads into strongly-typed hierarchical JSON envelopes with sub-5ms latency:
{
"valid": true,
"syntax": "CII_INVOICE",
"profile": "PEPPOL_BIS_BILLING_3_0",
"summary": {
"status": "COMPLIANT",
"fatalCount": 0,
"warningCount": 0
}
}
Copy-Paste Integration Code (6 Languages)
Integrate Factur-X / ZUGFeRD 2.2 UN/CEFACT CII E-Invoice Parser & Validator 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
Yes. Factur-X (CII) and UBL 2.1 are the two primary syntax formats mandated for French B2B electronic invoicing and PDP (Plateforme de Dématérialisation Partenaire) compliance.
Related Peppol BIS Billing 3.0 & EN 16931 E-Invoice Engine Formats
Explore sibling specifications and standards in the same developer cluster:
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.
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.