Blog

PDF/A e Factur-X spiegati agli ingegneri (senza il gergo legale)

Cosa vincolano realmente i profili PDF/A, perché FatturaPA è obbligatorio in Italia dal 2019, e la pipeline pratica più piccola per emettere conformi da un renderer JSON.

Se sei un ingegnere a cui hanno appena detto «le fatture devono essere PDF/A-3 con Factur-X entro il prossimo trimestre», e il tuo unico contesto è che qualcuno in legale ha pronunciato quelle parole, questo post è per te.

Tagliamo il tono dei documenti di standardizzazione e spieghiamo cosa vincolano realmente questi profili, perché i governi hanno iniziato a renderli obbligatori, e la pipeline pratica più piccola per emettere un PDF conforme da un renderer di dati strutturati.

PDF/A in due paragrafi

PDF è un formato flessibile. Troppo flessibile — la stessa specifica PDF ti permette di embeddare JavaScript, linkare a risorse esterne che potrebbero non esistere tra 50 anni, cifrare contenuti con crittografia reversibile, referenziare font esterni, e cento altre cose che rendono un documento non auto-contenuto.

PDF/A («A» per Archival) è un profilo di PDF che vieta le parti che impedirebbero al documento di renderizzare identicamente tra 50 anni. Le regole di alto livello:

  • Tutti i font devono essere embedded.
  • Niente JavaScript, niente link esterni, niente audio/video.
  • Niente cifratura.
  • Tutta la trasparenza deve essere appiattita o supportata dalla versione del profilo.
  • I colori devono essere device-independent (profilo ICC richiesto).
  • Tutto il contenuto deve essere nel file — niente riferimenti che dipendono dalla rete.

Esistono varie versioni, ognuna che aggiunge tolleranza per feature più recenti:

ProfiloAnnoCosa aggiunge
PDF/A-1b2005Baseline originale — il più stretto
PDF/A-2b2011Permette JPEG2000, trasparenza, layer
PDF/A-3b2012Permette allegati di file arbitrari (la fondazione di Factur-X)
PDF/A-42020Base ISO 32000-2 (PDF 2.0), livelli di conformità semplificati

Il suffisso «b» significa conformità «basic» (fedeltà visiva). Esistono anche varianti «u» (unicode-mappata) e «a» (taggata accessibilità) — per la maggior parte dei workflow fattura/ricevuta, «b» è ciò che vuoi, perché la conservazione fiscale si preoccupa della riproducibilità visiva, non della semantica per screen reader.

Conclusione pratica: se il tuo renderer dice di supportare PDF/A-3b, dovrebbe essere un singolo flag di configurazione ({ profile: "PDF/A-3b" } o equivalente). Se devi eseguire un secondo strumento (Ghostscript, qpdf, Acrobat) per convertire dopo, è una lacuna di workflow da considerare nelle tue ops.

Perché PDF/A-3 conta specificamente: è il portatore delle fatture elettroniche

PDF/A-3 ha aggiunto una capacità che si è rivelata cambiare il mondo: allegati di file arbitrari dentro il PDF.

Sembra noioso. Non lo è. È l’intera fondazione tecnica dei mandati di fatturazione elettronica che si stanno spiegando in Europa proprio ora.

L’architettura: un singolo file PDF che è sia

  1. Una fattura leggibile dall’uomo (layout visivo, totali, branding) — la parte che l’umano legge.
  2. Una fattura XML leggibile dalla macchina — la parte che il software dell’autorità fiscale parsa.

Entrambe dentro un file, entrambe rappresentanti la stessa fattura, e il wrapper PDF/A-3 garantisce che il file sarà ancora parseable in decenni.

I due formati XML principali:

  • Factur-X (Francia) — profilo XML basato su UN/CEFACT Cross Industry Invoice
  • ZUGFeRD (Germania) — sostanzialmente identico a Factur-X (i due standard si sono fusi tecnicamente nel 2018)
  • EN 16931 — la norma europea a cui entrambe le implementazioni si conformano
  • FatturaPA (Italia) — formato XML italiano via SDI (Sistema di Interscambio); quando esportato per interoperabilità EU si conforma a EN 16931

Per la maggior parte dei workflow, «Factur-X» e «ZUGFeRD» sono termini intercambiabili — condividono uno schema, condividono il meccanismo di embedding, e un singolo PDF conforme con uno è generalmente conforme con l’altro.

Cosa è obbligatorio, dove, quando

Una snapshot non esaustiva per ingegneri che pianificano rollout Q2/Q3 2026:

PaeseStatusFormato richiesto
ItaliaB2B obbligatorio dal 2019 via SDI; B2G dal 2014FatturaPA via SDI
GermaniaB2B obbligatorio per ricezione dal 2025-01-01; emissione dal 2027EN 16931 (ZUGFeRD / Factur-X / XRechnung)
FranciaEmissione obbligatoria per grandi imprese 2026-09; PMI 2027-09Factur-X via Chorus Pro
PoloniaObbligatorio dal 2024-07KSeF
SpagnaObbligatorio dal 2026 (B2B)Facturae via FACe
BelgioObbligatorio dal 2026-01Peppol BIS 3

Il pattern: ogni stato membro UE sta implementando una variante di e-fatturazione conforme EN 16931 su una timeline 2024–2027. Se i tuoi clienti operano in uno di questi mercati, il tuo generatore PDF dovrà emettere XML allegato accanto alla fattura visiva.

