What UBL actually is
UBL stands for Universal Business Language. It is an open standard maintained by OASIS, and it is not specific to invoicing. UBL defines a whole library of XML document types covering the procurement and supply-chain lifecycle: orders, order responses, despatch advices, catalogues, receipts, and many more. For electronic invoicing, two of these document types matter: the Invoice and the CreditNote. When people say "a UBL invoice," they mean an XML document following the UBL Invoice (or CreditNote) structure.
UBL is a syntax, meaning it defines how invoice data is expressed in XML: which elements exist, how they nest, and what they are named. It is deliberately verbose and descriptive. Element names are long and readable, such as AccountingSupplierParty or LegalMonetaryTotal, which makes a UBL document relatively legible to a human inspecting it, at the cost of being lengthy. The version referenced by the European standard is UBL 2.1.
The anatomy of a UBL invoice
A UBL invoice is organised through two namespaces that you will see throughout any UBL document, usually abbreviated cbc and cac.
The cbc namespace is Common Basic Components. These are the simple, leaf-level elements that hold a single value: an identifier, a date, an amount, a code. Examples are the invoice number, the issue date, or a currency code.
The cac namespace is Common Aggregate Components. These are the composite elements that group other elements together into meaningful structures: a party, an address, a tax total, an invoice line. A cac element contains cbc elements and sometimes other cac elements, building the document up in layers.
With that in mind, the skeleton of a UBL invoice reads fairly logically. At the top sit document-level basic elements: the UBL version, a customization identifier and a profile identifier (discussed below), the invoice number, the issue date, the due date, the invoice type code, and the document currency. Then come the aggregate structures: the supplier party and the customer party, each containing their name, address, and tax registration; the payment means; one or more tax totals broken down by category and rate; the legal monetary totals that summarise the document; and finally the invoice lines, each an aggregate containing the item, quantity, price, and line-level tax. The structure mirrors how a person would read an invoice, from header down to line items to totals.
How UBL relates to EN 16931
UBL does not, on its own, define what a compliant European invoice must contain. That comes from EN 16931, the semantic standard that specifies the data model: the business terms an invoice needs, their meaning, and the rules relating them. EN 16931 is deliberately syntax-neutral at the semantic level, and it permits two syntaxes to express that model. UBL is one of them. The other is UN/CEFACT CII, covered in a separate article in this series.
The relationship is that each semantic element defined by EN 16931 maps to a specific location in the UBL structure. A given business term has a defined path in the UBL document where its value belongs. So producing an EN 16931-compliant UBL invoice means placing every required business term at its correct UBL element path, with the correct codes and formats. UBL is the vessel; EN 16931 defines what has to be in it and where.
Declaring conformance: CustomizationID and ProfileID
One feature of UBL deserves particular attention because it is central to how e-invoicing works in practice: the customization identifier. Because the same UBL Invoice structure is used by many different specifications around the world, a UBL document has to declare which specification it actually follows. It does this through two elements near the top of the document.
The CustomizationID states which specification or national profile the document conforms to. It is a precise string that names, for example, a particular Peppol billing specification, or a national profile. The ProfileID identifies the business process the document is part of, such as a specific billing process. A receiving system reads the CustomizationID first, because it tells the receiver which rule set to validate against. The same physical UBL structure can carry a Peppol invoice, a Dutch national invoice, or a Norwegian one, and it is the CustomizationID that disambiguates which of these it is and therefore which rules apply.
To make this concrete, a Peppol BIS Billing 3.0 invoice declares these two values at the top of the document:
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0</cbc:CustomizationID>
<cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>
A German XRechnung 3.0 invoice, by contrast, keeps the same UBL structure but declares a different CustomizationID:
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0</cbc:CustomizationID>
These identifiers are case-sensitive and must match exactly. Even a minor variation (a wrong separator, an outdated version number, or the older urn:xoev-de:kosit:standard:xrechnung_3.0 form still seen in some tooling) causes the receiver to misidentify or reject the document. This is why two UBL invoices can look structurally identical and yet be judged against different rules. The syntax is shared; the declared specification is not.
The CIUS landscape: one syntax, many profiles
Because UBL is a stable, widely-adopted syntax, it has become the base for a large number of national and network-specific invoice specifications. These are often called CIUS, Core Invoice Usage Specifications, meaning a constrained, specialised version of the core standard for a particular context.
UBL is the syntax behind Peppol BIS Billing, the Dutch NLCIUS, the Norwegian EHF, the Danish national profile, the German XRechnung (which can be expressed in either UBL or CII), and the PINT-based profiles used in markets such as Singapore, Australia, and Japan. Each of these takes the UBL Invoice as its structural base and layers its own additional rules and constraints on top. This is what makes UBL so significant: learning the format once gives you the structural foundation for invoicing across a wide range of countries and networks, even though the specific rules differ between them.
Validating a UBL invoice
Validation of a UBL invoice happens in two distinct layers, and understanding the difference explains where most real-world problems occur.
The first layer is XSD schema validation. The UBL schemas define the structural grammar: which elements are allowed, their order, their data types. Schema validation confirms the document is well-formed UBL. It is necessary but shallow, it catches malformed structure but knows nothing about business logic.
The second layer is Schematron validation, which is where the business rules live. The EN 16931 rules and any applicable CIUS rules (the Peppol overlay, a national profile's rules) are expressed as Schematron and check the logic of the invoice: that totals reconcile, that VAT breakdowns are consistent, that conditionally required fields are present, that codes come from the correct lists. A UBL invoice can pass XSD validation perfectly and still fail dozens of Schematron rules. This second layer is where most rejections originate, and it is the layer that determines whether an invoice is genuinely acceptable rather than merely well-formed.
A technical point worth noting: the official Schematron artefacts are implemented in XSLT 2.0. Many environments only support XSLT 1.0 by default, so executing the full rule set requires a suitable processor. Validating structure without validating business rules is a common shortcut and a common cause of invoices that pass internal checks and then get rejected downstream.
The maintenance dimension
The UBL syntax itself is stable and changes rarely. The moving parts are the specifications built on top of it. The EN 16931 rules and code lists are revised periodically, and each CIUS, Peppol BIS, XRechnung, the various national profiles, evolves on its own schedule, with new versions, adjusted rules, and effective dates by which the new version must be in use.
For anyone maintaining a UBL integration directly, this means the format is not the maintenance burden, the rules are. Keeping current involves tracking the specifications relevant to the markets you serve, obtaining updated Schematron and code lists, testing existing output against the revised rules, and deploying by each version's effective date. The more countries and profiles you support, the more of these schedules you are tracking at once.
Where a service fits in
Producing structurally correct UBL is achievable with care. The harder, ongoing part is producing UBL that is valid against the right specification for each market, and keeping that current as the rules change.
This is the kind of work that can be delegated rather than built and maintained in house. InvoiceXML generates valid UBL invoices and validates them against EN 16931 and the applicable CIUS overlay, whether that is Peppol BIS, a national profile such as NLCIUS or EHF, or a PINT-based profile for a non-European market, applying the correct CustomizationID and the corresponding rule set automatically. It can be reached through a REST API for direct integration, through no-code automation platforms, or through an MCP interface for AI-driven and agentic workflows. Because the specifications and their rule sets are maintained on the service's side, updates arrive without you tracking release schedules or re-integrating Schematron artefacts.
Building it in house remains entirely viable for teams that want full control and have the capacity to maintain it. The purpose of this overview is simply to make the format legible: UBL is a shared, verbose XML syntax, structured through basic and aggregate components, that expresses the EN 16931 model and declares through its CustomizationID which of many specifications it follows. Once that structure is clear, the rest of the e-invoicing landscape, the networks that carry UBL and the national profiles that constrain it, becomes much easier to reason about.