An invoice that conforms perfectly to EN 16931 can be rejected in a way that reads, to the person receiving the rejection, like nonsense: the field the receiver is complaining about is optional in the standard, and they left it out because it is optional.

Both parties are right. The receiver is validating against a profile, and profiles are where the European standard stops being one thing.

What a profile does

A core invoice usage specification is a published restriction of the standard for a particular context. Three operations are available to it, and only three:

  1. Make optional mandatory. The standard permits a buyer reference; a profile requires it.
  2. Forbid what the standard permits. The standard allows a delivery address; a profile excludes it.
  3. Narrow a code list or a value range. The standard permits any code from a list; a profile permits four of them.

What a profile cannot do is add. If a profile appears to add a field, it is either using an element of the standard in a specific way, or it is not a profile — it is a profile plus an extension.

That restriction is the reason the whole arrangement works. A receiver that can process the standard can process any conforming profile of it, because a profile only ever produces documents that are already valid against the standard. The converse is not true, which is exactly the asymmetry that surprises people.

The four layers between the European semantic model and what a specific receiver will actually accept.
The four layers between the European semantic model and what a specific receiver will actually accept.

The specification identifier

Every conforming document carries an identifier saying which specification it claims to follow. It is a small element and it does a large job: it tells the receiver which rule set to run.

Two failure modes are worth knowing.

The wrong identifier. The document declares one profile and is built to another. Validation then applies rules the document was never designed to satisfy, and the resulting error list is long, confusing and unrelated to the actual problem.

A default identifier. A system that emits the same identifier for every document, regardless of destination, will pass in the country it was configured for and fail elsewhere. This is common in first implementations and is one of the more satisfying bugs to find, because the fix is a single field.

What to check first when a document is rejected in one country and accepted in another

The specification identifier. Before the mapping, before the code lists, before the totals. It is the cheapest thing to verify and it explains a surprising share of cross-border rejections.

Layered profiles

In practice more than one profile applies at once. A document exchanged over a European network into a country with a national profile has to satisfy both: the network's specification and the national restrictions.

What a document may have to satisfy simultaneously
LayerSet byTypical restriction
European standardThe standard itselfTotals must reconcile; VAT breakdown must be complete
Network profileThe network's governing bodyA defined identifier scheme; mandatory buyer reference
National profileA national body or tax administrationNational identifiers; mandatory payment terms
Receiver rulesThe buying organisationPurchase order reference; approved cost centre

The union of those restrictions is the target. Building to the European standard alone, and expecting the layers above to be forgiving, is how a pilot that worked becomes a rollout that does not. The full picture is in testing against a real validation stack.

Extensions, and why to avoid them

An extension carries information the core model has no term for: a sector-specific product classification, a complex rebate structure, a logistics reference nobody outside your industry uses.

Extensions are legitimate, and they are the correct answer when the information genuinely does not fit. They also have a property that makes them a poor default: a conforming receiver is not obliged to understand them. Anything you put in an extension may be silently ignored by the party you sent it to, and you will not be told.

Three consequences follow.

  • Never put commercially essential information in an extension unless you have a bilateral agreement that the receiver reads it. A payment condition in an extension is a payment condition that does not exist.
  • Extensions do not convert. If you also produce the other syntax, or if a provider converts on your behalf, extension content is where conversion loses things.
  • Extensions complicate archiving. The instance you keep must be the instance you sent, extensions and all, which rules out storing a normalised core-only version for convenience. See archiving a structured invoice.

Before reaching for an extension, check whether the standard already has a term that fits. It has more of them than most implementations use, and the exercise of reading through the model looking for a home for a piece of data is the fastest way to learn what is in it. The mechanics are in business terms and business groups.

How to work with profiles rather than against them

Treat each profile as a target with a test suite. Not a variant of a shared target. Each has its own mandatory elements, its own code list restrictions and its own rules.

Keep a matrix. Which profiles you must satisfy, which of your document shapes each has been tested with, and when. Nobody keeps this by accident and everybody needs it at the second country.

Read the release notes. Profiles are versioned and they change, typically once or twice a year. A version that was mandatory becomes deprecated and then unacceptable, and the transition window is not generous. This is an operational subscription, not a project task, and it belongs with whoever owns exception handling.

Do not build a profile of your own. If you are a large buyer, the temptation to publish your own restrictions is strong and the cost falls on your suppliers, several of whom will simply keep sending PDFs and dare you to reject them. Where you genuinely need extra data, ask for it in an element the standard already provides.