Blog

Validare ZUGFeRD con Mustang: cosa passa, cosa fallisce e perché

Mustang è il reference checker de-facto per Factur-X / ZUGFeRD. Errori comuni quando si incorpora CII XML in PDF/A-3 e come verificare prima dell’invio.

Se invii e-invoices a un cliente B2B tedesco nel 2026, il file è ZUGFeRD-compliant oppure viene respinto alla ricezione. Lo stesso vale in Francia con Factur-X. Il formato è un wrapper PDF/A-3 con EN 16931 CII XML allegato; generarlo da zero non è banale, e validarlo richiede un motore di riferimento.

Quel motore, in pratica, è Mustang (mustangproject.org): un progetto Java open-source che estrae l’XML embedded da un PDF/A-3 e lo valida contro EN 16931 Schematron. Mustang ha il supporto più profondo per ZUGFeRD e Factur-X tra gli strumenti open-source, ed è ciò che eseguono molti verificatori indipendenti.

Questo post passa in rassegna i failure modes che Mustang segnala e un modo più rapido per eseguirlo.

Cosa controlla davvero Mustang

Quando passi un PDF Factur-X o ZUGFeRD a Mustang, fa circa questo:

  1. Estrae l’embedded file. PDF/A-3 memorizza gli attachments nel name tree /EmbeddedFiles. Mustang cerca il filename canonico (factur-x.xml per Factur-X, zugferd-invoice.xml per ZUGFeRD 2.x) e legge i bytes.
  2. Controlla AFRelationship. L’attached file deve essere dichiarato AFRelationship="Alternative" secondo la baseline Factur-X / ZUGFeRD. Qualunque altro valore (Source, Data, Supplement) fallisce.
  3. Controlla namespace XMP e version. Factur-X 1.0 usa urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#. ZUGFeRD 2.x usa urn:zugferd:pdfa:CrossIndustryDocument:invoice:2p0#. Namespace o version string errati falliscono.
  4. Parsa l’XML come Cross-Industry Invoice (CII). Deve essere well-formed XML e iniziare con il CII root element corretto (rsm:CrossIndustryInvoice).
  5. Esegue EN 16931 Schematron. È il grosso della validation: ~200 business rules su semantica dei campi, codici obbligatori, totals math, VAT logic, party identifiers, ecc.

Pass = la fattura è accettabile da qualunque AP system conforme EN 16931 nell’UE. Fail = l’AP automation del cliente rifiuterà la fattura alla ricezione e il team AR avrà un’eccezione manuale.

I cinque failure modes più frequenti

Compaiono spesso nel lato Mustang di validator quando i team testano le prime e-invoices.

1. AFRelationship sbagliato

ERROR: Embedded file factur-x.xml uses AFRelationship="Source",
expected "Alternative".

La PDF spec consente vari relationship types per attached files. Factur-X / ZUGFeRD richiedono Alternative: l’XML allegato è una rappresentazione alternativa del contenuto visibile del PDF. Se il tuo PDF generator usa Data (default in molte librerie), Mustang fallisce subito. Il PDF visivo renderizza ancora correttamente, ma il payload strutturato non è valido per l’AP system.

2. Namespace XMP sbagliato o mancante

ERROR: XMP metadata missing fx:DocumentType or fx:DocumentFileName under
namespace urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#.

Il pacchetto XMP del PDF deve dichiarare quale Factur-X profile è (MINIMUM, BASIC, EN 16931, EXTENDED) e quale filename cercare. È facile dimenticarlo scrivendo a mano il wrapper PDF/A-3; l’endpoint gPdf /api/v1/e-invoice/render lo emette automaticamente.

3. CII XML well-formed, ma EN 16931 Schematron fallisce

ERROR: BR-CO-25 — In an invoice (BR-01) the
  ram:SpecifiedTradePaymentTerms/ram:DueDateDateTime is required when
  ram:DocumentTypeCode is 380.

È il grosso dei fallimenti reali. L’XML è sintatticamente valido; falliscono le business rules. Le regole EN 16931 Schematron hanno ID stabili (BR-01, BR-CO-25, ecc.) che puoi cercare nella specifica. Comuni:

  • BR-01: invoice deve avere un unique invoice number.
  • BR-04: invoice deve avere issue date.
  • BR-05: invoice deve avere invoice type code.
  • BR-CO-25: payment terms required quando document type è “Commercial invoice”.
  • BR-Z-01: VAT category codes deve essere uno tra S, Z, E, AE, K, G, O, L, M.

Correggi i source data, ricostruisci e re-validate.

4. Il wrapper PDF/A non valida

INFO: CII XML extracted and validates against EN 16931.
ERROR: PDF/A-3b conformance check failed: missing Output Intent.

Qui il check XML di Mustang passa, ma il wrapper PDF/A-3 sottostante fallisce. Causa comune: qualcuno ha scritto correttamente l’XML ma ha emesso un PDF ordinario invece di PDF/A-3. L’embedded file è presente, ma le regole di archiviazione non sono rispettate. Il validator su gpdf.com/validator/ lo cattura eseguendo veraPDF in parallelo: il fail PDF/A-3 appare nella colonna veraPDF mentre Mustang segnala XML pass.

5. Encoding / declaration mismatch

ERROR: XML declares <?xml version="1.0" encoding="UTF-8"?> but the
embedded byte stream is UTF-8 with BOM. Mustang strict mode rejects BOM.

È più comune di quanto sembri quando uno strumento XML emette UTF-8 BOM e i bytes vengono embedded raw. Fix: rimuovere il BOM prima dell’embed. L’e-invoice endpoint di gPdf normalizza questo caso.

Eseguire Mustang senza installare Java

Installare Java + Mustang CLI va bene per un check singolo. Per verification continua — ogni invoice generata, ogni CI run che assert e-invoice compliance — è attrito non necessario.

gpdf.com/validator/ esegue Mustang nel browser:

  1. Trascina il PDF Factur-X / ZUGFeRD nell’upload zone.
  2. Il validator estrae l’embedded XML ed esegue lo Schematron engine di Mustang (compilato in JavaScript / WebAssembly, eseguito in Cloudflare Worker).
  3. Il report Mustang torna affiancato al report PDF/A-3 di veraPDF, perché entrambi i layer devono passare.
  4. Scarica il report JSON come QA evidence.

Nessun login. Nessuna quota. Lo stesso tipo di Mustang che installeresti via Maven, servito come servizio pubblico gratuito.

TL;DR

Mustang segnala 5 failure modes comuni; la maggior parte equivale a “il file è stato generato da un tool che non emette un PDF/A-3 Factur-X / ZUGFeRD fully-conformant”. La E-invoice API di gPdf lo emette in una call. validator verifica il risultato con Mustang + veraPDF in parallelo.

La maggior parte dei bug che Mustang cattura riguarda wrapper o AFRelationship, non solo XML semantics. Generare correttamente il file è gran parte della battaglia; validator è la ricevuta che lo prova.