Automation MCP Server Features Blog Pricing Contact
POST /v1/validate/ubl

UBL Validation API

Validate UBL 2.1 invoices and credit notes against the UBL XSD schema, EN 16931 Schematron, and the right Peppol BIS Billing 3.0 or national CIUS overlay, returned as structured JSON in under two seconds.

UBL is the native XML syntax of the Peppol network and one of the two EN 16931 syntaxes. The API auto-detects the applied CIUS from the CustomizationID (BT-24), Peppol BIS Billing 3.0, NLCIUS, EHF Billing 3.0, XRechnung in UBL, or PINT, and runs the same multi-layer checks a Peppol access point applies before accepting a document for delivery. Every violation is reported with rule ID, severity, and XPath location.

Bash
curl -X POST https://api.invoicexml.com/v1/validate/ubl \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "[email protected]"
200 OK · Application/JSON
{
  "valid": true,
  "data": {
    "profile": "ehf",
    "customizationId": "urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0#conformant#urn:fdc:anskaffelser.no:2019:ehf:spec:3.0"
  },
  "errors": [],
  "warnings": []
}

Try it live, no API key required

This runs the same POST /v1/validate/ubl endpoint your integration will call. Drop any UBL XML, Peppol BIS, NLCIUS, EHF, XRechnung, or PINT, to see the full validation response and detected profile.

Drop your UBL XML here

or browse files to upload

POST /v1/validate/ubl · Accepted: UBL 2.1 Invoice or CreditNote XML · Max 20 MB

Submit any UBL 2.1 Invoice or CreditNote XML. The API reads the CustomizationID (BT-24) to detect your Peppol BIS or national CIUS, NLCIUS, EHF Billing 3.0, XRechnung in UBL, or PINT, then runs the correct XSD schema, EN 16931 Schematron, and profile-specific overlay rules. Every rule violation is returned with its rule ID, severity, and the validation layer it came from: en16931 or the specific CIUS that fired it.
UBL profile ladder

One UBL syntax, many country profiles. The CustomizationID picks the rules.

UBL validation is layered. Every invoice is first checked against the OASIS UBL 2.1 XSD, then the 200+ EN 16931 business rules, then a Customised Usage Specification (CIUS) that narrows EN 16931 for a specific network or country. The CIUS is never something you pass as a parameter: the API reads it from the CustomizationID (BT-24) inside the document and applies the matching overlay automatically. A document declaring the Peppol BIS Billing 3.0 identifier gets the Peppol overlay; a Norwegian EHF document declaring the anskaffelser.no conformant identifier gets the EHF overlay on top of Peppol.

Supported overlays, all from one endpoint:

  • Peppol BIS Billing 3.0, the cross-border baseline for the whole Peppol network.
  • NLCIUS (Netherlands, SimplerInvoicing), the Dutch CIUS used for domestic and public-sector invoicing.
  • EHF Billing 3.0 (Norway), built on Peppol BIS and mandatory for the Norwegian public sector.
  • XRechnung in UBL syntax (Germany), the German CIUS for B2G, also expressible in the CII syntax.
  • PINT and A-NZ PINT (Peppol International), the basis for Australia, New Zealand, Singapore, Japan, and Malaysia.

Because detection is driven by the document, you can onboard a Belgian supplier (B2B mandate from 2026), a Dutch buyer on NLCIUS, and a Norwegian counterparty on EHF without writing a single branch in your integration. The same /v1/validate/ubl call returns the profile it actually applied in data.profile.

Validation report

Not just pass or fail. A full UBL compliance report.

A Peppol access point rejection tells you a document failed and little else. The InvoiceXML UBL API returns a complete report array on every response: one row for each EN 16931 Business Term found in your Invoice or CreditNote, each with the extracted value and a pass or fail verdict, evaluated against the CIUS the document actually declared. Run it as a pre-submission pre-flight and catch Peppol BIS, EHF, or NLCIUS problems before the document reaches the network, with zero cac: and cbc: XML parsing on your side.

