Hoe Peppol SMP- en SML-discovery werkelijk werkt
Voordat een Peppol-factuur kan worden bezorgd, moet het systeem van de verzender het Access Point van de ontvanger vinden. Er is geen centraal register dat je rechtstreeks kunt bevragen. In plaats daarvan gebruikt Peppol een tweelaagse discoveryketen die werkt als DNS.
Inzicht in deze keten is essentieel als je een directe Peppol-integratie bouwt in plaats van routering te delegeren aan een Access Point-provider. Zelfs als je een provider gebruikt, helpt kennis van het discoverymechanisme bij het debuggen van bezorgingsfouten.
De twee onderdelen
SML (Service Metadata Locator) is de basis van de keten. Het is een op DNS gebaseerde dienst beheerd door OpenPEPPOL. Zijn taak is je te vertellen waar je de SMP van een deelnemer kunt vinden.
SMP (Service Metadata Publisher) is een service op deelnemersniveau. Elk Peppol Access Point beheert een SMP voor zijn geregistreerde deelnemers. De SMP publiceert welke documenttypen een deelnemer kan ontvangen en de endpoint-URL waar die documenten moeten worden bezorgd.
De volledige discoveryflow:
- Je hebt een deelnemersidentificator (bijvoorbeeld een Belgisch ondernemingsnummer)
- Hash het en codeer het in een DNS-hostnaam
- Bevraag de SML-DNS-zone om de SMP-hostnaam van de deelnemer te vinden
- Bevraag de SMP om de servicemetadata voor het doeldocumenttype op te halen
- Extraheer de endpoint-URL en het certificaat van de ontvanger
- Bezorg het ondertekende AS4-bericht bij dat endpoint
Stap 1: de DNS-opzoeking samenstellen
De Peppol-deelnemersidentificator heeft twee delen: een schemacode en een waarde. Voor een Belgisch bedrijf geidentificeerd via zijn ondernemingsnummer:
Schema: 0208
Waarde: 0468863455
Volledig: iso6523-actorid-upis::0208:0468863455
Om dit om te zetten in een DNS-hostnaam:
- Zet de volledige deelnemersidentificator naar kleine letters
- Bereken de MD5-hash
- Codeer de hash in Base32 (geen opvulling, kleine letters)
- Voeg
b-toe als prefix (het Peppol SML-prefix) - Voeg het SML-domein toe:
edelivery.tech.ec.europa.eu
In C#:
static string BuildSmlHostname(string participantId)
{
var lower = participantId.ToLowerInvariant();
var hash = MD5.HashData(Encoding.UTF8.GetBytes(lower));
var b32 = Base32.ToBase32String(hash).ToLowerInvariant().TrimEnd('=');
return $"b-{b32}.iso6523-actorid-upis.edelivery.tech.ec.europa.eu";
}
Base32-codering is RFC 4648. De .NET-standaardbibliotheek bevat geen Base32; gebruik een kleine hulpklasse of het SimpleBase NuGet-pakket.
Stap 2: de SML-DNS-query
Bevraag de hostnaam als CNAME. De reactie geeft je de SMP-hostnaam.
static async Task<string> LookupSmpHostname(string smlHostname)
{
var result = await Dns.GetHostEntryAsync(smlHostname);
return result.HostName;
}
Als de DNS-query mislukt (NXDOMAIN), is de deelnemer niet geregistreerd in het Peppol-netwerk. Dit is een definitief “geen deelnemer gevonden”-antwoord, geen tijdelijke fout. Log het en toon het aan de gebruiker in plaats van het opnieuw te proberen.
Stap 3: de SMP bevragen
De SMP-endpoint-URL wordt samengesteld uit de SMP-hostnaam, het deelnemerschema en de deelnemerswaarde. De Peppol SMP-specificatie (versie 2.0) definieert de URL-structuur:
https://{smp-hostnaam}/{schema}%3A%3A{waarde}/services/{doctype}
De :: scheidingsteken tussen schema en waarde is procentgecodeerd. De documenttype-identificator is ook procentgecodeerd.
Voor een Peppol BIS Billing 3.0-factuur:
doctype: urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1
Volledig voorbeeldverzoek:
GET https://{smp-hostnaam}/iso6523-actorid-upis%3A%3A0208%3A0468863455/services/urn%3Aoasis%3Anames...
De SMP retourneert een ondertekend XML-document (de servicemetadata). Hier ziet de reactie eruit, teruggebracht tot de relevante delen:
<ServiceMetadata>
<ServiceInformation>
<ParticipantIdentifier scheme="iso6523-actorid-upis">0208:0468863455</ParticipantIdentifier>
<DocumentIdentifier>urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::...</DocumentIdentifier>
<ProcessList>
<Process>
<ProcessIdentifier scheme="cenbii-procid-ubl">urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</ProcessIdentifier>
<ServiceEndpointList>
<Endpoint transportProfile="peppol-as4-2.0">
<EndpointURI>https://ap.example.com/as4</EndpointURI>
<Certificate>MIIBxTCCA...</Certificate>
</Endpoint>
</ServiceEndpointList>
</Process>
</ProcessList>
</ServiceInformation>
<Signature>...</Signature>
</ServiceMetadata>
Stap 4: de SMP-handtekening verifiëren
De SMP-reactie is ondertekend met het certificaat van het Access Point. Je moet deze handtekening verifiëren voordat je de endpoint-URL vertrouwt.
Hier lopen de meeste implementaties op vast. SMP-reacties gebruiken XML-digitale handtekeningen (XMLDSig). Veel SMP-servers herserializeren het ondertekende document bij bezorging, waardoor naamruimte-prefixdeclaraties worden gewijzigd. Dit breekt de referentiedigest in de handtekening.
Het probleem en de oplossing worden uitgebreid behandeld in Valkuilen bij XML-handtekeningvalidatie in Peppol. De korte versie: gebruik een XML-parser met PreserveWhitespace = true en herserializeer het document niet voor verificatie.
Na verificatie haal je de endpoint-URL en het certificaat op:
var ns = new XmlNamespaceManager(doc.NameTable);
ns.AddNamespace("wsa", "http://www.w3.org/2005/08/addressing");
ns.AddNamespace("bdxr", "http://docs.oasis-open.org/bdxr/ns/SMP/2016/05");
var endpointNode = doc.SelectSingleNode(
"//bdxr:Endpoint[@transportProfile='peppol-as4-2.0']/bdxr:EndpointURI", ns);
var certNode = doc.SelectSingleNode(
"//bdxr:Endpoint[@transportProfile='peppol-as4-2.0']/bdxr:Certificate", ns);
var endpointUrl = endpointNode?.InnerText;
var cert = new X509Certificate2(Convert.FromBase64String(certNode?.InnerText ?? ""));
Stap 5: bezorging
Met de endpoint-URL en het certificaat bij de hand wordt de factuur verpakt in een AS4-bericht en bezorgd via HTTPS. AS4 is het Peppol-transportprotocol. Het vereist:
- Het AS4-bericht ondertekenen met het certificaat van je Access Point
- De payload versleutelen met het certificaat van de ontvanger (uit de SMP-reactie)
- Verzenden naar de
EndpointURIuit de SMP
AS4-implementatie valt buiten het bereik van dit artikel. In de praktijk is het bouwen van een eigen AS4-laag een aanzienlijke technische inspanning. De meeste organisaties gebruiken een gecertificeerde Access Point-provider in plaats van AS4 zelf te implementeren.
Caching
SMP-opzoekingen moeten worden gecachet. De DNS-TTL op het SML-item is doorgaans 3600 seconden. De SMP-servicemetadata verandert niet vaak. Een cache van 24 uur op SMP-reacties is redelijk voor de meeste productiesystemen.
Cache geen negatieve resultaten (NXDOMAIN) voor onbepaalde tijd. Een deelnemer kan zich na je eerste opzoeking registreren. Cache negatieve resultaten voor 15 tot 30 minuten, niet voor dagen.
Wat er mis kan gaan
NXDOMAIN van SML: de deelnemer is niet geregistreerd. Dit is permanent, niet tijdelijk. Probeer het niet opnieuw zonder onderzoek.
SMP retourneert 404: de deelnemer is geregistreerd in de SML maar heeft geen servicemetadata voor het gevraagde documenttype. Het Access Point van de ontvanger heeft mogelijk geen ondersteuning geconfigureerd voor Peppol BIS Billing 3.0.
Certificaatvalidatiefout: de SMP-reactiehandtekening gebruikt een certificaat dat niet in de Peppol PKI-vertrouwenslijst staat. Dit moet worden behandeld als een beveiligingsfout, niet als een verbindingsfout. Weiger de reactie.
Naamruimte-gerelateerde handtekeningfout: zie Valkuilen bij XML-handtekeningvalidatie in Peppol.
Endpoint retourneert AS4 SOAP-fout: de factuur is bezorgd maar door het Access Point van de ontvanger afgewezen. De foutcode geeft aan of de afwijzing te wijten is aan certificaatmismatch, niet-ondersteund documenttype of validatiefout van de payload.
SealDoc en SMP-discovery
De REST-API van SealDoc voert de volledige SMP-discoveryketen intern uit. Wanneer je een factuurgeneratieverzoek indient met een Peppol-deelnemer-ID, lost de API het endpoint op, valideert de keten en routeert het document. Als discovery mislukt, retourneert de API een gestructureerde fout die aangeeft welke stap is mislukt. Je hoeft SML- of SMP-opzoeking niet zelf te implementeren.
Voor deelnemers die opzoekingen moeten uitvoeren in het Peppol-netwerk voor testen of auditeren, kan de SealDoc publieke validator verifiëren of een Peppol-factuur routeerbaar is naar een specifieke deelnemer voordat je overgaat tot bezorging.