Aller au contenu
gaetancottrez.dev

Factur-X, UBL, CII : le guide du développeur qui doit produire (ou lire) des factures électroniques

Publié: at 08:00 | (7 min de lecture)
Factur-X, UBL, CII : le guide du développeur qui doit produire (ou lire) des factures électroniques

Table des matières

Ouvrir table des matières

Trois formats, une seule sémantique

Dans l’épisode 1 de cette série, on a posé le décor de la réforme : à partir du 1er septembre 2026, les factures B2B françaises circulent via des plateformes agréées, dans des formats structurés. Aujourd’hui, on ouvre le capot de ces formats — parce que c’est la première chose que votre code va toucher.

Le socle de la réforme repose sur trois formats, et la meilleure façon de ne pas s’y perdre est de comprendre d’emblée ceci : ce sont trois syntaxes pour une même sémantique. La sémantique, c’est la norme européenne EN 16931 : elle définit ce que contient une facture électronique — les champs, leurs significations, leurs règles de gestion. Les formats définissent comment ces champs s’écrivent sur le fil. Une fois cette séparation en tête, tout le reste devient de la traduction.

Les trois candidats :

Première conséquence pratique : arrêtez de penser « quel format vais-je choisir ? » comme si c’était un mariage. Votre code devrait raisonner sur un modèle interne aligné sur la sémantique EN 16931, avec des adaptateurs de sérialisation vers UBL, CII ou Factur-X selon le canal. Les habitués de l’architecture hexagonale reconnaîtront le refrain : le format est un détail de la frontière, pas le cœur du domaine.

Factur-X de près : un PDF qui cache bien son jeu

Factur-X mérite qu’on s’y attarde, parce que son astuce est élégante : le fichier est un PDF/A-3 — une variante d’archivage du PDF qui autorise les pièces jointes embarquées — et la facture structurée est un XML CII attaché à l’intérieur du PDF. L’humain ouvre le PDF et lit sa facture ; la machine extrait le XML et l’intègre sans OCR. Deux publics, un seul fichier.

Le standard définit cinq profils de richesse croissante — MINIMUM (les données minimales), BASIC WL (en-tête et pied, sans lignes), BASIC (avec les lignes essentielles), EN 16931 (l’intégralité de la norme européenne) et EXTENDED (la norme « augmentée de données additionnelles »). Le profil est déclaré dans les métadonnées : votre parseur doit le lire avant de décider ce qu’il a le droit d’attendre du fichier.

Côté code, l’extraction n’a rien de sorcier — l’XML est une pièce jointe nommée de façon normalisée :

// Extraction du XML embarqué d'un Factur-X (pseudo-code avec une lib PDF)
import { PDFDocument, PDFName } from "pdf-lib-de-votre-choix";

async function extractFacturXml(pdfBytes: Uint8Array): Promise<string | null> {
  const doc = await PDFDocument.load(pdfBytes);
  const attachments = doc.getAttachments(); // les pièces jointes du PDF/A-3
  const xml = attachments.find(
    a =>
      a.name === "factur-x.xml" ||
      a.name === "xrechnung.xml" ||
      a.name.endsWith(".xml")
  );
  return xml ? new TextDecoder("utf-8").decode(xml.data) : null;
}

Et le piège symétrique, que vous éviterez désormais : un PDF ordinaire n’est pas une facture électronique. Un PDF « image », un PDF texte sans XML embarqué — même très joli, même signé — ne satisfait pas le circuit de la réforme. Le test n’est pas « est-ce un PDF ? » mais « y a-t-il des données structurées conformes dedans ? ».

Valider une facture : deux étages, pas un

Deuxième réflexe à installer : la validation d’une facture électronique se joue à deux étages, et confondre les deux coûte cher.

Étage 1 — la syntaxe. Le fichier est-il un XML bien formé, conforme au schéma de son format ? C’est le travail des XSD — et bonne nouvelle, les spécifications externes publiées sur impots.gouv.fr incluent les XSD dans leur dossier (version 3.2 au moment où j’écris). C’est mécanique, rapide, et ça attrape les erreurs de plomberie.

Étage 2 — les règles métier. Un XML syntaxiquement parfait peut être une facture invalide : total qui ne correspond pas à la somme des lignes, TVA incohérente, champ obligatoire pour tel cas d’usage manquant… Ces règles-là s’expriment traditionnellement en Schematron (des assertions XPath sur le document), et l’écosystème EN 16931 en publie des jeux officiels. Votre pipeline doit passer les deux étages, dans cet ordre — et restituer des erreurs actionnables : « BT-112 incohérent » ne parle à personne ; « le total TTC (ligne X) ne correspond pas à la somme des lignes » sauve votre support.

Au passage, vous croiserez partout les identifiants BT-n (Business Terms) et BG-n (Business Groups) : c’est la nomenclature des champs de l’EN 16931. « BT-1 » est le numéro de facture quel que soit le format de sérialisation. Adoptez cette nomenclature dans vos messages d’erreur et vos mappings internes — c’est la lingua franca du domaine, et vos interlocuteurs plateforme la parlent couramment.

Valider une facture : deux étages

Lequel émettre, lesquels accepter ?

La question stratégique, maintenant. En réception, la réponse est simple et non négociable : les trois. Vous ne choisissez pas ce que vos partenaires vous envoient — le socle de la réforme les autorise tous, votre intégration doit tous les avaler.

En émission, quelques repères de praticien :

Et si vous êtes éditeur avec un modèle interne propre : mappez-le une bonne fois vers la sémantique EN 16931 (les BT/BG), puis générez chaque syntaxe depuis ce pivot. Un pivot, N sérialiseurs, des tests de non-régression par profil — c’est l’architecture qui vieillit bien.

Épilogue

Retenez trois choses. Un : trois formats, une sémantique — pensez EN 16931 d’abord, syntaxe ensuite. Deux : Factur-X est un PDF/A-3 avec un XML CII embarqué, décliné en cinq profils — lisez le profil avant de lire la facture. Trois : validez à deux étages, XSD puis règles métier, et parlez BT/BG dans vos erreurs.

La suite logique : Intégrer une plateforme agréée : par où commencer — parce qu’un beau fichier ne sert à rien tant qu’il ne circule pas. Et si le sujet devient un chantier chez vous, mon expérience de terrain est résumée sur gaetancottrez.dev/facturation-electronique 🔗.

Des questions sur un cas de mapping tordu ? En commentaire — je me ferai une joie de vous répondre.


Sources (consultées en août 2026) : Factur-X — FNFE-MPE 🔗 (standard, profils, version 1.09.2) · Spécifications externes et normes 🔗 (impots.gouv.fr — dossier v3.2, XSD, normes XP Z12-012/-013/-014).

Vous pourriez aussi aimer

La facturation électronique expliquée aux développeurs : ce qui change vraiment le 1er septembre 2026

La facturation électronique expliquée aux développeurs : ce qui change vraiment le 1er septembre 2026

Mettre en place une CI GitHub Actions

Mettre en place une CI GitHub Actions

Article suivant
La facturation électronique expliquée aux développeurs : ce qui change vraiment le 1er septembre 2026