UBL Compliance Report

invoice-ubl.xml · Peppol BIS Billing 3.0 · EHF Billing 3.0 (Norway)

162 terms 160 passed 2 failed
Status Business Term Field Value
BT-1 Invoice number invoiceNumber EHF-2026-04417
BT-5 Invoice currency currency NOK
BT-27 Seller name seller.name Nordisk Handel AS
BT-31 Seller VAT identifier seller.vatIdentifier NO999888777MVA
BT-49 Buyer electronic address buyer.electronicAddress Missing. Peppol BIS requires a buyer electronic address.
BT-112 Invoice total with VAT totals.grandTotalAmount 14 875.00
BT-115 Amount due for payment totals.duePayableAmount Inconsistent. Document total cannot be reconciled.

Rendered from the report array. Each row is one object: code, name, section, path, value, isValid, and error. Example supplier Nordisk Handel AS (Norway), declared profile EHF Billing 3.0 over Peppol BIS, currency NOK.

Peppol access point pre-flight

Run the report before you hand a document to your access point. A single failing row exposes the exact Business Term that would trigger a Peppol BIS, EHF, or NLCIUS rejection, so you fix it in your own UI instead of decoding a cryptic network rejection code hours later. The same pre-flight protects you for the Belgium B2B 2026 mandate, the Netherlands, and the Nordics from one integration.

Inline form highlighting

The path on every report row, and the fields array on every friendly error, map straight to your invoice form inputs. Mark the failing field red and show the message beside it, so a Norwegian supplier corrects the exact value, for example buyer.electronicAddress or seller.vatIdentifier, before resubmitting an EHF invoice.

Multi-country profile coverage

The report is built the same way whether the document is a plain EN 16931 UBL invoice, a Peppol BIS 3.0 invoice from any market, an NLCIUS invoice for a Dutch buyer, an EHF invoice for Norway, an XRechnung in UBL for Germany, or a PINT invoice for Australia, New Zealand, Singapore, Japan, or Malaysia. It covers both Invoice and CreditNote types, so one rendering component handles every profile and trading partner you onboard.

Just need to create or validate one invoice?

Skip the API. Use getubl.com

Our online companion tool. Create and validate UBL invoices in your browser, no integration, no API key, no code. Perfect for freelancers, small businesses, and one-off invoices.

Open getubl.com

Validate UBL REST API Request

A single endpoint handles every UBL invoice and credit note profile. Document type and CIUS are detected from the CustomizationID inside the submitted XML automatically:

Request
$ curl -X POST https://api.invoicexml.com/v1/validate/ubl \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "[email protected]"

# Also accepts UBL CreditNote documents
$ curl -X POST https://api.invoicexml.com/v1/validate/ubl \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "[email protected]"

You only send the file. The API reads the CustomizationID, detects the document type and CIUS, and returns the detected values. No profile parameter to set or keep in sync.

Validate UBL API Response

Both valid and invalid documents return HTTP 200. The data.profile field tells you which rule set the API validated against, as a stable slug like peppol-bis-3, nlcius, ehf, xrechnung or pint, critical when you are processing invoices from trading partners across the Netherlands, Norway, Germany, and the wider Peppol network who declare different profiles in their CustomizationID. The full declared identifier is echoed in data.customizationId.

The layer field on each finding distinguishes structural failures (xsd) from EN 16931 base rule violations (en16931) and profile overlay violations (cius). A cius-layer error on an EHF or Peppol BIS invoice means your document satisfies the European standard but fails the network or national overlay, it would be rejected by your access point even though it is technically EN 16931 compliant.

Each friendly error also carries btCodes and a fields array of dotted JSON paths the error maps to, so a front-end form can highlight the exact input that failed, for example buyer.electronicAddress. Every response, valid or not, also includes a report array with one row per EN 16931 Business Term found on the document, each with its value and a pass or fail flag, ready to render as a compliance table.