Per team italiani specificamente: la FatturaPA (in vigore dal 2019 per B2B) è gestita via Sistema di Interscambio (SDI) dell’Agenzia delle Entrate. Ogni fattura B2B italiana deve essere inviata via SDI in formato XML strutturato. La conservazione 10 anni richiede file PDF/A-3 con XML embedded — esattamente il setup Factur-X / ZUGFeRD.

La pipeline pratica più piccola

Dimentica cosa prescrivono i documenti di standardizzazione. Ecco la vista da ingegnere:

   ┌─────────────────────┐
   │  Dati della tua     │  (già un oggetto JSON da qualche parte)
   │      fattura        │
   └─────────┬───────────┘


   ┌─────────────────────┐
   │ Costruire XML       │  (mapping deterministico; lib testate esistono)
   │     EN 16931        │
   └─────────┬───────────┘


   ┌─────────────────────┐
   │ Renderizzare        │
   │ PDF/A-3b + allegare │  (singola chiamata API a gPdf — o due step altrove)
   │       l'XML         │
   └─────────┬───────────┘


   ┌─────────────────────┐
   │  Consegnare a       │
   │  SDI / Chorus Pro / │
   │  Peppol / etc       │
   └─────────────────────┘

I due step non banali:

Step 1: costruire l’XML

Questo è fastidioso ma meccanico. Mappi i dati della tua fattura (righe, tasse, totali, parti) ai nomi di campo XML EN 16931 (o FatturaPA per SDI). Diverse librerie Java/Node/Python lo fanno per te — cerca «factur-x library» o «fatturapa library» nel tuo linguaggio. Non scriverlo da zero a meno che tu davvero non goda delle specifiche schema XML.

Step 2: renderizzare PDF/A-3 e allegare l’XML

È qui che la scelta del renderer conta.

Senza supporto integrato: renderizzi un PDF ordinario, poi post-processi con uno strumento che converte a PDF/A-3 e allega l’XML come file embedded. Stack comuni: Ghostscript + qpdf, o uno strumento a pagamento come Aspose. Due step extra, due punti di fallimento extra, e devi assicurarti che il post-processing non faccia derivare il layout visivo.

Con supporto integrato (l’approccio di gPdf): una chiamata.

curl -X POST https://gpdf.com/api/v1/e-invoice/render \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "document": {
      "pages": [{ "size": "a4", "elements": [...] }]
    },
    "einvoice": {
      "format": "factur-x",
      "profile": "BASIC",
      "xml": "<rsm:CrossIndustryInvoice>...</rsm:CrossIndustryInvoice>"
    }
  }' \
  --output fattura-con-factur-x.pdf

Questa è l’intera pipeline. Il renderer emette PDF/A-3b, allega il tuo XML come factur-x.xml (o zugferd-invoice.xml, entrambi riconosciuti da ogni consumer), e restituisce i byte.

Trabocchetti comuni

Alcune cose che la gente impara nel modo difficile:

«PDF/A» e «con font conformi PDF/A» non sono la stessa cosa

Un file PDF/A-3 richiede che tutti i font siano embedded con copertura completa dei glifi usati. Se la tua fattura ha un nome cliente straniero e il renderer fa fallback a un font che non è completamente embeddable, gli strumenti di validazione lo rifiuteranno. Verifica che il tuo renderer embedda font CJK in modalità PDF/A — molti non lo fanno di default.

Visivo + XML devono coincidere

La fattura XML e la fattura visiva devono rappresentare la stessa fattura. I revisori fiscali le diff-eranno. Se il tuo codice emette XML con total: 119,00 e il PDF visivo mostra Totale: 120,00 (a causa di un bug di arrotondamento o di un template stantio), hai una discrepanza fiscale negli archivi. Genera entrambe dalla stessa source-of-truth, idealmente nello stesso percorso di codice.

Livelli di «profilo» in EN 16931

Factur-X ha profili: MINIMUM, BASIC, EN 16931, EXTENDED. Differiscono per quanti dati ci sono nell’XML. Usa BASIC a meno che il tuo cliente non richieda specificamente di più — copre codici fiscali, righe, parti, totali, che è abbastanza per il ~95 % della fatturazione B2B.

Validazione prima dell’invio

Valida sempre il PDF generato contro un validatore PDF/A (veraPDF è lo standard open-source) e valida l’XML contro lo schema EN 16931 prima di inviare all’autorità fiscale. Invii falliti a SDI / Chorus Pro / FACe contano contro le tue metriche di affidabilità con il regolatore.

TL;DR

PDF/A è un profilo di documento auto-contenuto. PDF/A-3 ti permette di allegare file. Factur-X / ZUGFeRD è «un XML EN 16931 allegato dentro un PDF/A-3». I mandati di fatturazione elettronica attraverso l’UE rendono questa combinazione il formato di fatto B2B per il 2025–2027.

Se il tuo renderer tratta PDF/A-3 + Factur-X come un singolo flag di configurazione, la migrazione è meccanica. Se non lo fa, stai costruendo una pipeline ops multi-step. Il /api/v1/e-invoice/render di gPdf è la versione single-flag — la referenza API ha lo schema completo, o prova un render di esempio nel Playground.