Skip to content

Legal Entities API

Provision, list, authorise, and off-board your customers as Peppol legal entities. The multi-tenant surface for platforms.

Every endpoint here requires a master key with the matching legal_entities:* scope. A standard key receives 403. Customers you don't own return 404, never another platform's data.
POST /v1/legal-entities #

Create a customer as a draft Peppol legal entity. getpeppr validates the identifier format (for example, a Luhn check), then kicks off registry verification asynchronously. Returns 202 on creation, or 200 if the same externalId is replayed (the call is idempotent).

Creating the Legal Entity and attaching its Peppol Identifier are separate outcomes. A sandbox create can return 202 while the identifier later settles as verification_failed, not_found, or registration_failed if the identifier is fake, unsupported, already registered elsewhere, or not attachable on the test network. Poll GET /v1/legal-entities/:id or subscribe to legal_entity.* webhooks before treating the customer as send-ready.

Body parameters

NameTypeRequiredDescription
externalIdstringRequiredYour stable reference for this customer (1–64 chars). Echoed on every response and webhook.
companyNamestringRequiredLegal company name (2–64 chars). Matched against the business registry.
countrystringRequiredISO 3166-1 alpha-2 country code (e.g. GB).
address.line1stringRequiredStreet address (2–192 chars).
address.citystringRequiredCity (2–64 chars).
address.zipstringRequiredPostal / ZIP code (2–32 chars).
identifier.schemestringRequiredPeppol identifier scheme (1–16 chars, e.g. GB:CRN, 0208).
identifier.valuestringRequiredThe identifier value (1–64 chars). Format-checked (e.g. Luhn) before verification.
import { Peppol } from "@getpeppr/sdk";

const peppol = new Peppol({ apiKey: "sk_live_your_master_key" });

const customer = await peppol.legalEntities.create({
  externalId: "customer_8412",
  companyName: "Bright Health Ltd",
  country: "GB",
  address: { line1: "10 King Street", city: "London", zip: "EC2V 8EA" },
  identifier: { scheme: "GB:CRN", value: "12345678" },
});

console.log(customer.id, customer.status); // "7c9a1b34-…", "pending"
Response
// 202 Accepted — verification runs asynchronously
{
  "id": "7c9a1b34-2d5e-4f60-8a1b-9c2d3e4f5a6b",
  "externalId": "customer_8412",
  "companyName": "Bright Health Ltd",
  "country": "GB",
  "identifier": { "scheme": "GB:CRN", "value": "12345678" },
  "status": "pending",
  "environment": "production",
  "createdAt": "2026-06-01T10:00:00.000Z"
}

Belgian customers

For Belgian Legal Entities, use scheme 0208 with the 10-digit BCE/KBO enterprise number. If you start from a VAT number such as BE0685660237, drop the BE prefix and send 0208:0685660237. The companyName should be the exact registered legal name for that number. Avoid 9925 for this API flow unless getpeppr support explicitly instructs you to use it. When VAT registration is confirmed during verification, getpeppr also registers the derived BE:VAT identifier on the network automatically — required for sending invoices that carry VAT (see Network identifiers and VAT).

Belgian sandbox customer
curl https://api.getpeppr.dev/v1/legal-entities \
  -H "Authorization: Bearer sk_sandbox_your_master_key" \
  -H "Content-Type: application/json" \
  -d '{
    "externalId": "customer_be_001",
    "companyName": "Exact Registered Legal Name",
    "country": "BE",
    "address": { "line1": "Rue de la Loi 16", "city": "Brussels", "zip": "1000" },
    "identifier": { "scheme": "0208", "value": "0685660237" }
  }'

Swedish customers

For Swedish Legal Entities, use scheme 0007 with the 10-digit organisation number (organisationsnummer). If you start from a VAT number such as SE556036079301, drop the SE prefix and the trailing 01 and send 0007:5560360793. When the derived VAT number is confirmed against VIES, getpeppr also registers the SE:VAT identifier on the network automatically (see Network identifiers and VAT).

GET /v1/legal-entities #