Valid UBL Response (EHF, Norway)

Response, valid invoice
// 200 OK
{
  "valid": true,
  "detail": "Your invoice is UBL 2.1 compliant and meets the EHF Billing 3.0 (Norway) rules over Peppol BIS Billing 3.0.",
  "data": {
    "schemaValid": true,
    "schematronValid": true,
    "conformanceLevel": "UBL 2.1",
    "profile": "ehf",
    "customizationId": "urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0#conformant#urn:fdc:anskaffelser.no:2019:ehf:spec:3.0"
  },
  "errors": [],
  "warnings": [],
  "report": [
    { "code": "BT-1", "name": "Invoice number", "section": "header", "path": "invoiceNumber", "value": "EHF-2026-04417", "isValid": true, "errors": [], "warnings": [] }
    // one row per EN 16931 business term, see the compliance report section below
  ]
}

Invalid UBL Response (Peppol BIS overlay)

Response, invalid invoice
// 200 OK
{
  "valid": false,
  "detail": "Validation failed with 3 error(s)",
  "data": {
    "schemaValid": true,
    "schematronValid": false,
    "conformanceLevel": "UBL 2.1",
    "profile": "ehf",
    "customizationId": "urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0#conformant#urn:fdc:anskaffelser.no:2019:ehf:spec:3.0"
  },
  "errors": [
    {
      "rule": "PEPPOL-EN16931-R010",
      "layer": "cius",
      "line": null,
      "message": "Peppol BIS requires a buyer electronic address. Add the buyer's electronic address (a buyer VAT identifier is used as a fallback), or use the plain en16931 profile if the invoice is not meant for Peppol.",
      "btCodes": ["BT-49"],
      "fields": ["buyer.electronicAddress"],
      "raw": "[PEPPOL-EN16931-R010] CIUS: Buyer electronic address MUST be provided (at /*:Invoice/cac:AccountingCustomerParty)" },
    {
      "rule": "BR-CO-14",
      "layer": "en16931",
      "line": null,
      "message": "The invoice total VAT amount does not match the sum of VAT breakdown amounts. Check that all VAT calculations are consistent.",
      "btCodes": ["BT-110"],
      "fields": ["totals.taxTotalAmount"],
      "raw": "[BR-CO-14] Invoice total VAT amount must equal the sum of VAT breakdown amounts. (at /*:Invoice/cac:TaxTotal)" },
    {
      "rule": "BR-61",
      "layer": "en16931",
      "line": null,
      "message": "Payment means code 30 or 58 requires a PaymentMeans/PayeeFinancialAccount/ID (IBAN). Add the payee account identifier to the payment means block.",
      "btCodes": ["BT-84"],
      "fields": ["paymentDetails.paymentAccountIdentifier"],
      "raw": "[BR-61] If the payment means code is 30 or 58, a payment account identifier must be present. (at /*:Invoice/cac:PaymentMeans)" }
  ],
  "warnings": [],
  "report": [
    // full field-by-field report, see the compliance report section below
    { "code": "BT-49", "name": "Buyer electronic address", "section": "buyer", "path": "buyer.electronicAddress", "value": null, "isValid": false, "errors": ["Peppol BIS requires a buyer electronic address."], "warnings": [] }
  ]
}

Unknown CIUS? You still get a verdict

If the CustomizationID declares a profile the API has no dedicated rules for, the document is validated against the EN 16931 base rules instead of being rejected, and the response says exactly what happened:

