Votre ERP contient déjà toutes les données de la facture. Le numéro, la date, les montants, les identifiants fiscaux, les lignes de détail — tout est là, structuré dans des tables ou des objets métier. Le défi n’est pas de trouver les données. C’est de les mapper vers le modèle sémantique EN16931 attendu par le XML CII, avec les bons codes, les bons formats et les bonnes cardinalités.
Ce guide montre comment structurer les données ERP en JSON pour générer un Factur-X conforme via l’API, en mode invoice_data. Il couvre le modèle de données, les transformations nécessaires, et les cas spéciaux qui posent problème en pratique — autoliquidation BTP, avoirs, multi-taux TVA.
Pour le contexte général de la conversion PDF vers Factur-X (les deux modes, la validation intégrée, les quotas), voir Convertir une facture PDF en Factur-X 1.08 conforme. Pour la cartographie complète des Business Terms EN16931, voir Champs obligatoires EN16931 : cartographie et mapping ERP.
Le modèle de données invoice_data
L’API Convert en mode ERP attend un champ invoice_data contenant un objet JSON. Cet objet est la représentation structurée de la facture — l’API le transforme en XML CII D22B conforme et l’embarque dans le PDF/A-3.
Champs racine
| Champ JSON | BT EN16931 | Type | Obligatoire | Description |
|---|---|---|---|---|
invoiceNumber | BT-1 | string | oui | Numéro de facture |
issueDate | BT-2 | string | oui | Date d’émission (AAAAMMJJ) |
typeCode | BT-3 | string | non (défaut 380) | Type de document UNTDID 1001 |
currencyCode | BT-5 | string | oui | Code devise ISO 4217 |
Le typeCode vaut 380 pour une facture standard et 381 pour un avoir (note de crédit). D’autres codes existent (384 = facture corrective, 389 = autofacturation), mais 380 et 381 couvrent la grande majorité des cas en production.
Bloc seller
"seller": {
"name": "Dupont BTP SAS",
"vatId": "FR32123456789",
"legalId": "12345678901234",
"address": {
"street": "45 Avenue des Chantiers",
"city": "Lyon",
"postalCode": "69003",
"country": "FR"
}
}
| Champ JSON | BT EN16931 | Obligatoire | Notes |
|---|---|---|---|
name | BT-27 | oui | Raison sociale |
vatId | BT-31 | conditionnel | TVA intracommunautaire (schemeID VA) |
legalId | BT-30 | conditionnel | SIRET en France (schemeID 0002) |
address.street | BT-35 | non | Adresse ligne 1 |
address.city | BT-37 | non | Ville |
address.postalCode | BT-38 | non | Code postal |
address.country | BT-40 | oui | Code pays ISO 3166-1 alpha-2 |
La règle Schematron BR-CO-26 exige qu’au moins un identifiant vendeur soit présent parmi BT-29, BT-30 et BT-31. En pratique, fournir vatId et legalId ensemble est la configuration la plus robuste pour les entreprises françaises.
Bloc buyer
La structure est identique au bloc seller. Le minimum requis est le name (BT-44) et le address.country (BT-55). En B2B, ajouter le vatId (BT-48) est fortement recommandé pour le routage PDP.
Bloc lines
"lines": [
{
"description": "Pose de cloisons sèches — chantier Bellecour",
"quantity": 40,
"unitCode": "HUR",
"unitPrice": 55.00,
"vatRate": 20,
"vatCategory": "S"
}
]
| Champ JSON | BT EN16931 | Notes |
|---|---|---|
description | BT-153 | Nom / description de l’article |
quantity | BT-129 | Quantité facturée |
unitCode | BT-130 | Code UN/ECE Rec 20 (C62 = unité, HUR = heure, KGM = kg) |
unitPrice | BT-146 | Prix unitaire net HT |
vatRate | BT-152 | Taux TVA applicable (ex: 20 pour 20%) |
vatCategory | BT-151 | Code catégorie TVA UNCL 5305 |
Chaque facture doit contenir au moins une ligne (règle BR-16). Le unitCode par défaut est C62 (unité) s’il est omis. Les ERP stockent souvent des labels en clair (“heure”, “pièce”) qu’il faut convertir en codes UN/ECE Rec 20.
Bloc totals
"totals": {
"netAmount": 2200.00,
"vatAmount": 440.00,
"grossAmount": 2640.00,
"dueAmount": 2640.00
}
| Champ JSON | BT EN16931 | Description |
|---|---|---|
netAmount | BT-109 | Total HT |
vatAmount | BT-110 | Total TVA |
grossAmount | BT-112 | Total TTC |
dueAmount | BT-115 | Montant à payer |
Les règles Schematron BR-CO-10, BR-CO-13 et BR-CO-15 vérifient la cohérence arithmétique. Un écart d’un centime entre netAmount et la somme des lignes suffit à déclencher un rejet.
Bloc taxBreakdown (multi-taux)
Quand la facture comporte plusieurs taux de TVA, le bloc taxBreakdown ventile les montants par catégorie :
"taxBreakdown": [
{
"vatCategory": "S",
"vatRate": 20,
"taxableAmount": 1800.00,
"taxAmount": 360.00
},
{
"vatCategory": "S",
"vatRate": 5.5,
"taxableAmount": 400.00,
"taxAmount": 22.00
}
]
Chaque entrée correspond à un bloc ram:ApplicableTradeTax dans le XML CII (BG-23). La règle BR-CO-17 vérifie que taxAmount = taxableAmount x vatRate / 100, arrondi à 2 décimales. Chaque ligne de facture doit être rattachée au bon taux via son champ vatCategory + vatRate.
Mapping ERP vers invoice_data : les champs qui posent problème
La plupart des champs se mappent directement — le nom du vendeur dans l’ERP devient seller.name, le numéro de facture devient invoiceNumber. Mais plusieurs transformations sont nécessaires pour passer du modèle ERP au modèle EN16931.
Dates : ISO 8601 versus AAAAMMJJ
En CII, les dates utilisent le format AAAAMMJJ (ex: 20260401) avec l’attribut format="102". Les ERP stockent généralement en ISO 8601 (2026-04-01).
L’API gère cette conversion automatiquement : vous pouvez envoyer "issueDate": "2026-04-01" ou "issueDate": "20260401" — les deux formats sont acceptés. Si vous construisez le XML vous-même, le format attendu est strictement AAAAMMJJ.
Catégories TVA : S, Z, E, AE, K, G, O
Le code catégorie TVA (UNCL 5305) est une source d’erreur fréquente. Les ERP utilisent des labels internes (“Normal”, “Exonéré”, “Intra-UE”) qu’il faut mapper vers les codes normalisés :
| Code | Signification | Quand l’utiliser |
|---|---|---|
S | Standard rated | Taux normal (20%, 10%, 5.5%, 2.1% en France) |
Z | Zero rated | Opération taxable à taux zéro |
E | Exempt | Exonération de TVA (article 261 du CGI) |
AE | Reverse charge | Autoliquidation — sous-traitance BTP (CGI art. 283, 2 nonies) ou prestations intra-UE (CGI art. 283, 1, al. 2) |
K | Intra-community supply | Livraison intracommunautaire de biens |
G | Export outside EU | Exportation hors UE |
O | Not subject to VAT | Hors champ TVA |
Chaque code active des règles Schematron spécifiques (familles BR-S-*, BR-Z-*, BR-E-*, BR-AE-*, etc.). Utiliser le mauvais code déclenche des erreurs en cascade. Le détail de ces règles est documenté dans le Catalogue des erreurs BR-* EN16931.
Identifiants légaux : SIRET et TVA intracommunautaire
En France, deux identifiants coexistent :
- BT-30 (identifiant légal) : le SIRET à 14 chiffres, avec
schemeID="0002"(répertoire SIRENE, ISO 6523) - BT-31 (identifiant TVA) : le numéro de TVA intracommunautaire (
FRXX+ 9 chiffres), avecschemeID="VA"
Dans le JSON invoice_data, ils correspondent respectivement à legalId (SIRET) et vatId (TVA intra). L’API génère automatiquement les bons schemeID dans le XML CII.
La règle BR-CO-26 exige au moins un identifiant vendeur. Pour l’autoliquidation (code AE), les règles BR-AE exigent un identifiant fiscal vendeur (BT-31, BT-32 ou BT-63) et côté acheteur un identifiant TVA ou un identifiant légal (BT-48 ou BT-47).
Adresses : BT-35, BT-37, BT-40
Seul le code pays (address.country → BT-40) est strictement obligatoire (cardinalité 1..1). La rue (BT-35) et la ville (BT-37) sont optionnelles dans EN16931 (0..1), mais fortement recommandées pour le routage PDP et la conformité pratique.
Cas spéciaux
Autoliquidation (code TVA AE)
L’autoliquidation recouvre deux régimes juridiques distincts : la sous-traitance BTP (CGI art. 283, 2 nonies) et les prestations de services intra-UE (CGI art. 283, 1, alinéa 2). Dans les deux cas, le vendeur ne facture pas de TVA — c’est l’acheteur qui la déclare et la déduit. Le code catégorie TVA AE est le même, mais le fondement légal et la mention obligatoire diffèrent.
Dans le JSON invoice_data, quatre éléments sont nécessaires :
vatCategory: "AE"sur chaque ligne de facturevatRate: 0— le taux est zéro puisque la TVA n’est pas facturée- Un motif d’exonération — le champ
taxExemptionReason(BT-120) avec la mention légale - Un identifiant fiscal vendeur et un identifiant acheteur — pour une facture en autoliquidation (AE), les règles BR-AE exigent un identifiant fiscal vendeur (BT-31, BT-32 ou BT-63) et côté acheteur un identifiant TVA ou un identifiant légal (BT-48 ou BT-47)
Le taxBreakdown doit refléter la même configuration :
"taxBreakdown": [
{
"vatCategory": "AE",
"vatRate": 0,
"taxableAmount": 5000.00,
"taxAmount": 0.00,
"taxExemptionReason": "Autoliquidation - Sous-traitance BTP, article 283, 2 nonies du CGI"
}
]
L’absence du motif d’exonération (BT-120 ou BT-121) déclenche une erreur BR-AE. L’absence d’un identifiant fiscal vendeur (BT-31, BT-32 ou BT-63) ou d’un identifiant acheteur (BT-48 ou BT-47) en déclenche une autre. Ces deux erreurs sont parmi les plus fréquentes sur les factures de sous-traitance.
Avoir / note de crédit
Un avoir utilise le typeCode 381 au lieu de 380. Les montants suivent la convention positive — l’avoir représente un montant à restituer, les lignes et totaux sont positifs.
{
"invoiceNumber": "AV-2026-007",
"issueDate": "20260415",
"typeCode": "381",
"currencyCode": "EUR",
"precedingInvoiceReference": "FA-2026-042",
...
}
Le champ precedingInvoiceReference (BT-25) permet de rattacher l’avoir à la facture d’origine. Ce lien n’est pas obligatoire dans le noyau EN16931, mais il est fortement recommandé pour la traçabilité et peut devenir requis par certaines PDP.
Multi-taux TVA
Quand une facture mélange des taux différents (20% sur les prestations, 5.5% sur les matériaux), chaque ligne doit être rattachée au bon taux, et le taxBreakdown doit ventiler les montants par catégorie/taux :
"lines": [
{
"description": "Main d'oeuvre — pose carrelage",
"quantity": 20,
"unitCode": "HUR",
"unitPrice": 45.00,
"vatRate": 20,
"vatCategory": "S"
},
{
"description": "Fourniture carrelage grès cérame",
"quantity": 25,
"unitCode": "MTK",
"unitPrice": 32.00,
"vatRate": 5.5,
"vatCategory": "S"
}
],
"taxBreakdown": [
{ "vatCategory": "S", "vatRate": 20, "taxableAmount": 900.00, "taxAmount": 180.00 },
{ "vatCategory": "S", "vatRate": 5.5, "taxableAmount": 800.00, "taxAmount": 44.00 }
],
"totals": {
"netAmount": 1700.00,
"vatAmount": 224.00,
"grossAmount": 1924.00,
"dueAmount": 1924.00
}
La règle BR-CO-17 vérifie la cohérence de chaque entrée du taxBreakdown. La règle BR-CO-15 vérifie que grossAmount = netAmount + vatAmount. Un seul centime d’écart provoque un rejet.
Exemple complet : facture de sous-traitance BTP en autoliquidation
Voici un JSON invoice_data réaliste pour une facture de sous-traitance avec autoliquidation, deux lignes de prestation, SIRET et TVA intracommunautaire.
{
"invoiceNumber": "FA-2026-158",
"issueDate": "20260401",
"typeCode": "380",
"currencyCode": "EUR",
"seller": {
"name": "Dupont BTP SAS",
"vatId": "FR32123456789",
"legalId": "12345678901234",
"address": {
"street": "45 Avenue des Chantiers",
"city": "Lyon",
"postalCode": "69003",
"country": "FR"
}
},
"buyer": {
"name": "Grands Travaux Rhône SA",
"vatId": "FR87987654321",
"legalId": "98765432109876",
"address": {
"street": "12 Rue de la République",
"city": "Lyon",
"postalCode": "69002",
"country": "FR"
}
},
"lines": [
{
"description": "Pose cloisons sèches — Lot 3 chantier Bellecour",
"quantity": 120,
"unitCode": "HUR",
"unitPrice": 48.00,
"vatRate": 0,
"vatCategory": "AE"
},
{
"description": "Fourniture et pose faux plafonds — Lot 3 chantier Bellecour",
"quantity": 85,
"unitCode": "MTK",
"unitPrice": 35.00,
"vatRate": 0,
"vatCategory": "AE"
}
],
"taxBreakdown": [
{
"vatCategory": "AE",
"vatRate": 0,
"taxableAmount": 8735.00,
"taxAmount": 0.00,
"taxExemptionReason": "Autoliquidation - Sous-traitance BTP, article 283, 2 nonies du CGI"
}
],
"totals": {
"netAmount": 8735.00,
"vatAmount": 0.00,
"grossAmount": 8735.00,
"dueAmount": 8735.00
}
}
Les montants se vérifient : ligne 1 (120 x 48.00 = 5 760.00) + ligne 2 (85 x 35.00 = 2 975.00) = 8 735.00 = netAmount. TVA à 0 (autoliquidation), donc grossAmount = netAmount.
Appel curl
curl -X POST https://api.facturxapi.com/api/v1/convert \
-H "X-API-Key: votre-cle-api" \
-F "file=@facture-btp.pdf" \
-F 'invoice_data={
"invoiceNumber": "FA-2026-158",
"issueDate": "20260401",
"typeCode": "380",
"currencyCode": "EUR",
"seller": {
"name": "Dupont BTP SAS",
"vatId": "FR32123456789",
"legalId": "12345678901234",
"address": {
"street": "45 Avenue des Chantiers",
"city": "Lyon",
"postalCode": "69003",
"country": "FR"
}
},
"buyer": {
"name": "Grands Travaux Rhône SA",
"vatId": "FR87987654321",
"legalId": "98765432109876",
"address": {
"street": "12 Rue de la République",
"city": "Lyon",
"postalCode": "69002",
"country": "FR"
}
},
"lines": [
{
"description": "Pose cloisons sèches — Lot 3 chantier Bellecour",
"quantity": 120,
"unitCode": "HUR",
"unitPrice": 48.00,
"vatRate": 0,
"vatCategory": "AE"
},
{
"description": "Fourniture et pose faux plafonds — Lot 3 chantier Bellecour",
"quantity": 85,
"unitCode": "MTK",
"unitPrice": 35.00,
"vatRate": 0,
"vatCategory": "AE"
}
],
"taxBreakdown": [
{
"vatCategory": "AE",
"vatRate": 0,
"taxableAmount": 8735.00,
"taxAmount": 0.00,
"taxExemptionReason": "Autoliquidation - Sous-traitance BTP, article 283, 2 nonies du CGI"
}
],
"totals": {
"netAmount": 8735.00,
"vatAmount": 0.00,
"grossAmount": 8735.00,
"dueAmount": 8735.00
}
}'
Réponse attendue
{
"durationMs": 2800,
"targetProfile": "EN16931",
"conversionSuccessful": true,
"xml": "PD94bWwg...",
"xmlSize": 5120,
"pdf": "JVBERi0x...",
"pdfSize": 115200,
"extraction": {
"sourceType": "structured_data",
"pageCount": 1
},
"validation": {
"valid": true,
"profile": "EN16931",
"summary": { "errorCount": 0, "warningCount": 0 }
}
}
Le sourceType: "structured_data" confirme que les données viennent du JSON invoice_data et non d’une extraction PDF. La validation intégrée confirme la conformité EN16931 sans erreur.
Validation des données avant conversion
L’API valide les données ERP avant de générer le XML CII. Si une incohérence est détectée, elle retourne un code 422 avec un diagnostic précis avant même de toucher au PDF.
Erreurs courantes côté ERP
| Erreur | Cause ERP typique | Diagnostic API |
|---|---|---|
totals.netAmount != somme des lignes | Arrondi ou ligne oubliée dans l’export | arithmetic_mismatch: netAmount |
Identifiant fiscal absent avec catégorie AE | Champ TVA ou identifiant légal non mappé dans l’export ERP | missing_field: seller tax identifier (required for AE) |
vatRate > 0 avec catégorie AE | Code TVA ERP mal converti | invalid_combination: AE with vatRate > 0 |
taxBreakdown incohérent avec les lignes | Ventilation TVA calculée indépendamment des lignes | tax_breakdown_mismatch |
unitCode invalide | Label en clair au lieu du code UN/ECE | invalid_unit_code |
Recommandation : valider côté ERP avant d’envoyer
Plutôt que de découvrir les erreurs via l’API, implémentez les vérifications en amont dans votre pipeline ERP :
- Cohérence arithmétique — somme des lignes (quantity x unitPrice) = netAmount, netAmount + vatAmount = grossAmount
- Complétude des identifiants — au moins un identifiant vendeur (vatId ou legalId), code pays présent
- Codes normalisés — vatCategory parmi S, Z, E, AE, K, G, O ; unitCode valide UN/ECE Rec 20 ; currencyCode ISO 4217
- Cohérence TVA — si vatCategory = “AE”, alors vatRate = 0 et taxExemptionReason présent
Cela réduit les allers-retours avec l’API et accélère le flux de production. Les erreurs de format (dates, décimaux) peuvent être corrigées automatiquement — voir Corriger automatiquement un XML CII invalide.
Aller plus loin
- Champs obligatoires EN16931 — la cartographie complète des Business Terms, avec XPaths CII et erreurs Schematron associées : Champs obligatoires EN16931 : cartographie et mapping ERP
- Profils Factur-X — le choix du profil détermine quels champs sont obligatoires dans le XML. EN16931 est recommandé pour le B2B : Profils Factur-X : MINIMUM → EXTENDED
- Catalogue d’erreurs BR-* — référence consultable de chaque règle Schematron avec XML invalide, XML corrigé et pièges : Catalogue des erreurs BR-* EN16931
- Conversion PDF vers Factur-X — les deux modes (extraction PDF et données ERP), la validation intégrée, les quotas : Convertir une facture PDF en Factur-X
- Validation Schematron — comprendre les règles XSD vs Schematron et les déboguer : Valider EN16931/Factur-X : XSD vs Schematron
- Documentation API — endpoints, formats de réponse, exemples de code : Documentation complète