Skip to content
einvoicing.dev

The guideChapter 03

Participant identifiers

A scheme and a value, the UK codes that matter, and why the same company can exist twice on the network.

An email address is a string somebody tells you. A Peppol identifier is a pair: a scheme, saying what kind of identifier this is, and a value, the identifier itself. Written down it looks like this:

9932:GB123456789

9932 is the scheme — a UK VAT number — and GB123456789 is the value. The scheme codes come from the EAS list, an official code list maintained for exactly this purpose. Without the scheme the value is ambiguous: plenty of countries issue numbers that look alike, and the network has to know which register it is being pointed at.

The codes a UK developer meets

  • 9932 — UK VAT number. The usual identifier for a UK business.
  • 0088 — GLN, a GS1 global location number. Common in retail supply chains, and what the NHS uses.
  • 0060 — DUNS number, occasionally seen with larger multinationals.

And one absence that catches people out: there is no scheme for a Companies House number. A company registration number is the obvious identifier for a UK business and it is not how Peppol addresses one. If your data model treats the company number as the primary key for a counterparty — which is reasonable for every other purpose — you will need somewhere to keep a Peppol identifier alongside it.

Scheme 0192, which turns up in search results as a “national organisation number”, is Norwegian. It is not a UK code.

The same company, twice

UK VAT numbers are written both with and without the GB prefix, and both forms exist as registrations on the network. Peppol treats them as different participants: 9932:GB123456789 and 9932:123456789 hash to different addresses, resolve through different DNS lookups, and can have different Access Points behind them — or one can exist while the other does not.

There is no way to reason your way around this from first principles. The reliable approach is to try both forms and use whichever answers, which is what GET /v1/participants/{id} does, reporting back the form that is actually registered. If you implement lookups yourself, do the same, and store the form that answered rather than the form you were given.

Identifiers are matched case-insensitively, and the network works in lower case because the identifier is hashed on the way into the SML. Expect a lookup to return gb123456789 where you sent GB123456789; that is normal, not a mangled value.

Looking one up

A lookup answers two questions at once: is this participant on the network, and what can they receive?

curl https://api.einvoicing.dev/v1/participants/9932:GB123456789 \
  -H "Authorization: Bearer $EINVOICING_API_KEY"

Three things about the answer are worth designing around.

Not registered is an answer, not an error. A participant who is not on the network comes back as a successful response saying registered: false. Absence from a public register is a fact about the world; treating it as a 404 pushes application logic into exception handling, where it tends to turn into “something went wrong” in front of a user who needed to be told “this customer cannot receive e-invoices yet”.

A missing directory entry means nothing. The Peppol Directory is optional for participants, so directory comes back null for plenty of businesses that are registered and reachable. Only the SML and SMP are authoritative. This is the single most common way a home-grown lookup goes wrong.

Capabilities matter as much as existence. The response lists the document types the participant accepts. A business registered to receive orders but not invoices is registered — and will still reject your invoice. Check for the document type you are about to send, not merely for the participant.

What to do in your own code

  • Store the scheme and the value separately, or store the identifier in its scheme:value form, but never store a bare number and reconstruct the scheme later from a country field. That is how a GLN becomes a VAT number in a report six months on.
  • Ask for it. The simplest way to learn a counterparty’s Peppol identifier is to ask them for it during onboarding, next to the VAT number you already collect.
  • Look it up before you send, and cache the result. Registrations change rarely, and the lookup is a live network call: einvoicing.dev caches for up to five minutes and tells you when it last asked, in checked_at.
  • Re-check when sending fails. A participant who moves Access Point keeps the same identifier, so a cached endpoint can go stale while the identifier stays right.

With an identifier that resolves and a document type the receiver accepts, what is left is the document itself — which is where the rules live, and the next chapters.

Checked against its sources on 17 September 2026

Get the rest by email

One email when the guide is finished, and an explainer on Budget day.

Developer docs

Getting a key, validating a document, and the API reference.