Response, unrecognised CustomizationID
// 200 OK
{
  "valid": true,
  "detail": "Your invoice is UBL 2.1 compliant and meets the EN 16931 specifications.",
  "data": {
    "schemaValid": true,
    "schematronValid": true,
    "conformanceLevel": "UBL 2.1",
    "profile": null,
    "customizationId": "urn:cen.eu:en16931:2017#compliant#urn:example:custom-cius:v9"
  },
  "errors": [],
  "warnings": [
    {
      "rule": "PROFILE-DETECTION",
      "layer": "cius",
      "line": null,
      "message": "The declared CustomizationID 'urn:cen.eu:en16931:2017#compliant#urn:example:custom-cius:v9' is not a profile this validator has dedicated rules for. The invoice was validated against the EN 16931 base rules only.",
      "btCodes": [],
      "fields": [],
      "raw": "[PROFILE-DETECTION] CIUS: The declared CustomizationID 'urn:cen.eu:en16931:2017#compliant#urn:example:custom-cius:v9' is not a profile this validator has dedicated rules for. The invoice was validated against the EN 16931 base rules only." }
  ]
}
Standards maintained for you

OpenPeppol ships in spring and autumn waves. We switch on the go-live date, you change nothing.

OpenPeppol publishes Peppol BIS Billing 3.0 updates in scheduled spring and autumn release waves, each with a fixed go-live date, and the national CIUS bodies (NLCIUS, EHF, XRechnung, PINT) update on their own cadence. Self-hosted open-source validators such as the KoSIT validator or Mustang put that whole calendar on you: you have to track every release wave, download the new Schematron and XSD, upgrade the library, redeploy, and hope nothing regressed before the rules go live.

InvoiceXML removes that work entirely. When OpenPeppol or a national authority publishes a new XSD schema, Schematron rule set, or validation artifact, we ship the updated artifacts and switch /v1/validate/ubl to them on the standard's official effective date, automatically. Your integration keeps calling the same endpoint and is always validating against the currently-effective rules: no tracking release waves, no monitoring standards bodies, no library upgrades, no redeploys, no maintenance.

Zero changes on your side

Same endpoint, same request. The currently-effective rule set is applied for you on each release date.

No silent drift

Eliminates the risk of an integration falling out of compliance the day a Peppol wave goes live.

0.3 to 0.5 FTE removed

The compliance-maintenance burden a self-hosted validator demands is no longer yours to carry.

What the UBL validation API checks

UBL 2.1 XSD Schema

Validates the document against the OASIS UBL 2.1 XSD schema, UBL-Invoice-2.1.xsd for Invoice documents and UBL-CreditNote-2.1.xsd for CreditNote documents. Catches structural errors in the cac: and cbc: component hierarchy, incorrect data types in monetary amounts and quantities, missing required elements, and namespace declaration errors. The document type is detected from the root element before the correct schema is applied.

EN 16931 Schematron

Validates all 200+ EN 16931 business rules against the UBL syntax. Includes the UBL-specific rule implementations: cac:TaxTotal/cbc:TaxAmount arithmetic (BR-CO-14), PaymentMeans account identifier rules (BR-61, BR-62), party address requirements (BR-07, BR-08), and VAT category conditional rules (BR-AE-05 through BR-E-02). Errors from this layer indicate European standard non-compliance, the common ground under Peppol BIS, EHF, NLCIUS, XRechnung, and PINT.

Peppol BIS and National CIUS Rules

When the CustomizationID declares a Peppol or national CIUS, the API automatically runs the corresponding overlay Schematron on top of EN 16931. Peppol BIS Billing 3.0 rules (PEPPOL-EN16931-Rxx codes) enforce network-specific constraints like invoice type code values and endpoint identifier schemes. National overlays for NLCIUS (Netherlands), EHF Billing 3.0 (Norway), XRechnung (Germany), and PINT (Australia, New Zealand, Singapore, Japan, Malaysia) add their own requirements. Errors from this layer cause Peppol access point rejection even when EN 16931 passes.

CustomizationID Profile Detection

Reads the cbc:CustomizationID element (BT-24) to identify the declared CIUS and routes the document to the correct validation stack. A plain EN 16931 UBL invoice, a Peppol BIS 3.0 invoice, an NLCIUS invoice for a Dutch buyer, an EHF invoice for Norway, and a PINT invoice for Australia or New Zealand all declare different CustomizationID values and require different Schematron artefacts. The API handles all of them from a single endpoint, no profile parameter required.