List the customers you manage, newest first. Results are isolated to your platform account. When offset exceeds the total, data is empty and has_more is false.

Query parameters

NameTypeRequiredDescription
limitnumberOptionalMax results (default 50, max 100).
offsetnumberOptionalPagination offset (default 0, max 100000).
import { Peppol } from "@getpeppr/sdk";

const peppol = new Peppol({ apiKey: "sk_live_your_master_key" });

// One page
const page = await peppol.legalEntities.list({ limit: 20, offset: 0 });
console.log(page.data, page.meta.hasMore);

// …or iterate every customer — pagination handled for you
for await (const customer of peppol.legalEntities.listAll()) {
  console.log(customer.externalId, customer.status);
}
Response
{
  "data": [
    {
      "id": "7c9a1b34-2d5e-4f60-8a1b-9c2d3e4f5a6b",
      "externalId": "customer_8412",
      "companyName": "Bright Health Ltd",
      "country": "GB",
      "identifier": { "scheme": "GB:CRN", "value": "12345678" },
      "status": "active",
      "environment": "production",
      "createdAt": "2026-06-01T10:00:00.000Z"
    }
  ],
  "pagination": { "total_count": 42, "offset": 0, "limit": 20, "has_more": true }
}
GET /v1/legal-entities/:id #

Retrieve a single customer by their getpeppr id. On production this surfaces the full attestation lifecycle status (see the status reference); in sandbox it returns the verification status. Unknown or unowned ids return 404.

import { Peppol } from "@getpeppr/sdk";

const peppol = new Peppol({ apiKey: "sk_live_your_master_key" });

const customer = await peppol.legalEntities.get(
  "7c9a1b34-2d5e-4f60-8a1b-9c2d3e4f5a6b",
);
console.log(customer.status); // production: full attestation lifecycle status
DELETE /v1/legal-entities/:id #

Off-board a customer. The legal entity is archived: the customer drops out of active lists and can no longer send, while audit records, attestations, and history are retained for compliance. Returns 200 with the archived entity. You can also archive a customer from the console (Legal Entities → the row's Archive action), which applies the same retention rules — production archives require typing the customer reference to confirm.

import { Peppol } from "@getpeppr/sdk";

const peppol = new Peppol({ apiKey: "sk_live_your_master_key" });

const result = await peppol.legalEntities.archive(
  "7c9a1b34-2d5e-4f60-8a1b-9c2d3e4f5a6b",
);
console.log(result.status); // "archived"
Response
{
  "id": "7c9a1b34-2d5e-4f60-8a1b-9c2d3e4f5a6b",
  "externalId": "customer_8412",
  "status": "archived"
}
POST /v1/legal-entities/:id/attestation #

Request (or resend) the customer's authorisation. getpeppr emails a co-branded, getpeppr-signed attestation link to the contact; once they confirm, the customer advances toward active. Production only — calling this with a sandbox key returns 400.

Body parameters

NameTypeRequiredDescription
contactEmailstringRequiredEmail of the person who will authorise invoicing for this customer (max 254 chars).
contactNamestringOptionalDisplay name shown in the authorisation email (max 128 chars).
Returns 409 if the customer isn't verified yet or has already attested, and 502 if the email couldn't be sent (retry to mint a fresh link). Issuing an attestation emits a legal_entity.awaiting_authz webhook.
import { Peppol } from "@getpeppr/sdk";

const peppol = new Peppol({ apiKey: "sk_live_your_master_key" });

const attestation = await peppol.legalEntities.requestAttestation(
  "7c9a1b34-2d5e-4f60-8a1b-9c2d3e4f5a6b",
  { contactEmail: "owner@brighthealth.co.uk", contactName: "Dr Jane Okafor" },
);
console.log(attestation.status, attestation.expiresAt); // "awaiting_authz", "…"
Response
// 202 Accepted — co-branded email sent to the customer
{
  "id": "7c9a1b34-2d5e-4f60-8a1b-9c2d3e4f5a6b",
  "externalId": "customer_8412",
  "status": "awaiting_authz",
  "expiresAt": "2026-06-08T10:00:00.000Z"
}