Skip to main content

Migrating Access Points

Moving a participant from another Access Point to GoRoute is a change of directory entry, not a transfer of data. A participant can be published in the Peppol directory by only one Access Point at a time, so the order never varies: your current provider removes the entry, then GoRoute publishes a new one pointing at GoRoute's endpoint.

There is no migration API

Earlier revisions of this page described a set of endpoints for requesting a transfer, moving participants in bulk, watching progress, forcing a re-check and retrying a failure. None of them has ever existed, and code written against that page failed on its first request.

Every call below is in the running API today, named with its method and full path.

What actually happens​

Your current Access Point            GoRoute
β”‚ β”‚
β”‚ 1. You create the β”‚
β”‚ participant record ────▢│ (no directory change yet)
β”‚ β”‚
2. You ask them to ──▢ directory β”‚
deregister entry removed β”‚
β”‚ β”‚
β”‚ 3. You confirm the entry β”‚
β”‚ is gone (lookup) β”‚
β”‚ β”‚
β”‚ 4. You register ──────────▢│ directory entry
β”‚ β”‚ recreated for GoRoute
β”‚ β”‚
β”‚ 5. You verify (smp-status) β”‚

The one step GoRoute cannot do for you is step 2. Your current provider controls the directory entry until they remove it.

Step 1 β€” Create the participant record in GoRoute​

POST /api/v1/participants β€” returns 201 Created and requires the participants:manage permission.

This creates a record inside GoRoute. It changes nothing on the Peppol network. What you need from it is the participant's id, a UUID that every later call in this sequence uses.

import requests

BASE_URL = "https://app.goroute.ai/peppol-api"

response = requests.post(
f"{BASE_URL}/api/v1/participants",
headers={"X-API-Key": "your_api_key", "Content-Type": "application/json"},
json={
"scheme": "0106",
"identifier": "12345678",
"display_name": "My Company BV",
"country": "NL",
"contact_email": "invoices@mycompany.nl",
},
)
response.raise_for_status()

participant_id = response.json()["id"] # UUID β€” not the Peppol identifier

A rejected create returns HTTP 400 with an error_code of either DUPLICATE_PARTICIPANT (you already hold this participant) or PARTICIPANT_IDENTITY_INVALID (the identifier does not satisfy the rules for its country, for example a Belgian enterprise number failing its check digit). The two mean different things: retry with a corrected identifier only for the second.

See Registration for the rest of the fields the create call accepts.

Step 2 β€” Ask your current provider to deregister​

Providers handle this differently, and most treat it as a support request rather than a self-service action. Ask them in writing and keep the reply.

Subject: Peppol participant deregistration request

Dear Support,

We are moving our Peppol registration to a new Access Point.

Participant:
- Peppol ID: [scheme]:[identifier]
- Company name: [your company name]

Please deregister this participant from your SMP and confirm when it is done.
Our new Access Point is GoRoute (Peppol seat POP000991), which will publish the
participant once your deregistration is confirmed.

Thank you,
[your name]

Step 3 β€” Confirm the entry has gone​

GET /api/v1/participants/lookup β€” requires the participants:read permission. It takes a single peppol_id in scheme:value form and queries the live Peppol directory, so it is the honest check on whether your old provider has actually removed the entry.

response = requests.get(
f"{BASE_URL}/api/v1/participants/lookup",
params={"peppol_id": "0106:12345678"},
headers={"X-API-Key": "your_api_key"},
)

result = response.json()
print(result["found"]) # False once the old entry is gone
found: false is not proof on its own

The endpoint also answers found: false when the directory query itself fails, so a single negative answer can mean "removed" or "could not tell". Check twice, a few minutes apart, before moving on. A confirmation email from the old provider is better evidence than either answer.

Step 4 β€” Register the participant to GoRoute​

POST /api/v1/participants/{participant_id}/register β€” requires the participants:manage permission. {participant_id} is the UUID from step 1, not the Peppol identifier.

Do not run this until step 3 shows the old entry is gone.

response = requests.post(
f"{BASE_URL}/api/v1/participants/{participant_id}/register",
headers={"X-API-Key": "your_api_key"},
)

result = response.json()
print(result["smp_registered"], result["sml_registered"], result["total_doc_types"])

The request takes no body. You do not choose document types β€” GoRoute derives them from the participant's country. A refusal from the SMP comes back as HTTP 502 with an error_code. SMP Registration documents the response fields and every error code, including the extra step Oman participants need on the Fawtara Portal.

Step 5 β€” Verify​

GET /api/v1/participants/{participant_id}/smp-status β€” note the hyphen; smp-status is one path segment.

status = requests.get(
f"{BASE_URL}/api/v1/participants/{participant_id}/smp-status",
headers={"X-API-Key": "your_api_key"},
).json()

print(status["registered"], status["participant"])

There is no webhook that announces a completed move, and no progress endpoint to poll for one. Poll smp-status instead, and treat registered as the signal.

Moving several participants​

There is no bulk endpoint. Each participant is an independent sequence of the five steps above, so loop over them and handle each failure on its own β€” one participant whose old provider has not yet deregistered should not stop the rest.

Moving away from GoRoute​

POST /api/v1/participants/{participant_id}/deregister β€” a POST, not a DELETE, and it requires the participants:manage permission. Its status is deleted, not_found (already gone, which counts as success) or error_<status>. A refusal leaves the participant published and returns HTTP 502. See SMP Registration.

While the move is happening​

Between your old provider's deregistration and GoRoute's registration, the participant is not in the directory. Documents addressed to it in that window will not be delivered; senders get an error and have to send again.

  • Tell your regular trading partners before you start.
  • Note anything you are expecting to receive, and ask senders to retry afterwards.
  • Keep the window short by doing steps 4 and 5 as soon as step 3 confirms the entry is gone.

After the move​

  • Confirm smp-status reports the participant as registered.
  • Send a test invoice and receive one.
  • Check the document types on the participant record are the set you expected.
  • Point your webhooks at the right endpoint if they were configured elsewhere.
  • Tell trading partners who address you directly that your Access Point has changed.

Next Steps​