Aller au contenu

Ironfang Finance - ZUGFeRD / Factur-X

Valider ZUGFeRD et Factur-X

Les profils, ce qui est contrôlé dans un PDF et dans son XML, ce qui ne l'est pas, comment appeler l'API, comment lire un résultat et comment extraire le XML d'un PDF.

Ironfang Finance valide les factures et avoirs ZUGFeRD et Factur-X soit sous forme de PDF hybride, le PDF avec son XML de facture intégré, soit sous forme de XML seul. ZUGFeRD 2.5.2 et Factur-X 1.09.2 sont la même norme, et un document qui déclare l'une ou l'autre est contrôlé de la même manière. Essayez-le sans compte dans le validateur ZUGFeRD / Factur-X, également en allemand.

Profils et versions

Le profil est lu dans l'identifiant de spécification du XML (l'identifiant de guideline, ram:GuidelineSpecifiedDocumentContextParameter), et chaque profil a sa propre version : son schéma et le Schematron officiel ZUGFeRD 2.5.2 de ce profil, issu du paquet du FeRD. Le résultat l'indique dans ruleset.variant, ruleset.official_release (2.5.2) et ruleset.technical_release (1.09.2).

ProfilvariantRemarque
MINIMUMminimumPas une facture EN 16931 complète ; le résultat l'indique.
BASIC WLbasic-wlPas une facture EN 16931 complète ; le résultat l'indique.
BASICbasic
EN 16931en16931Le profil de la norme européenne.
EXTENDEDextended
XRECHNUNGxrechnungReconnu et refusé avec unsupported_variant.

Chaque profil est en UN/CEFACT CII D22B, pour les factures et les avoirs. Une XRechnung en UBL ou en CII est validée comme famille xrechnung ; voir le guide XRechnung.

Ce qui est contrôlé

Un PDF est contrôlé en trois groupes, indiqués dans groups, chacun contenant ses étapes. Une étape qui échoue arrête les suivantes, et le résultat indique que chaque étape ultérieure n'a pas été atteinte plutôt que réussie. Un XML envoyé seul ne passe que par le groupe du XML de facture.

GroupeÉtapeCe qu'elle contrôle
pdfainputLa requête et le PDF dans leurs limites. Un PDF chiffré, ou un PDF qui n'a pas exactement un XML de facture intégré, est refusé à la place par une réponse Problem.
pdfapdfaLe PDF par rapport à la conformité PDF/A qu'il déclare, avec veraPDF. Une facture hybride doit déclarer PDF/A-3, ou PDF/A-4f.
attachment_metadatahybrid_bindingLes règles du FeRD pour le conteneur, sous la forme des contrôles Ironfang FW-HYB-001 à FW-HYB-013 : la facture est un fichier associé avec une relation, un nom et un type de média autorisés, et les métadonnées XMP Factur-X déclarent le profil propre du XML, le nom du fichier intégré, le type de document INVOICE et une version de Factur-X.
invoice_xmlxmlUn XML bien formé dans les limites, sans DTD, sans entités au-delà des cinq prédéfinies et sans XInclude.
invoice_xmlxsdLe schéma XML du profil.
invoice_xmlzugferd_profileLe Schematron officiel ZUGFeRD 2.5.2 du profil, y compris les règles métier EN 16931 qu'applique le profil.

Seuls les constats fatal (erreur) font échouer un document ; warning (avertissement) et information jamais. Les contrôles de l'intégration portent le niveau que le FeRD fixe pour chaque exigence.

Ce qui n'est pas contrôlé

Chaque résultat liste ce qu'il ne peut pas établir dans coverage.not_checked :

AspectQuand
visual_consistencyTout PDF. La correspondance entre les pages visibles et la facture du XML n'est pas comparée ; le XML constitue les données de la facture.
digital_signatureTout PDF. Les signatures sont hors du périmètre du contrôle.
pdf_containerXML envoyé seul : rien n'a été contrôlé concernant un PDF.
en16931_semanticsMINIMUM et BASIC WL, qui ne contiennent pas une facture EN 16931 complète.

Valider avec l'API

POST /finance/v2/einvoices/validate reçoit le PDF en application/pdf ou le XML en application/xml. Indiquez la famille, comme le fait ce script, afin qu'un document qui déclare une autre famille soit refusé avec ce qu'il déclare. Le script conserve le résultat dans result.json et dérive l'Idempotency-Key du fichier, si bien qu'une nouvelle tentative renvoie le premier résultat et n'est pas décomptée une seconde fois.