UBL Validation Response Schema

Both valid and invalid documents return HTTP 200. The profile and customizationId fields confirm exactly which CIUS was validated, useful when processing invoices from trading partners across Belgium, the Netherlands, Norway, Germany, and the wider Peppol markets who may declare different profiles. The layer field on each error tells you whether to fix an EN 16931 data problem or a Peppol network-specific configuration issue. Create/convert endpoints return HTTP 400 with the same errors structure on validation failure.

Field Type Description
Always present
validbooleanPrimary flag to branch on. true when the document passes UBL XSD, EN 16931 Schematron, and all applicable CIUS overlay rules.
detailstringHuman-readable summary naming the rule set that was applied, e.g. "Your invoice is UBL 2.1 compliant and meets the EHF Billing 3.0 (Norway) rules."
data.conformanceLevelstringSyntax conformance label, e.g. UBL 2.1.
data.profilestring?The profile whose rules were applied, as a stable slug: peppol-bis-3, en16931, nlcius, ehf, xrechnung or pint. Null when the declared CustomizationID has no dedicated rule set (the EN 16931 base rules are applied and a PROFILE-DETECTION warning explains it).
data.customizationIdstring?Full CustomizationID URI (BT-24) read from the submitted XML, e.g. urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0.
data.schemaValidbooleanUBL 2.1 XSD schema check passed for the detected document type.
data.schematronValidbooleanAll EN 16931 and applicable CIUS Schematron rules passed.
Findings (always present)
errorsobject[]Flat array of finding objects, one per rule violation. Empty array when the document is valid.
warningsobject[]Flat array of finding objects for non-fatal issues. The document is still compliant when only warnings are present. May contain entries on a valid response.
[].rulestringRule identifier, e.g. PEPPOL-EN16931-R010, BR-CO-14, BR-61.
[].layerstringValidation layer that produced the finding: xsd (structure), en16931 (European standard base rules), or cius (the profile overlay: Peppol BIS, EHF, NLCIUS, XRechnung or PINT rules).
[].lineint?Invoice line item number from the InvoiceLine sequence, or null for document-level findings.
[].messagestringFriendly, human-readable description referencing the UBL element concept in plain language, not the cac:/cbc: XPath.
[].btCodesstring[]EN 16931 Business Term codes the rule references, e.g. ["BT-49"].
[].fieldsstring[]Dotted JSON paths the finding maps to, e.g. ["buyer.electronicAddress"]. Use them to highlight the exact form input that failed.
[].rawstringVerbatim technical validator output, including the rule code and XPath location, e.g. "[PEPPOL-EN16931-R010] Buyer electronic address MUST be provided. (at /*:Invoice/cac:AccountingCustomerParty)".
Compliance report (always present)
reportobject[]One row per EN 16931 Business Term found on the invoice, with its value and a pass/fail flag. null if the report could not be built.
report[].codestringBusiness Term code, e.g. BT-1.
report[].namestringHuman-readable term name, e.g. Invoice number.
report[].sectionstringGrouping for display: header, seller, buyer, lines, payment, totals, or tax.
report[].pathstringDotted JSON path to the field, e.g. lines[0].priceDetails.netPrice.
report[].valuestring?Current value of the term, or null when absent.
report[].isValidbooleanfalse when a validation error references this term, otherwise true.
report[].errorsstring[]All friendly error messages on this Business Term. Empty array when the term has no errors.
report[].warningsstring[]All friendly warning messages on this Business Term. Empty array when the term has no warnings.

Integrate UBL validation into your workflow

REST API

Call POST /v1/validate/ubl from any language. Invoice and CreditNote documents handled automatically. Returns structured JSON in under 2 seconds. Use the profile field to log which CIUS your Peppol trading partners are submitting: NLCIUS, EHF, XRechnung, PINT, or plain Peppol BIS. A profile mismatch between sender and receiver is a frequent source of silent Peppol delivery failures.

