Peppol Identifiers
Every participant on the Peppol network has a unique identifier. Understanding how these identifiers work is essential for successful document exchange.
Identifier Structure
A Peppol identifier consists of two parts:
{scheme}:{identifier}
For example:
0106:12345678— Netherlands Chamber of Commerce number0204:DE123456789— German VAT number9925:0123456789— French SIRET number
Common Identifier Schemes
European Schemes
| Scheme | Country | Name | Format Example |
|---|---|---|---|
0007 | 🇸🇪 Sweden | Organisationsnummer | 1234567890 |
0088 | 🌍 Global | EAN/GLN | 1234567890123 |
0096 | 🇩🇰 Denmark | CVR | 12345678 |
0106 | 🇳🇱 Netherlands | KVK | 12345678 |
0130 | 🇪🇺 EU | Directorates-General | DIGIT.B.3 |
0184 | 🇩🇰 Denmark | CVR (alternative) | DK12345678 |
0190 | 🇳🇱 Netherlands | OIN | 00000001234567890000 |
0192 | 🇳🇴 Norway | Organisasjonsnummer | 123456789 |
0195 | 🇸🇬 Singapore | UEN | S12345678A |
0196 | 🇮🇸 Iceland | Kennitala | 1234567890 |
0198 | 🇩🇰 Denmark | ERSTORG | 12345678 |
0200 | 🇱🇹 Lithuania | Company Code | 123456789 |
0201 | 🇱🇹 Lithuania | VAT | LT123456789 |
0204 | 🇩🇪 Germany | VAT | DE123456789 |
0208 | 🇧🇪 Belgium | Enterprise Number | 0123456789 |
0209 | 🇩🇪 Germany | Leitweg-ID | 991-12345-67 |
0210 | 🇮🇹 Italy | Codice Fiscale | 12345678901 |
0211 | 🇮🇹 Italy | IPA Code | ABC123 |
0213 | 🇪🇪 Estonia | Registry Code | 12345678 |
0215 | 🇫🇮 Finland | Y-tunnus | 1234567-8 |
0216 | 🇫🇮 Finland | OVT | 003712345678 |
0221 | 🇯🇵 Japan | Corporate Number | 1234567890123 |
0230 | 🇲🇾 Malaysia | BRN | 202301012345 |
VAT-based Schemes
| Scheme | Country | Format |
|---|---|---|
9906 | 🇮🇹 Italy | IT + 11 digits |
9914 | 🇦🇹 Austria | ATU + 8 digits |
9917 | 🇳🇱 Netherlands | NL + 9 digits + B + 2 digits |
9918 | 🇪🇪 Estonia | EE + 9 digits |
9919 | 🇪🇸 Spain | ESX + 8 digits |
9920 | 🇦🇹 Austria | AT + 9 digits |
9922 | 🇦🇩 Andorra | AD + 8 digits |
9923 | 🇦🇱 Albania | AL + 10 digits |
9924 | 🇧🇦 Bosnia | BA + 12 digits |
9925 | 🇫🇷 France | FR + 11 digits (SIRET) |
9926 | 🇭🇺 Hungary | HU + 8 digits |
9930 | 🇮🇹 Italy | IT + Partita IVA |
9955 | 🇸🇪 Sweden | SE + 12 digits |
9956 | 🇧🇪 Belgium | BE + 10 digits |
9957 | 🇫🇷 France | FR + 11 digits |
9959 | 🇪🇺 EU | Employer ID Number |
Validating Identifiers
GoRoute validates identifiers before accepting documents:
import requests
# Validate a participant identifier
response = requests.get(
"https://app.goroute.ai/peppol-api/api/v1/validate/participant",
params={
"scheme": "0106",
"identifier": "12345678"
},
headers={
"X-API-Key": "your_api_key"
}
)
result = response.json()
print(f"Valid: {result['valid']}")
print(f"Format: {result['format_description']}")
Looking Up Participants
Check if a participant is registered on Peppol:
import requests
# Lookup participant on the Peppol network
response = requests.get(
"https://app.goroute.ai/peppol-api/api/v1/participants/lookup",
params={
"scheme": "0106",
"identifier": "12345678"
},
headers={
"X-API-Key": "your_api_key"
}
)
if response.status_code == 200:
participant = response.json()
print(f"Participant found: {participant['name']}")
print(f"Document types: {participant['document_types']}")
else:
print("Participant not found on Peppol network")
Identifier Requirements
Format Rules
Each scheme has specific format requirements:
| Scheme | Length | Format | Check Digit |
|---|---|---|---|
0106 | 8 | Numeric only | No |
0192 | 9 | Numeric only | Modulo 11 |
0204 | 11 | DE + 9 digits | Yes |
0208 | 10 | Numeric only | Modulo 97 |
Common Validation Errors
Common Mistakes
- Including country prefix when not required (e.g.,
NLin KVK numbers) - Omitting country prefix when required (e.g.,
DEin German VAT) - Wrong number of digits
- Including spaces or special characters
Best Practices
1. Validate Early
Always validate identifiers before storing:
def validate_peppol_id(scheme: str, identifier: str) -> bool:
"""Validate a Peppol identifier format."""
response = requests.get(
f"{API_BASE}/validate/participant",
params={"scheme": scheme, "identifier": identifier},
headers={"X-API-Key": API_KEY}
)
return response.json().get("valid", False)
2. Normalize Before Storage
Store identifiers in a consistent format:
def normalize_identifier(scheme: str, identifier: str) -> str:
"""Normalize identifier for storage."""
# Remove spaces and convert to uppercase
identifier = identifier.replace(" ", "").upper()
# Remove common separators
identifier = identifier.replace("-", "").replace(".", "")
return identifier
3. Use the Correct Scheme
Different schemes may cover the same organization:
# A Dutch company might be registered with:
# - 0106 (KVK number) - Preferred for Peppol
# - 0190 (OIN) - Government organizations
# - 9917 (VAT) - VAT number scheme
# Always check which scheme the receiver is registered with
Scheme Selection Guide
When should you use which scheme?
| Country | B2B | B2G | Recommended |
|---|---|---|---|
| 🇳🇱 Netherlands | 0106 | 0190 | 0106 (KVK) |
| 🇩🇪 Germany | 0204 | 0209 | 0204 (VAT) |
| 🇧🇪 Belgium | 0208 | 0208 | 0208 (CBE) |
| 🇫🇷 France | 9925 | 0009 | 9925 (SIRET) |
| 🇮🇹 Italy | 0210 | 0211 | 0210 (Codice Fiscale) |
| 🇳🇴 Norway | 0192 | 0192 | 0192 (Org.nr) |
| 🇸🇪 Sweden | 0007 | 0007 | 0007 (Org.nr) |
API Reference
Validate Identifier
GET /api/v1/validate/participant
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
scheme | string | Yes | The scheme code |
identifier | string | Yes | The participant identifier |
Response:
{
"valid": true,
"scheme": "0106",
"identifier": "12345678",
"scheme_name": "KVK",
"country": "NL",
"format_description": "8-digit Dutch Chamber of Commerce number"
}
Lookup Participant
GET /api/v1/participants/lookup
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
scheme | string | Yes | The scheme code |
identifier | string | Yes | The participant identifier |
Response:
{
"found": true,
"participant": {
"scheme": "0106",
"identifier": "12345678",
"name": "Example BV",
"country": "NL",
"registered_at": "2024-01-15T10:30:00Z",
"document_types": [
"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2",
"urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2"
]
}
}