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.

From a self-hosted Access Point​

If you run your own Access Point β€” Oxalis, phase4, Domibus, Holodeck B2B or similar β€” and publish your participants on your own SMP, the move follows the same five steps, with two differences: you perform step 2 yourself, and your sending and receiving code changes.

Directory: you deregister yourself​

Step 2 is yours: remove each participant's entry from your SMP and from the SML, the way your SMP software does it. Then confirm with step 3 that the entry is gone before you register it with GoRoute in step 4. Until step 4 completes, nobody can deliver to that participant, so move one participant first and time the rest outside your busiest hours.

Sending: replace the AS4 call with one API call​

Your documents do not change. Where your code built an AS4 message and pushed it to the recipient's Access Point, it now posts the same UBL to POST /api/v1/documents:

  • Send the UBL document itself, without an SBDH envelope β€” GoRoute's Access Point adds the envelope, does the SMP lookup and handles the AS4 exchange, receipts and retries.
  • Pass the receiver as receiver_scheme / receiver_id, and the document_type / process_id you used to send with (the defaults are Peppol BIS 3.0 Invoice and billing).
  • Outcomes arrive as transaction.delivered / transaction.failed webhooks instead of AS4 receipts in your logs.

The rules for documents you build yourself are in Send XML you already generate.

Receiving: webhooks instead of an inbox folder​

Documents addressed to your participants now arrive at GoRoute. Subscribe to transaction.received and fetch each document from the API β€” see Webhook setup and Processing received documents.

What you no longer run​

Once every participant is registered with GoRoute and smp-status confirms it for each, you no longer need your own AS4 endpoint, SMP, Access Point certificate or its yearly renewal, or to track Peppol specification changes in your stack. Keep your old endpoint running for a short overlap so that a message already in flight is not lost.

If you operated your Access Point for other companies and want to keep serving them under your own brand, see For software vendors and resellers and the white-label platform.

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​