API docs

Zapier / Make / n8n

Validate UBL invoices received from your Peppol access point before they enter your AP system. Branch on the layer field in the friendly errors array: a cius error means a Peppol BIS or national overlay issue the supplier needs to fix, while an en16931 error means a data problem in the invoice itself. Route each type to a different notification workflow as you onboard suppliers across the Netherlands, the Nordics, and Belgium's 2026 B2B mandate.

Automation integrations

CI/CD Pipeline

OpenPeppol ships Peppol BIS updates in spring and autumn release waves. When a new wave goes live, the InvoiceXML rules switch automatically on the effective date, so your pipeline catches PEPPOL-EN16931-Rxx regressions before non-compliant invoices reach your access point and generate network rejection codes with no obvious link to the change that caused them. No Schematron download, no library bump, no redeploy on your side.

View cURL example

Complete UBL Toolkit

Everything you need to create, convert, validate, and preview UBL invoices, via REST API or online.

Frequently Asked Questions

Which Peppol and national UBL profiles does the validation API support?

The API reads the CustomizationID (BT-24) and applies the matching CIUS Schematron automatically. Supported profiles are plain EN 16931 UBL, Peppol BIS Billing 3.0, NLCIUS (Netherlands, SimplerInvoicing), EHF Billing 3.0 (Norway, built on the Peppol rule set), XRechnung in UBL syntax (Germany), and PINT including A-NZ PINT (Peppol International, covering Australia, New Zealand, Singapore, Japan, and Malaysia). Both Invoice and CreditNote document types are supported for every profile.

Who keeps the UBL and Peppol BIS rules up to date, and when do new versions take effect?

InvoiceXML does. OpenPeppol publishes Peppol BIS Billing 3.0 updates in scheduled spring and autumn release waves, each with a fixed go-live date, and national authorities update their CIUS (NLCIUS, EHF, XRechnung, PINT) on their own cadence. When a new XSD, Schematron rule set, or validation artifact is published, we ship it and switch /v1/validate/ubl to it on the standard's official effective date. Your integration keeps calling the same endpoint and is always validating against the currently-effective rules, with no tracking of release waves, no library upgrades, and no redeploys on your side. That removes the 0.3 to 0.5 FTE compliance-maintenance burden a self-hosted validator (KoSIT validator, Mustang) puts on your team and the risk of silently falling out of compliance the day a wave goes live.

Does the API validate UBL CreditNote documents as well as invoices?

Yes. UBL defines Invoice and CreditNote as separate document types with slightly different element constraints. The API detects the root element automatically, Invoice or CreditNote, and applies the correct XSD schema and Schematron rules for each, including the matching Peppol BIS or national CIUS overlay. CreditNote-specific rules around negative amounts, reason codes, and document references are validated correctly.

Why does my UBL invoice pass EN 16931 validation but get rejected by the Peppol network?

EN 16931 and Peppol BIS Billing 3.0 are two different validation layers. A document can satisfy all 200+ EN 16931 business rules and still fail the Peppol BIS overlay, for example PEPPOL-EN16931-R010 (a buyer electronic address must be provided) or PEPPOL-EN16931-R004 (the CustomizationID must be exactly the Peppol BIS identifier). The InvoiceXML UBL validation API runs both layers automatically when the CustomizationID declares a Peppol or national profile, so pre-submission validation catches access-point rejections before they reach the network. The layer field on each finding tells you whether the failure came from the en16931 base rules or the cius overlay.

Start free today

Ready to automate your invoices?

Validate, convert and embed compliant e-invoices through one API. Start your 30-day free trial. No credit card required.

GDPR Compliant No credit card required Setup in minutes
Peppol UBL
Factur-X
EN 16931
142 / 142 passed
Compliant
PDF/A-3 embedded