Skip to content

UBL 2.1 for invoicing

How an OASIS Universal Business Language invoice is put together: the namespaces that identify it, the structures that carry parties, lines and tax, and the places implementations most often go wrong.

What UBL is

UBL is an OASIS standard defining XML documents for business processes — orders, despatch advices, invoices and many more. Version 2.1 is the one European e-invoicing is built on: it is the syntax behind Peppol BIS Billing 3.0 and one of the two syntaxes EN 16931 can be expressed in, the other being UN/CEFACT CII.

A UBL invoice is a tree of typed elements. There is no schema-level flexibility to invent your own fields: what you can express is what the standard defines, and profiles such as Peppol restrict it further.

Namespaces

Four namespace URIs matter for invoicing. These URIs — not the prefixes conventionally bound to them — are what identify an element.

  • urn:oasis:names:specification:ubl:schema:xsd:Invoice-2 — the Invoice document root.
  • urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2 — the CreditNote document root.
  • urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2 — structures, conventionally cac.
  • urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2 — leaf values, conventionally cbc.

The word conventionally is doing real work there. A prefix is a document-local alias. An invoice that declares xmlns:foo="…CommonBasicComponents-2" and writes <foo:ID> is exactly as valid as one writing <cbc:ID>, and so is one that makes the namespace the default and writes <ID>. Any tool that matches on the string cbc: will fail on conformant documents. This is the single most common defect in home-grown UBL parsers.

Document skeleton

An EN 16931-shaped UBL invoice has this order at the top level:

  • cbc:CustomizationID, cbc:ProfileID — the specification and process the document claims to follow.
  • cbc:ID, cbc:IssueDate, cbc:DueDate, cbc:InvoiceTypeCode, cbc:DocumentCurrencyCode, cbc:BuyerReference — the header.
  • cac:AccountingSupplierParty, cac:AccountingCustomerParty, optionally cac:PayeeParty and cac:TaxRepresentativeParty.
  • cac:Delivery, cac:PaymentMeans, cac:PaymentTerms.
  • cac:AllowanceCharge — document-level discounts and surcharges.
  • cac:TaxTotal — the VAT breakdown.
  • cac:LegalMonetaryTotal — the totals.
  • cac:InvoiceLine — one per line, last.

Note that the totals come before the lines. This trips people up when reading a raw document for the first time.

Parties

A cac:Party splits identity across several children, and they mean different things:

  • cac:PartyName/cbc:Name — the trading name.
  • cac:PartyLegalEntity/cbc:RegistrationName — the registered legal name, plus cbc:CompanyID for the registration number and cbc:CompanyLegalForm for additional legal information.
  • cac:PartyTaxScheme/cbc:CompanyID with a nested cac:TaxScheme/cbc:ID of VAT — the VAT identifier.
  • cbc:EndpointID with a schemeID — the electronic address used for routing, for example a Peppol participant identifier.
  • cac:PartyIdentification/cbc:ID — any other identifier, with its scheme.
  • cac:PostalAddress and cac:Contact.

Collapsing these into a single "name" and a single "tax number" loses information. The UBL viewer keeps them apart.

Lines

Each cac:InvoiceLine carries cbc:InvoicedQuantity with a unitCode attribute (UN/ECE Recommendation 20), cbc:LineExtensionAmount for the line net amount, a cac:Item describing what was supplied, and a cac:Price giving the unit price and its base quantity.

The VAT rate for a line is not on the line itself but on cac:Item/cac:ClassifiedTaxCategory, which holds the category code, the percentage and the tax scheme. A gross price is expressed indirectly: UBL has no gross price element, so a discounted price appears as cac:Price/cac:AllowanceCharge whose cbc:BaseAmount is the price before discount.

Tax and totals

cac:TaxTotal holds the total tax amount and one cac:TaxSubtotal per VAT category and rate combination, each with its taxable amount, tax amount, category code, percentage and — where the category requires it — an exemption reason. A document may carry a second cac:TaxTotal expressing the same tax in the accounting currency.

cac:LegalMonetaryTotal then gives the arithmetic of the document:

  • cbc:LineExtensionAmount — the sum of the line net amounts.
  • cbc:AllowanceTotalAmount, cbc:ChargeTotalAmount.
  • cbc:TaxExclusiveAmount — the taxable base.
  • cbc:TaxInclusiveAmount — base plus VAT.
  • cbc:PrepaidAmount, cbc:PayableRoundingAmount.
  • cbc:PayableAmount — the amount actually due.

The relationships between these are exactly what the EN 16931 BR-CO-* rules check. A document can be schema-valid and still fail them.

Where implementations go wrong

  • Matching on prefixes. Covered above, and worth repeating because it is the failure that produces "works with our files, breaks with theirs".
  • Searching descendants instead of children. Using an unscoped descendant search for Name from the document root will find whichever party appears first in the file, which is not necessarily the supplier.
  • Assuming currency is on every amount. In UBL most amounts do carry currencyID, but code that requires it will break on documents that rely on cbc:DocumentCurrencyCode.
  • Parsing amounts with a locale-aware number parser. XSD decimals use a full stop and no thousands separator. A parser that accepts 1.234,56 will produce a number that is not in the document.

Try it

Open a document in the UBL viewer to see these structures resolved, with the raw XML and the parsed model beside them. For the semantic model both UBL and CII implement, see EN 16931; for the other syntax, see UN/CEFACT CII.

Frequently asked questions

What is the difference between cac and cbc?

They are two namespaces, not two kinds of importance. Common Basic Components (cbc) hold leaf values — an ID, a date, an amount. Common Aggregate Components (cac) hold structures that contain other elements, such as a Party or an InvoiceLine. The prefixes cac and cbc are conventions; only the namespace URIs are normative.

Is an Invoice the same document as a CreditNote in UBL?

No. They are separate document types with separate root namespaces (…:xsd:Invoice-2 and …:xsd:CreditNote-2) and different line elements: cac:InvoiceLine with cbc:InvoicedQuantity versus cac:CreditNoteLine with cbc:CreditedQuantity. Some profiles instead express a credit as an Invoice with type code 381 and negative amounts, so both patterns occur in practice.

What does CustomizationID mean?

It is the identifier of the specification the document claims to follow — for example a Peppol BIS Billing 3.0 URN or a plain EN 16931 URN. It is a declaration by the producer, not evidence of conformance. Validating a document means running the rule set that identifier names, which is a separate step.