Participant Registration
Register your organization or your customers as Peppol participants to send and receive documents.
Registration Overviewโ
Registration involves three steps:
1. Create Participant โ 2. Configure Capabilities โ 3. Publish to SMP
Create a Participantโ
Basic Registrationโ
import requests
def register_participant(
scheme: str,
identifier: str,
name: str,
country: str,
email: str
) -> dict:
"""Register a new Peppol participant."""
response = requests.post(
"https://app.goroute.ai/peppol-api/api/v1/participants",
headers={
"X-API-Key": "your_api_key",
"Content-Type": "application/json"
},
json={
"scheme": scheme,
"identifier": identifier,
"name": name,
"country": country,
"contact_email": email,
"auto_register_smp": True
}
)
response.raise_for_status()
return response.json()
# Register a Dutch company
participant = register_participant(
scheme="0106",
identifier="12345678",
name="My Company BV",
country="NL",
email="invoices@mycompany.nl"
)
print(f"Participant ID: {participant['id']}")
print(f"Peppol ID: {participant['scheme']}:{participant['identifier']}")
Responseโ
{
"id": "part_abc123",
"scheme": "0106",
"identifier": "12345678",
"name": "My Company BV",
"country": "NL",
"contact_email": "invoices@mycompany.nl",
"status": "active",
"smp_status": "registered",
"capabilities": [
{
"document_type": "Invoice",
"process_id": "urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"
},
{
"document_type": "CreditNote",
"process_id": "urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"
}
],
"created_at": "2024-01-15T10:30:00Z",
"registered_at": "2024-01-15T10:30:45Z"
}
Registration Optionsโ
Full Registration Requestโ
participant_data = {
# Required fields
"scheme": "0106",
"identifier": "12345678",
"name": "My Company BV",
"country": "NL",
# Contact information
"contact_email": "invoices@mycompany.nl",
"contact_phone": "+31 20 123 4567",
"technical_contact_email": "it@mycompany.nl",
# Address
"address": {
"street": "Main Street 123",
"city": "Amsterdam",
"postal_code": "1012AB",
"country": "NL"
},
# Registration options
"auto_register_smp": True,
"environment": "production", # or "test"
# Document capabilities
"capabilities": [
{
"document_type": "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2",
"process_id": "urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"
},
{
"document_type": "urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2",
"process_id": "urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"
}
],
# Webhook for incoming documents
"webhook_url": "https://your-app.com/webhooks/peppol",
# Metadata
"metadata": {
"internal_id": "CUST-12345",
"erp_code": "NL-001"
}
}
Choosing the Right Identifierโ
By Countryโ
| Country | Preferred Scheme | Format |
|---|---|---|
| ๐ณ๐ฑ Netherlands | 0106 | 8 digits (KVK) |
| ๐ง๐ช Belgium | 0208 | 10 digits (CBE) |
| ๐ฉ๐ช Germany | 0204 | DE + 9 digits (VAT) |
| ๐ซ๐ท France | 9925 | 14 digits (SIRET) |
| ๐ฎ๐น Italy | 0210 | 11-16 chars (Codice Fiscale) |
| ๐ณ๐ด Norway | 0192 | 9 digits (Org.nr) |
| ๐ธ๐ช Sweden | 0007 | 10 digits (Org.nr) |
| ๐ธ๐ฌ Singapore | 0195 | UEN format |
Validationโ
There is no identifier-validation endpoint
Earlier revisions of this page documented a POST route under /api/v1 that validated a
scheme and identifier before registration and returned valid, scheme_name and an
error. No such endpoint exists.
Check the format yourself against the table above before you register. To find out whether
an identifier already resolves on the Peppol network, use
GET /api/v1/participants/lookup with a single peppol_id in scheme:value form:
import requests
response = requests.get(
"https://app.goroute.ai/peppol-api/api/v1/participants/lookup",
params={"peppol_id": "0106:12345678"},
headers={"X-API-Key": "your_api_key"},
)
result = response.json()
if result["found"]:
print("Already registered on Peppol:", result["name"])
else:
print("Not on the network:", result["message"])
See Identifiers for the full lookup reference.
Configure Capabilitiesโ
Add Document Typesโ
def add_capability(participant_id: str, document_type: str, process_id: str):
"""Add a document capability to a participant."""
response = requests.post(
f"https://app.goroute.ai/peppol-api/api/v1/participants/{participant_id}/capabilities",
headers={
"X-API-Key": "your_api_key",
"Content-Type": "application/json"
},
json={
"document_type": document_type,
"process_id": process_id
}
)
return response.json()
# Add order capability
add_capability(
"part_abc123",
document_type="urn:oasis:names:specification:ubl:schema:xsd:Order-2",
process_id="urn:fdc:peppol.eu:2017:poacc:ordering:01:1.0"
)
Standard Capability Setsโ
# Billing only (invoices and credit notes)
BILLING_CAPABILITIES = [
{
"document_type": "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2",
"process_id": "urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"
},
{
"document_type": "urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2",
"process_id": "urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"
}
]
# Full procurement
FULL_CAPABILITIES = BILLING_CAPABILITIES + [
{
"document_type": "urn:oasis:names:specification:ubl:schema:xsd:Order-2",
"process_id": "urn:fdc:peppol.eu:2017:poacc:ordering:01:1.0"
},
{
"document_type": "urn:oasis:names:specification:ubl:schema:xsd:OrderResponse-2",
"process_id": "urn:fdc:peppol.eu:2017:poacc:ordering:01:1.0"
},
{
"document_type": "urn:oasis:names:specification:ubl:schema:xsd:DespatchAdvice-2",
"process_id": "urn:fdc:peppol.eu:2017:poacc:despatch_advice:01:1.0"
}
]
Multi-Tenant Registrationโ
For platforms managing multiple participants:
class ParticipantManager:
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = "https://app.goroute.ai/peppol-api"
def register_customer(
self,
scheme: str,
identifier: str,
name: str,
country: str,
email: str,
internal_id: str
) -> dict:
"""Register a customer as a Peppol participant."""
# Check if already registered
existing = self.find_participant(scheme, identifier)
if existing:
return existing
# Register new participant
response = requests.post(
f"{self.base_url}/api/v1/participants",
headers={
"X-API-Key": self.api_key,
"Content-Type": "application/json"
},
json={
"scheme": scheme,
"identifier": identifier,
"name": name,
"country": country,
"contact_email": email,
"auto_register_smp": True,
"capabilities": BILLING_CAPABILITIES,
"metadata": {
"internal_id": internal_id
}
}
)
response.raise_for_status()
return response.json()
def find_participant(self, scheme: str, identifier: str) -> dict:
"""Find an existing participant."""
response = requests.get(
f"{self.base_url}/api/v1/participants",
params={"scheme": scheme, "identifier": identifier},
headers={"X-API-Key": self.api_key}
)
if response.status_code == 200:
items = response.json().get("items", [])
return items[0] if items else None
return None
# Usage
manager = ParticipantManager("your_api_key")
# Register customers
for customer in customers:
participant = manager.register_customer(
scheme=customer.peppol_scheme,
identifier=customer.peppol_id,
name=customer.company_name,
country=customer.country_code,
email=customer.email,
internal_id=customer.id
)
print(f"Registered: {participant['scheme']}:{participant['identifier']}")
Registration Statusโ
Check Statusโ
def get_participant(participant_id: str) -> dict:
"""Get participant details and status."""
response = requests.get(
f"https://app.goroute.ai/peppol-api/api/v1/participants/{participant_id}",
headers={"X-API-Key": "your_api_key"}
)
return response.json()
participant = get_participant("part_abc123")
print(f"Status: {participant['status']}")
print(f"SMP Status: {participant['smp_status']}")
Status Valuesโ
| Status | Description |
|---|---|
pending | Registration in progress |
active | Fully registered and active |
suspended | Temporarily disabled |
deregistered | Removed from Peppol network |
| SMP Status | Description |
|---|---|
pending | SMP registration in progress |
registered | Visible on Peppol network |
failed | SMP registration failed |
deregistered | Removed from SMP |
Error Handlingโ
Common Registration Errorsโ
try:
participant = register_participant(...)
except requests.HTTPError as e:
error = e.response.json()
if error["code"] == "IDENTIFIER_IN_USE":
print("This identifier is already registered with another Access Point")
# Contact the other AP for migration
elif error["code"] == "INVALID_IDENTIFIER":
print(f"Invalid identifier format: {error['message']}")
elif error["code"] == "DUPLICATE_PARTICIPANT":
print("This participant already exists in your organization")
# Return existing participant instead