L'API Ironfang Finance a deux versions qui fonctionnent côte à côte. V1, sous /finance/v1, est inchangée : ses clients gardent leurs structures Peppol, et elle ne renvoie jamais de résultat V2. V2, sous /finance/v2, valide davantage de familles et de formats et indique exactement ce qui a été vérifié. Rien ne doit migrer : une intégration V1 continue de fonctionner, et V2 valide toutes les familles, Peppol compris.
Quelle API sert quoi
| Quoi | API |
|---|---|
| Validation Peppol BIS Billing 3 (UBL) | Les deux. V2 (family=peppol-bis-billing-3, ou détectée à partir du document) exécute la même version sur le même validateur Peppol et rend compte des mêmes étapes et constats dans son propre résultat. |
| Validation XRechnung 3.0.2 (UBL ou CII) | V2 uniquement (family=xrechnung). |
| Validation ZUGFeRD 2.5.2 / Factur-X 1.09.2 (XML CII ou PDF hybride) | V2 uniquement (family=zugferd-facturx). |
| Génération de factures à partir de JSON | V1 uniquement (POST /finance/v1/einvoices/generate). |
| PDF lisible d'une facture générée | V1 uniquement (POST /finance/v1/einvoices/render). |
| Rapports de preuve signés | Les deux. POST /finance/v2/einvoices/reports signe un rapport de tout résultat conservé dans la version propre à ce résultat, V1 ou V2 ; POST /finance/v1/einvoices/reports de V1 ne signe que des résultats V1. POST /finance/v2/einvoices/reports/verify vérifie les rapports des deux versions. |
| Résultats conservés, livraisons, tâches et lots | Les deux. V2 liste ensemble les enregistrements V1 et V2 ; V1 ne liste que les siens. |
| Destinations (webhooks et S3) | Routes V1 (/finance/v1/einvoices/destinations) ; une destination reçoit les événements V1 et V2. |
GET /finance/v2/einvoices/rulesets liste exactement la famille, la variante, la syntaxe, le type de document et le périmètre que couvre chaque version V2 active ; rien d'autre n'est pris en charge. Les guides des familles en disent plus : XRechnung et Factur-X / ZUGFeRD.
Requêtes
Les deux versions acceptent le document comme corps de la requête, avec les choix passés en paramètres de requête, ou en multipart/form-data avec une partie document et une partie options facultative qui contient les mêmes choix en JSON. Les paramètres de requête ne sont pas lus pour les requêtes multipart, et un paramètre ou une partie inconnu ou répété donne 400 malformed_request dans les deux.
| V1 | V2 | |
|---|---|---|
| Corps | application/xml ou text/xml | La même chose, ou application/pdf pour une facture hybride. Le contenu est inspecté ; du XML contenant un PDF, ou l'inverse, donne 415. |
| Choix | ruleset, profile, document_type | ruleset, family, variant, document_type, scope |
| Détection | Sans profil, à partir de CustomizationID et ProfileID du document | Sans famille, à partir de la déclaration du document. Une famille indiquée que le document contredit donne 422 family_mismatch, avec ce qu'il déclare dans detected. |
| Périmètre | XML uniquement | xml pour du XML, hybrid_pdf pour un PDF ; toute autre combinaison donne 422 scope_unavailable. |
| Taille | XML jusqu'à 5 Mio | XML jusqu'à 5 Mio ; un PDF jusqu'à 20 Mio, 200 pages et 20 fichiers intégrés, avec le XML de sa facture jusqu'à 5 Mio. |
| Délai | 10 secondes | 10 secondes pour du XML, 30 secondes pour un PDF |
Résultats
Un résultat V1 a le schéma financewolf/einvoice/validation-result/v1, un résultat V2 ironfang/finance/einvoice/validation-result/v2. Les deux indiquent outcome valid ou invalid pour une validation terminée, selon les seuls constats fatals ; tout ce qui a empêché un verdict est, dans les deux, un Problem avec outcome: indeterminate, sans rien facturer. Les champs qui diffèrent :
| Champ | V1 | V2 |
|---|---|---|
input | sha256, bytes, content_type, document_type | media_type au lieu de content_type ; pour un PDF, aussi embedded_xml, le XML qui a été vérifié |
ruleset | requested, id, selection_method, state, vesid, official_release | Pas de vesid ; ajoute family, variant, syntax, scope et technical_release |
profile | La famille de profil | Absent : ruleset.family et ruleset.variant |
declared | Absent | Ce que le document dit de lui-même, recopié : syntaxe, racine, identifiants de spécification et de processus, code de type et, pour un PDF, ce que déclarent ses métadonnées |
layers | Toujours les cinq mêmes : input, xml, xsd, en16931, peppol | La séquence propre à la famille, parmi input, pdfa, hybrid_binding, xml, xsd, en16931, peppol, xrechnung et zugferd_profile |
groups | Absent | Les étapes regroupées : toujours invoice_xml et, pour un PDF, pdfa et attachment_metadata avant lui |
coverage | Absent | Le périmètre, les étapes exécutées et not_checked : ce que le résultat ne peut pas établir, par exemple un PDF qui n'a pas été fourni |
engine / engines | Un engine : nom, empreinte de l'image, version du paquet d'indications | Une liste engines, chacun avec un role : xml, et pdf pour un contrôle hybride |
links / next_actions | links | next_actions : view, et extract_xml pour un PDF |
operation_id, status, counts, findings_summary, timing et usage existent dans les deux. En V2, counts compte aussi les constats information.
Constats
| V1 | V2 | |
|---|---|---|
| Gravité | fatal ou warning | fatal, warning ou information ; rule_flag est le niveau propre à la règle lorsque la configuration de la famille en fixe un autre |
| Emplacement | location (une chaîne) et location_kind : none, xpath ou line-column | Un objet location avec kind (aussi pdf, un chemin d'objet PDF) et value |
| Source | Un id de règle en FW- signale un contrôle propre à Ironfang | rule_source : official ou ironfang |
| Indications | hint_code, hint, source_url, ruleset_id | hint_code, source_url |
Dans les deux, message est l'un des messages fixes d'Ironfang : les textes officiels des règles ne sont pas repris, car ils peuvent contenir des valeurs de la facture. rule_id est l'identifiant officiel, inchangé.
Résultats conservés
GET /finance/v2/einvoices/results liste ensemble les validations et générations faites via V1 et les validations faites via V2, chacune indiquant l'API qui l'a produite (api_version), le schéma de son document conservé (result_schema) et sa famille, avec un filtre sur chacun. GET /finance/v2/einvoices/results/{id} renvoie chacun d'eux dans le schéma sous lequel il a été produit, et DELETE efface l'un comme l'autre. La liste propre à V1 ne montre que des résultats V1, et lire un résultat V2 via V1 donne 404 : un résultat V2 n'est pas un document que décrit le schéma de V1. Les résultats sont conservés 30 jours dans les deux.
Événements webhook et livraisons
Une opération terminée met en file un événement, livré à chaque destination webhook ou S3 activée et signé de la même façon quelle que soit l'API qui l'a produite. Une opération faite via V1 envoie financewolf/einvoice/event/v1, dont le result_url est sous /finance/v1. Une opération faite via V2 envoie ironfang/finance/einvoice/event/v2, dont le result_url est sous /finance/v2 et dont le data porte aussi les family, variant et scope sous lesquels le résultat a été produit. Un récepteur qui accepte les deux doit se baser sur schema.
GET /finance/v2/einvoices/deliveries liste les livraisons des deux sortes, chacune avec son api_version et son événement tel qu'il a été mis en file, et peut filtrer sur api_version. POST /finance/v2/einvoices/deliveries/{id}/retry relance une livraison échouée de l'une ou l'autre sorte. La liste, la lecture et la relance des livraisons de V1 ne voient que les livraisons d'événements V1.
Tâches et lots
POST /finance/v2/einvoices/jobs met en file une validation V2 et POST /finance/v2/einvoices/batches de 1 à 100 ensemble, toutes ou aucune. Chaque tâche contient document_base64, son media_type et les options synchrones. Un document que la validation synchrone refuserait est refusé dès l'acceptation avec le même Problem, et rien n'est mis en file ni facturé. Le résultat, l'utilisation et l'événement d'une tâche sont exactement ceux d'une validation synchrone.
| V1 | V2 | |
|---|---|---|
| Opérations | Validation et génération | Validation |
| Document | XML jusqu'à 5 Mio | XML jusqu'à 5 Mio ou un PDF jusqu'à 20 Mio |
| Enveloppe d'une tâche | 8 Mio | 28 Mio |
| Lot | De 1 à 100 tâches, enveloppe de 32 Mio | De 1 à 100 tâches, documents de 25 Mio au total, enveloppe de 36 Mio |
Les tâches V1 et V2 partagent la file d'attente de chaque organisation : au plus 100 tâches non terminées et 25 Mio de leurs documents, conservés chiffrés jusqu'à leur achèvement, 24 heures au plus. Les listes de tâches et de lots de V1 ne montrent que le travail V1 ; celles de V2 montrent les deux.
Ce que les deux ont en commun
- Les clés API de la plateforme Ironfang (
Authorization: Bearer) avec les mêmes portées :finance:einvoices:writepour valider,finance:einvoices:readpour lire. - La validation anonyme sans clé : rien n'est enregistré, et des limites de débit plus strictes s'appliquent.
- Une
Idempotency-Keyfacultative sur les requêtes authentifiées : la même clé et la même requête renvoient le premier résultat et ne sont pas facturées à nouveau. Les clés de V2 sont propres à V2, séparées de celles de V1. - Les Problems au format RFC 9457,
application/problem+json; basez-vous surcode. - Un seul quota Finance : une validation terminée via l'une ou l'autre API compte pour une opération.
- La validation synchrone n'enregistre pas les documents importés.
Exemple
Une facture Peppol via les deux API, puis une facture XRechnung et un PDF ZUGFeRD / Factur-X, que seule V2 valide.
# V1: a Peppol BIS Billing 3 invoice (UBL).
curl --fail-with-body --silent --show-error \
"https://api.ironfang.uk/finance/v1/einvoices/validate?ruleset=latest&profile=peppol-bis-billing-3" \
-H "Authorization: Bearer $IRONFANG_API_KEY" \
-H "Content-Type: application/xml" \
-H "Idempotency-Key: peppol-invoice-0001" \
--data-binary @peppol-invoice.xml
# V2: the same invoice. The same release runs on the same engine; the
# answer is the V2 result, with the family named instead of a profile.
curl --fail-with-body --silent --show-error \
"https://api.ironfang.uk/finance/v2/einvoices/validate?ruleset=latest&family=peppol-bis-billing-3" \
-H "Authorization: Bearer $IRONFANG_API_KEY" \
-H "Content-Type: application/xml" \
-H "Idempotency-Key: peppol-invoice-0001-v2" \
--data-binary @peppol-invoice.xml
# V2: an XRechnung invoice (UBL or CII). Only V2 validates XRechnung.
curl --fail-with-body --silent --show-error \
"https://api.ironfang.uk/finance/v2/einvoices/validate?ruleset=latest&family=xrechnung" \
-H "Authorization: Bearer $IRONFANG_API_KEY" \
-H "Content-Type: application/xml" \
-H "Idempotency-Key: xrechnung-invoice-0001" \
--data-binary @xrechnung-invoice.xml
# V2: a ZUGFeRD / Factur-X hybrid PDF. Only V2 takes a PDF.
curl --fail-with-body --silent --show-error \
"https://api.ironfang.uk/finance/v2/einvoices/validate?family=zugferd-facturx" \
-H "Authorization: Bearer $IRONFANG_API_KEY" \
-H "Content-Type: application/pdf" \
--data-binary @zugferd-invoice.pdf