#!/usr/bin/env bash
# Validate one ZUGFeRD / Factur-X invoice, PDF or XML, with the Ironfang
# Finance API and keep the result.
#
#   IRONFANG_API_KEY=... ./validate-zugferd.sh invoice.pdf
#
# A .pdf is checked as a hybrid invoice (PDF/A, attachment and metadata,
# then its embedded XML); anything else is sent as the invoice XML alone.
# The result is written to result.json. A retry with the same file sends
# the same Idempotency-Key, so it returns the first result and is not
# charged again.
set -euo pipefail
file="$1"
base="${IRONFANG_FINANCE_API:-https://api.ironfang.uk/finance}"
key="zf-$(sha256sum "$file" | cut -c1-40)"
case "$file" in
  *.pdf|*.PDF) type="application/pdf" ;;
  *) type="application/xml" ;;
esac

curl --fail-with-body --silent --show-error \
  "$base/v2/einvoices/validate?family=zugferd-facturx" \
  -H "Authorization: Bearer $IRONFANG_API_KEY" \
  -H "Content-Type: $type" \
  -H "Idempotency-Key: $key" \
  --data-binary "@$file" \
  --output result.json

grep -o '"outcome":"[a-z]*"' result.json | head -n 1
Paramètre de requêteSignification
familyzugferd-facturx. Sans lui, la famille est lue dans l'identifiant de spécification du document.
variantUn profil, du tableau ci-dessus. Sans lui, le profil est lu dans le document ; un profil qui le contredit donne family_mismatch.
document_typeinvoice, credit_note ou auto (la valeur par défaut : lu dans le document).
scopexml ou hybrid_pdf. Il suit le corps : un PDF est contrôlé en hybrid_pdf et le XML en xml ; demander l'autre donne scope_unavailable.
rulesetlatest (la valeur par défaut) ou l'identifiant exact d'une version, tiré de GET /finance/v2/einvoices/rulesets.

Un PDF peut peser jusqu'à 20 Mio, avec au plus 200 pages et 20 fichiers intégrés, 25 Mio de pièces jointes décodées et 256 Mio de contenu décodé ; son XML de facture, comme un XML envoyé seul, jusqu'à 5 Mio. Un PDF dispose de 30 secondes pour aboutir à un verdict. Sans clé API, la même requête est anonyme : rien n'est conservé et des limites de débit plus strictes s'appliquent. Avec une clé, une validation terminée compte pour une opération de votre quota Finance et le résultat est conservé 30 jours à l'adresse GET /finance/v2/einvoices/results/{id}. Le contrat complet est le document OpenAPI V2, et les différences entre V2 et V1 sont décrites dans le guide V1 et V2.

Lire un résultat

outcome vaut valid ou invalid pour une validation terminée ; tout ce qui a empêché un verdict, comme un dépassement de délai, est une réponse Problem avec outcome: indeterminate, et rien n'est décompté. Pour un PDF, input décrit le PDF et input.embedded_xml le XML contrôlé (sa taille, son SHA-256 et son nom de fichier) ; declared.pdf reprend tel quel ce que les métadonnées du PDF disent de lui-même : le niveau de conformité Factur-X, le nom de fichier, le type et la version du document, ainsi que la partie et la conformité PDF/A.

Les constats des étapes input, pdfa et hybrid_binding portent un emplacement pdf, le chemin de l'objet PDF ; les constats sur le XML portent un XPath. Les règles de veraPDF sont indiquées sous la forme ISO19005-<part>:<clause>-<test>, une fois par règle en échec. engines nomme les deux moteurs, celui du XML et celui du PDF, chacun par le condensé de son image. next_actions inclut extract_xml pour un PDF.

Extraire le XML d'un PDF

POST /tools/v2/invoice/extract reçoit un PDF (application/pdf, jusqu'à 20 Mio) et renvoie son XML de facture octet pour octet, en application/xml. La facture est identifiée exactement comme la validation l'identifie, si bien que le XML est celui que contrôle une validation du même PDF. Rien n'est jugé et rien n'est conservé. Un PDF sans facture intégrée, avec plusieurs, chiffré ou au-delà d'une limite est refusé avec le code correspondant. Pour lire le XML comme un document, ouvrez-le dans la visionneuse XRechnung, qui lit le XML CII de ZUGFeRD et Factur-X.

Réponses d'erreur

CodeQuand
no_embedded_invoiceLe PDF ne contient aucun XML de facture : il s'agit peut-être d'une facture PDF ordinaire.
ambiguous_embedded_invoiceLe PDF contient plus d'un XML de facture.
encrypted_pdfLe PDF est chiffré ou protégé par un mot de passe.
processing_limit, payload_too_largeAu-delà d'une limite publiée.
family_mismatchLe XML déclare une autre famille ou un autre profil que celui indiqué ; detected indique ce qu'il déclare.
family_undetectedAucun profil n'a été indiqué et le XML n'en déclare aucun que reconnaît Ironfang.
unsupported_variantLe profil XRECHNUNG.
unsupported_document_typeNi une facture ni un avoir, ou un type qui contredit celui indiqué.
scope_unavailableUne portée à laquelle le corps ne peut pas être contrôlé.
validator_unavailable, validation_timeout, internal_errorAucun verdict : indéterminé et non décompté. Réessayez.