Come generare una fattura Peppol conforme con n8n e SealDoc
Generare una fattura Peppol conforme comporta più elementi di quanto non sembri. Serve un documento XML CII valido, il profilo EN 16931 corretto, un contenitore PDF/A-3, un allegato XML incorporato e idealmente un timestamp RFC 3161 prima che vada nell’archivio. Fare tutto questo da zero in un’integrazione personalizzata richiede settimane di lavoro.
Questo tutorial mostra come ottenere lo stesso risultato in n8n in circa 30 minuti, usando il nodo community n8n-nodes-sealdoc. Nessun codice personalizzato. Il flusso di lavoro copre la generazione della fattura, il polling del job e la memorizzazione del risultato.
Prerequisiti
Prima di iniziare, è necessario avere:
- Un’istanza n8n che esegue la versione 1.0 o successiva, sia self-hosted che n8n Cloud. Il nodo community funziona su entrambi.
- Un account SealDoc con piano Starter o superiore. Le funzionalità di generazione fatture e timestamp sono disponibili dal piano Starter.
- Una chiave API SealDoc. Generarla nella dashboard SealDoc sotto Impostazioni, poi Chiavi API. Copiarla immediatamente; viene mostrata una sola volta.
Installare il nodo community sull’istanza n8n:
npm i n8n-nodes-sealdoc
Riavviare n8n dopo l’installazione. Ora si vedrà il nodo SealDoc disponibile nel pannello dei nodi nella categoria Community.
Cosa fa il flusso di lavoro
Questo flusso di lavoro prende i dati della fattura (venditore, acquirente, voci, importi) e produce un Factur-X PDF/A-3 completamente conforme con XML CII incorporato. I passaggi sono:
- Un trigger fornisce i dati della fattura come JSON (da un webhook, una query al database, un invio di form o qualsiasi altra sorgente n8n).
- Il nodo SealDoc Invoice.Generate invia i dati strutturati all’API SealDoc e restituisce un job ID.
- Il nodo SealDoc Job.Get esegue il polling finché il job non è completato e restituisce un URL di download per il documento generato.
- Un nodo finale memorizza il risultato nella posizione di archiviazione scelta.
Fase 1: impostare il trigger
Creare un nuovo flusso di lavoro. Aggiungere un nodo trigger Webhook. Impostare il metodo HTTP su POST. Questo fornisce un URL che è possibile chiamare con i dati della fattura da qualsiasi sistema in grado di effettuare una richiesta HTTP.
Per i test, è possibile utilizzare anche un Execute Workflow Trigger o un Manual Trigger con dati statici. L’importante è che il trigger produca un oggetto JSON con i campi della fattura. Si farà riferimento a quei campi nella fase successiva.
Un esempio minimale dei dati della fattura che il trigger deve fornire:
{
"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"
}
Fase 2: aggiungere il nodo Invoice.Generate
Aggiungere un nodo SealDoc alla canvas. Impostare:
- Resource: Invoice
- Operation: Generate
- Profile: EN 16931 (usare EXTENDED se l’acquirente o il mandato richiedono campi aggiuntivi)
- Embed timestamp: ON (questo collega un timestamp RFC 3161 al documento di output)
- Input data: mappare dall’output del trigger usando le espressioni n8n, ad esempio
{{ $json.invoiceNumber }}per il numero di fattura,{{ $json.seller.vatNumber }}per il numero IVA del venditore, e così via per ogni campo.
Nella sezione Credentials, selezionare o creare una credenziale API SealDoc. Incollare la propria chiave API nel campo Secret.
Fare clic su Execute Node per testare. Se la chiave API è valida e i dati della fattura sono completi, si riceverà una risposta come:
{
"jobId": "job_9kxQr2mPLv",
"status": "pending",
"estimatedSeconds": 4
}
Il job è stato messo in coda. L’API SealDoc lo elabora in modo asincrono in modo che un rendering PDF lento non blocchi l’esecuzione del flusso di lavoro.
Fase 3: aggiungere il nodo Job.Get con polling
Aggiungere un secondo nodo SealDoc. Impostare:
- Resource: Job
- Operation: Get
- Job ID:
{{ $node["SealDoc Invoice Generate"].json.jobId }}
Avvolgere questo nodo nel nodo Wait di n8n impostato su un intervallo di 3 secondi, con un loop che controlla se status è uguale a completed o failed. La maggior parte delle fatture viene completata in meno di 5 secondi. Impostare il conteggio massimo delle iterazioni a 10 per evitare un loop infinito su un job genuinamente bloccato.
Quando status è completed, la risposta Job.Get include:
downloadUrl: un URL a tempo limitato (valido per 10 minuti) che punta al documento PDF/A-3 generato.evidencePackUrl: un archivio ZIP contenente gli input originali, il PDF/A-3 di output, l’XML Factur-X incorporato, il token di timestamp RFC 3161 e un file manifest con hash. Questo è ciò che si consegna a un revisore.facturXProfile: il profilo effettivamente utilizzato (conferma EN 16931 o EXTENDED).timestampedAt: il timestamp UTC del token RFC 3161, che è il tempo di creazione legalmente significativo.
Se status è failed, controllare il campo failureReason. I valori comuni sono validation_failed (un campo obbligatorio mancava dall’input), unsupported_currency (SealDoc supporta EUR, USD, GBP, CHF, PLN, CZK e un elenco in crescita) e quota_exceeded (il limite mensile di job è raggiunto).
Fase 4: memorizzare il risultato
Aggiungere il nodo di storage che si adatta al proprio stack. Opzioni comuni:
- Nodo HTTP Request per fare PUT del file nel proprio sistema di gestione documentale o bucket MinIO.
- Nodo Google Drive o Dropbox se si utilizza il cloud storage per l’archivio.
- Nodo FTP/SFTP per lo storage on-premise.
- Move Binary Data più Write Binary File se n8n è self-hosted e si vuole scrivere direttamente in un percorso del filesystem.
Usare il downloadUrl dalla risposta Job.Get per recuperare il file binario, poi passarlo al nodo di storage. Memorizzare separatamente anche il evidencePackUrl se il criterio di conservazione lo richiede, il che dovrebbe essere il caso per le fatture sopra un certo valore o nei settori regolamentati.
Cosa si ottiene nell’output
Il file generato è un documento PDF/A-3B. Aprendolo in qualsiasi visualizzatore PDF si vede una fattura renderizzata. L’allegato incorporato factur-x.xml contiene l’XML CII completo, leggibile dal software contabile che supporta l’importazione Factur-X o ZUGFeRD. Il timestamp RFC 3161 è incorporato nel dizionario delle informazioni del documento PDF ed è verificabile indipendentemente.
Se si esegue l’output attraverso un validatore (il nostro strumento Validator gratuito accetta il file direttamente), si vedrà un risultato verde per la conformità PDF/A-3B, la validità dello schema EN 16931 e la presenza dell’allegato Factur-X.
Prossimi passi
Questo tutorial copre il flusso principale di generazione. L’API SealDoc supporta anche:
- Ricerca Peppol: prima di generare una fattura, verificare se l’acquirente è raggiungibile su Peppol tramite la risorsa Peppol nel nodo SealDoc.
- Solo validazione: inviare un file Factur-X o XRechnung esistente per la validazione dello schema senza generare un nuovo documento.
- Generazione in batch: inviare più payload di fatture in una singola chiamata API per scenari ad alto volume.
La documentazione completa dell’API è nella nostra pagina developers, con spec OpenAPI ed esempi curl pronti all’uso per ogni endpoint.