← Back to all articles

Cómo funciona realmente el descubrimiento de Peppol SMP y SML

SealDoc Team · · 6 min read

Antes de que una factura Peppol pueda entregarse, el sistema del remitente necesita encontrar el Access Point del receptor. No existe un registro central que puedas consultar directamente. En cambio, Peppol utiliza una cadena de descubrimiento de dos niveles que funciona como DNS.

Comprender esta cadena es esencial si estás construyendo una integración directa con Peppol en lugar de delegar el enrutamiento a un proveedor de Access Point. Aunque uses un proveedor, conocer el mecanismo de descubrimiento ayuda a depurar fallos de entrega.

Los dos componentes

SML (Service Metadata Locator) es la raíz de la cadena. Es un servicio basado en DNS operado por OpenPEPPOL. Su función es indicarte dónde encontrar el SMP de un participante.

SMP (Service Metadata Publisher) es un servicio a nivel de participante. Cada Access Point Peppol ejecuta un SMP para sus participantes registrados. El SMP publica qué tipos de documentos puede recibir un participante y la URL del endpoint donde deben entregarse esos documentos.

El flujo de descubrimiento completo:

  1. Tienes un identificador de participante (por ejemplo, un número de empresa belga)
  2. Lo hash-eas y codificas en un nombre de host DNS
  3. Consultas la zona DNS del SML para encontrar el nombre de host SMP del participante
  4. Consultas el SMP para obtener los metadatos de servicio para el tipo de documento objetivo
  5. Extraes la URL del endpoint y el certificado del receptor
  6. Entregas el mensaje AS4 firmado a ese endpoint

Paso 1: construir la consulta DNS

El identificador de participante de Peppol tiene dos partes: un código de esquema y un valor. Para una empresa belga identificada por su número de empresa:

Scheme: 0208
Value:  0468863455
Full:   iso6523-actorid-upis::0208:0468863455

Para convertirlo en un nombre de host DNS:

  1. Convertir el identificador completo del participante a minúsculas
  2. Calcular el hash MD5
  3. Codificar el hash en Base32 (sin relleno, en minúsculas)
  4. Anteponer b- (el prefijo SML de Peppol)
  5. Añadir el dominio SML: edelivery.tech.ec.europa.eu

En 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";
}

La codificación Base32 es RFC 4648. La biblioteca estándar de .NET no incluye Base32; usa una pequeña utilidad o el paquete NuGet SimpleBase.

Paso 2: la consulta DNS del SML

Consulta el nombre de host como CNAME. La respuesta te da el nombre de host del SMP.

static async Task<string> LookupSmpHostname(string smlHostname)
{
    var result = await Dns.GetHostEntryAsync(smlHostname);
    // The CNAME target is the SMP hostname
    return result.HostName;
}

Si la consulta DNS falla (NXDOMAIN), el participante no está registrado en la red Peppol. Esta es una respuesta definitiva de “no existe tal participante”, no un error transitorio. Regístralo y muéstralo al usuario en lugar de reintentar.

Paso 3: consultar el SMP

La URL del endpoint SMP se construye a partir del nombre de host SMP, el esquema del participante y el valor del participante. La especificación SMP de Peppol (versión 2.0) define la estructura de la URL:

https://{smp-hostname}/{scheme}%3A%3A{value}/services/{doctype}

El separador :: entre el esquema y el valor está codificado en porcentaje. El identificador del tipo de documento también está codificado en porcentaje.

Para una factura Peppol BIS Billing 3.0:

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

Ejemplo de solicitud completa:

GET https://{smp-hostname}/iso6523-actorid-upis%3A%3A0208%3A0468863455/services/urn%3Aoasis%3Anames...

El SMP devuelve un documento XML firmado (los metadatos de servicio). Aquí tienes el aspecto de la respuesta, reducida a las partes relevantes:

<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>

Paso 4: verificar la firma del SMP

La respuesta del SMP está firmada con el certificado del Access Point. Debes verificar esta firma antes de confiar en la URL del endpoint.

Aquí es donde la mayoría de implementaciones tienen problemas. Las respuestas SMP usan firmas digitales XML (XMLDSig). Muchos servidores SMP reserializan el documento firmado al servirlo, lo que cambia las declaraciones de prefijos de espacio de nombres. Esto rompe el resumen de referencia en la firma.

El problema y su solución se tratan en detalle en Errores en la validación de firmas XML en Peppol. En resumen: usa un analizador XML con PreserveWhitespace = true y no reserialices el documento antes de verificar.

Después de la verificación, extrae la URL del endpoint y el certificado:

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 ?? ""));

Paso 5: entrega

Con la URL del endpoint y el certificado en mano, la factura se envuelve en un mensaje AS4 y se entrega por HTTPS. AS4 es el protocolo de transporte de Peppol. Requiere:

  • Firmar el mensaje AS4 con el certificado de tu Access Point
  • Cifrar el payload con el certificado del receptor (de la respuesta SMP)
  • Enviar a la EndpointURI del SMP

La implementación de AS4 está fuera del alcance de este artículo. En la práctica, construir tu propia capa AS4 es un esfuerzo de ingeniería considerable. La mayoría de las organizaciones usan un proveedor de Access Point certificado en lugar de implementar AS4 directamente.

Caché

Las consultas SMP deben almacenarse en caché. El TTL de DNS en la entrada SML es típicamente de 3600 segundos. Los metadatos de servicio del SMP no cambian con frecuencia. Una caché de 24 horas para las respuestas SMP es razonable para la mayoría de los sistemas en producción.

No almacenes en caché los resultados negativos (NXDOMAIN) indefinidamente. Un participante puede registrarse después de tu primera consulta. Almacena en caché los resultados negativos durante 15 a 30 minutos, no días.

Qué puede salir mal

NXDOMAIN del SML: el participante no está registrado. Esto es permanente, no transitorio. No reintentes sin investigación.

El SMP devuelve 404: el participante está registrado en el SML pero no tiene metadatos de servicio para el tipo de documento solicitado. Es posible que el Access Point del receptor no haya configurado soporte para Peppol BIS Billing 3.0.

Fallo de validación de certificado: la firma de la respuesta SMP usa un certificado que no está en la lista de confianza Peppol PKI. Esto debe tratarse como un error de seguridad, no de conectividad. Rechaza la respuesta.

Fallo de firma relacionado con espacios de nombres: consulta Errores en la validación de firmas XML en Peppol.

El endpoint devuelve un fallo SOAP AS4: la factura fue entregada pero rechazada por el Access Point del receptor. El código de fallo indica si el rechazo se debe a una discrepancia de certificado, un tipo de documento no admitido o un fallo de validación del payload.

SealDoc y el descubrimiento SMP

La API REST de SealDoc realiza internamente la cadena completa de descubrimiento SMP. Cuando envías una solicitud de generación de factura con un ID de participante Peppol, la API resuelve el endpoint, valida la cadena y enruta el documento. Si el descubrimiento falla, la API devuelve un error estructurado indicando qué paso falló. No necesitas implementar la consulta SML o SMP por tu cuenta.

Para participantes que necesiten realizar consultas contra la red Peppol para pruebas o auditorías, el validador público de SealDoc puede verificar si una factura Peppol es enrutable a un participante específico antes de comprometerse con la entrega.


← Back to all articles