Onboarding a business
From nothing to a business that can send and receive on Peppol.
Four steps. The first three are always yours; the fourth depends on whether the business will talk to us directly.
- Create the company — the business as a legal entity.
- Register its participant — the Peppol address others will send to.
- Declare its capabilities — which document types it sends and receives.
- Issue credentials, if it is going to connect itself.
1. Create the company
curl -sS -X POST https://api.businessgateway.se/v1/companies \
-H "X-API-Key: $KEY" -H 'Content-Type: application/json' \
-d '{
"name": "Kinnefrukt AB",
"identifier": "kinnefrukt",
"countryCode": "SE",
"registrationNumber": "5561234567"
}'Only name is required. countryCode falls back to your account's, and identifier is derived from the name when you leave it out.
Set identifier deliberately anyway. It is the customer-facing name of the company: it names the SFTP directory, it can appear in file names, and it shows up in lists. It must be unique under your account and safe in a file path, and changing it later moves directories your customer may already be writing into.
The response carries the company's id. Keep it — it is the companyId every later call uses.
Company verification (KYC)
Before a business's Peppol address goes live, we need to know that the people asking for it actually represent the business. That check is done by the business itself, not by you: your API key cannot do it (403 KYC_USE_ONBOARDING_LINK), and it does not need to.
When your account is expected to verify its companies, the create response carries a hosted onboarding link next to the company:
{
"company": { "id": "…", "name": "Kinnefrukt AB", … },
"onboarding": { "url": "https://…", "expiresAt": "…" }
}Hand that link to the business. On the page behind it, someone from the company uploads the official register extract — for a Swedish company, the registreringsbevis from Bolagsverket, as the sealed PDF and no older than 90 days — or enters the details of a company from elsewhere, and chooses who signs the agreement. The signatories get their own links by email. No account with us is needed for any of it.
The link is valid for 30 days. POST /v1/companies/{id}/kyc/onboarding-link issues a fresh one and ends the old one — use it when a link expired or went to the wrong person.
GET /v1/companies/{id}/kyc shows how far it has got. status is NOT_STARTED, PENDING_SIGNATURES, MANUAL_REVIEW, VERIFIED, REJECTED, EXPIRED or WITHDRAWN; companyVerified is the part that matters for the next step. When required is false your account is exempt, and verification is optional.
What it changes. Participants under a company that has not completed verification wait at PENDING_APPROVAL for us to approve them by hand. Once a Swedish company is verified, its participant with scheme 0007 and the verified organisation number is approved automatically — including one you registered before verification finished, so the order of the two steps does not matter. A verified company's registration number and country can no longer be changed over the API (409 KYC_LOCKED).
Sandbox companies
To try the whole flow without touching the network, create the company with "sandbox": true. A sandbox company:
- gets no onboarding link and needs no verification;
- has participants that are created
READYstraight away, but are local only — never published on Peppol, and refused if they try to send onto it (400 PEPPOL_LOCAL_PARTICIPANT); - can be sent simulated inbound documents with
POST /v1/companies/{id}/test-inbound, which run the real receiving path — see Trying it in a sandbox.
Only we can change the flag afterwards, so a sandbox cannot quietly become a live company. Leave sandbox documents out of lists with sandbox=exclude on GET /v1/messages.
2. Register the Peppol address
A participant is an address on the network, written scheme:value. Swedish organisation numbers are scheme 0007; Norwegian are 0192; GLN is 0088.
curl -sS -X POST https://api.businessgateway.se/v1/participants \
-H "X-API-Key: $KEY" -H 'Content-Type: application/json' \
-d '{
"companyId": "'"$COMPANY_ID"'",
"scheme": "0007",
"value": "5561234567",
"name": "Kinnefrukt AB",
"identifier": "kinnefrukt",
"capabilities": [
{"documentTypeId": "invoice", "direction": "BOTH"}
]
}'countryCode is derived from the scheme where the scheme implies one, and only needs supplying for schemes that do not — GLN and DUNS among them. identifier is the participant's filesystem-safe name, unique within the company, used the same way the company's is.
Passing capabilities here creates them in the same transaction as the participant; you can also add them afterwards (step 3).
Registration is not instant
A new participant starts at PENDING_APPROVAL and has to be approved before anything is published to the network — automatically when its company has completed verification, otherwise by us. After approval it moves through REGISTERING — where its address is published to the SMP so other access points can find it — and only then reaches ACTIVE.
| Status | Meaning |
|---|---|
PENDING_APPROVAL | Created, waiting for approval |
READY | Approved, not yet published |
REGISTERING | Being published to the SMP |
ACTIVE | Reachable on the network |
SUSPENDED | Temporarily not exchanging |
DEACTIVATING / DEACTIVATED | Being withdrawn, or withdrawn |
REJECTED | Not approved |
ERROR | Registration failed; it stays here until it is looked at |
Poll GET /v1/participants/{id}, or subscribe to the participant events on the stream. Do not build an onboarding flow that assumes a participant is usable the moment you create it — sending from one that is not READY or ACTIVE is refused.
If the business already exchanges Peppol documents through another provider, its address belongs to that provider today and cannot simply be registered here — it has to be migrated, which needs a token from the current provider. Start that conversation before you promise the customer a date.
3. Declare capabilities
A capability says "this participant handles this document type, in this direction". It is what the network reads to decide whether the business can be sent an invoice, and what we check before accepting a submission.
curl -sS -X POST "https://api.businessgateway.se/v1/participants/$PARTICIPANT_ID/capabilities" \
-H "X-API-Key: $KEY" -H 'Content-Type: application/json' \
-d '{"documentTypeId": "invoice", "direction": "BOTH"}'direction is SEND, RECEIVE or BOTH. Adding SEND where RECEIVE already exists merges to BOTH rather than creating a second row.
documentTypeId takes a short alias — see Document types — or a full Peppol document type identifier with its processId.
Getting this wrong is the most common reason a document that should have worked does not. A business that can receive invoices but has no RECEIVE capability for credit notes will have credit notes rejected by the sending side before they ever reach us.
The Peppol Directory business card
Every participant gets an entry in the Peppol Directory — the public search other businesses use to find a trading partner's address. Until you set one, the card is built from the company's name and country (custom: false).
curl -sS -X PUT "https://api.businessgateway.se/v1/participants/$PARTICIPANT_ID/business-card" \
-H "X-API-Key: $KEY" -H 'Content-Type: application/json' \
-d '{
"entities": [{
"names": [{"name": "Kinnefrukt AB"}],
"countryCode": "SE",
"geographicalInformation": "Kinnekulle",
"websites": ["https://kinnefrukt.example"],
"contacts": [{"type": "invoicing", "email": "faktura@kinnefrukt.example"}]
}]
}'PUT replaces the whole card, so a GET response can be edited and sent straight back. It is published while the participant is ACTIVE. DELETE drops the custom card and republishes the default. The field limits are in the API reference.
4. Issue credentials
Skip this if you are going to broker every document yourself. Otherwise, give the business one of the two:
An API key confined to the company
curl -sS -X POST https://api.businessgateway.se/v1/api-keys \
-H "X-API-Key: $KEY" -H 'Content-Type: application/json' \
-d '{
"name": "Kinnefrukt ERP",
"companyId": "'"$COMPANY_ID"'",
"permissions": ["read", "send", "receive"]
}'The key is in the response and is never shown again. permissions is any of read, send, receive, manage; omitted or empty means all four. Leave manage out unless the business should be able to change its own webhooks and participants.
A key with companyId cannot see the rest of your account. Ids from other companies answer 404, not 403, so it cannot enumerate what else exists.
An SFTP login
For businesses whose systems produce files. GET /v1/sftp/connection returns the host, port, host key fingerprint and the directory layout each login sees — hand those to the customer along with the credentials. The SFTP guide is written for them.
What to hand over
Whichever you issue, the business needs:
- The credential itself, transmitted somewhere other than email if you can.
- Its Peppol address, so it can tell its trading partners.
- A link to For businesses — those pages assume exactly this starting point.