Cómo generar una factura Peppol conforme con n8n y SealDoc
Generar una factura Peppol conforme implica más partes móviles de lo que parece. Necesitas un documento CII XML válido, el perfil EN 16931 correcto, un contenedor PDF/A-3, un adjunto XML incrustado y, preferiblemente, un sello de tiempo RFC 3161 antes de que entre en tu archivo. Hacer todo eso desde cero en una integración personalizada supone semanas de trabajo.
Este tutorial muestra cómo ensamblar el mismo resultado en n8n en aproximadamente 30 minutos, usando el nodo de comunidad n8n-nodes-sealdoc. Sin código personalizado. El flujo cubre la generación de facturas, el sondeo de trabajos y el almacenamiento de resultados.
Requisitos previos
Antes de empezar, necesitas:
- Una instancia n8n que ejecute la versión 1.0 o posterior, ya sea autoalojada o n8n Cloud. El nodo de comunidad funciona en ambas.
- Una cuenta SealDoc en el plan Starter o superior. Las funciones de generación de facturas y sellado de tiempo están disponibles desde Starter.
- Una clave API de SealDoc. Genera una en el panel de SealDoc, en Configuración y luego Claves API. Cópiala inmediatamente; solo se muestra una vez.
Instala el nodo de comunidad en tu instancia n8n:
npm i n8n-nodes-sealdoc
Reinicia n8n después de la instalación. Ahora verás el nodo SealDoc disponible en el panel de nodos bajo la categoría Community.
Qué hace el flujo
Este flujo toma datos de factura (vendedor, comprador, partidas, importes) y produce un PDF/A-3 Factur-X completamente conforme con CII XML incrustado. Los pasos son:
- Un disparador proporciona los datos de la factura como JSON (desde un webhook, una consulta de base de datos, un envío de formulario o cualquier otra fuente de n8n).
- El nodo SealDoc Invoice.Generate envía los datos estructurados a la API de SealDoc y devuelve un ID de trabajo.
- El nodo SealDoc Job.Get sondea hasta que el trabajo se completa y devuelve una URL de descarga para el documento generado.
- Un nodo final almacena el resultado en la ubicación de archivo de tu elección.
Paso 1: configurar el disparador
Crea un nuevo flujo. Añade un nodo disparador Webhook. Establece el método HTTP en POST. Esto te da una URL que puedes llamar con datos de factura desde cualquier sistema que pueda hacer una solicitud HTTP.
Para las pruebas, también puedes usar un disparador Execute Workflow o un Manual Trigger con datos estáticos. Lo importante es que el disparador produzca un objeto JSON con los campos de tu factura. Haremos referencia a esos campos en el siguiente paso.
Un ejemplo mínimo de los datos de factura que tu disparador debe proporcionar:
{
"invoiceNumber": "INV-2026-00042",
"issueDate": "2026-05-06",
"dueDate": "2026-06-05",
"seller": {
"name": "Acme BV",
"vatNumber": "NL123456789B01",
"address": "Herengracht 1, 1000 AA Amsterdam, NL",
"iban": "NL91ABNA0417164300"
},
"buyer": {
"name": "Widget GmbH",
"vatNumber": "DE987654321",
"address": "Hauptstrasse 10, 10115 Berlin, DE"
},
"lines": [
{
"description": "Consulting services May 2026",
"quantity": 10,
"unitPrice": 150.00,
"vatRate": 21
}
],
"currency": "EUR"
}
Paso 2: añadir el nodo Invoice.Generate
Añade un nodo SealDoc al lienzo. Configura:
- Recurso: Invoice
- Operación: Generate
- Perfil: EN 16931 (usa EXTENDED si tu comprador o mandato requiere campos adicionales)
- Incrustar sello de tiempo: ACTIVADO (adjunta un sello de tiempo RFC 3161 al documento de salida)
- Datos de entrada: mapea desde la salida del disparador usando expresiones n8n, por ejemplo
{{ $json.invoiceNumber }}para el número de factura,{{ $json.seller.vatNumber }}para el número de IVA del vendedor, y así sucesivamente para cada campo.
En la sección Credenciales, selecciona o crea una credencial API de SealDoc. Pega tu clave API en el campo Secreto.
Haz clic en Ejecutar nodo para probar. Si la clave API es válida y los datos de la factura están completos, recibirás una respuesta como:
{
"jobId": "job_9kxQr2mPLv",
"status": "pending",
"estimatedSeconds": 4
}
El trabajo ha sido encolado. La API de SealDoc lo procesa de forma asíncrona para que un renderizado PDF lento no bloquee la ejecución de tu flujo.
Paso 3: añadir el nodo Job.Get con sondeo
Añade un segundo nodo SealDoc. Configura:
- Recurso: Job
- Operación: Get
- ID de trabajo:
{{ $node["SealDoc Invoice Generate"].json.jobId }}
Envuelve este nodo en el nodo Wait de n8n configurado con un intervalo de 3 segundos, con un bucle de retorno que comprueba si status es igual a completed o failed. La mayoría de las facturas se completan en menos de 5 segundos. Establece el recuento máximo de iteraciones en 10 para evitar un bucle infinito en un trabajo genuinamente bloqueado.
Cuando status es completed, la respuesta de Job.Get incluye:
downloadUrl: una URL con límite de tiempo (válida durante 10 minutos) que apunta al documento PDF/A-3 generado.evidencePackUrl: un archivo ZIP que contiene las entradas originales, el PDF/A-3 de salida, el XML Factur-X incrustado, el token de sello de tiempo RFC 3161 y un fichero de hash manifiesto. Esto es lo que entregas a un auditor.facturXProfile: el perfil realmente utilizado (confirma EN 16931 o EXTENDED).timestampedAt: el sello de tiempo UTC del token RFC 3161, que es la hora de creación legalmente significativa.
Si status es failed, comprueba el campo failureReason. Los valores comunes son validation_failed (faltaba un campo obligatorio en tu entrada), unsupported_currency (SealDoc admite EUR, USD, GBP, CHF, PLN, CZK y una lista creciente) y quota_exceeded (se ha alcanzado tu límite mensual de trabajos).
Paso 4: almacenar el resultado
Añade el nodo de almacenamiento que se adapte a tu infraestructura. Opciones comunes:
- Nodo HTTP Request para hacer un PUT del fichero a tu propio sistema de gestión documental o bucket de MinIO.
- Nodo Google Drive o Dropbox si usas almacenamiento en la nube para tu archivo.
- Nodo FTP/SFTP para almacenamiento local.
- Move Binary Data más Write Binary File si n8n está autoalojado y quieres escribir directamente en una ruta del sistema de ficheros.
Usa el downloadUrl de la respuesta de Job.Get para obtener el fichero binario y luego pásalo a tu nodo de almacenamiento. Almacena también el evidencePackUrl por separado si tu política de retención lo requiere, lo que debería ser así para facturas por encima de un cierto valor o en sectores regulados.
Qué obtienes en la salida
El fichero generado es un documento PDF/A-3B. Abriéndolo en cualquier visor de PDF se muestra una factura renderizada. El adjunto incrustado factur-x.xml contiene el XML CII completo, legible por el software de contabilidad que admite la importación de Factur-X o ZUGFeRD. El sello de tiempo RFC 3161 está incrustado en el diccionario de información del documento PDF y es verificable de forma independiente.
Si ejecutas la salida a través de un validador (nuestra herramienta de validación gratuita acepta el fichero directamente), verás un resultado verde para la conformidad PDF/A-3B, la validez del esquema EN 16931 y la presencia del adjunto Factur-X.
Próximos pasos
Este tutorial cubre el flujo de generación principal. La API de SealDoc también admite:
- Búsqueda Peppol: antes de generar una factura, comprueba si el comprador es accesible en Peppol a través del recurso Peppol en el nodo SealDoc.
- Solo validación: envía un fichero Factur-X o XRechnung existente para la validación de esquema sin generar un nuevo documento.
- Generación por lotes: envía múltiples cargas útiles de facturas en una única llamada a la API para escenarios de alto volumen.
La documentación completa de la API está en nuestra página de desarrolladores, con la especificación OpenAPI y ejemplos curl listos para copiar y pegar para cada endpoint.