Guide d'intégration · Python

Générer un Factur-X en Python

Une facture Factur-X n'est pas un PDF avec un logo : c'est un PDF/A-3 qui embarque un XML CII conforme au profil EN 16931, et qui doit passer les contrôles XSD puis Schematron. Voici comment en produire une depuis du Python, et surtout comment savoir qu'elle est réellement valide.

Ce que « conforme » veut dire, concrètement

Trois couches se superposent, et un document peut échouer à n'importe laquelle sans que le PDF ait l'air cassé :

CoucheCe qui est vérifiéSymptôme si ça casse
PDF/A-3Le PDF est archivable et porte une pièce jointe factur-x.xmlLe lecteur du destinataire ne trouve aucune donnée structurée
XSDLe XML CII respecte le schéma (types, ordre, cardinalités)Rejet au dépôt, message technique illisible
SchematronLes règles métier : totaux cohérents, TVA ventilée, mentions légalesRejet avec un code de règle, ex. BR-CO-13

C'est la troisième couche qui pose problème en pratique. Un PDF/A-3 bien formé avec un XML syntaxiquement valide peut très bien annoncer un total TTC qui ne correspond pas à la somme de ses lignes — et sera refusé.

Écrire le XML soi-même, ou appeler une API ?

Les deux approches sont légitimes ; elles n'ont simplement pas le même coût dans le temps.

Bibliothèque localeAPI (Confactura)
Mise en routeConstruire le CII, gérer le PDF/A-3, brancher un moteur SchematronUn POST de votre JSON de facture
ValidationÀ câbler et à maintenir vous-même (Saxon requis pour Schematron)Systématique : un document invalide n'est jamais livré
Évolutions réglementairesVotre veille, vos correctifsCôté serveur
DonnéesRestent chez vousTraitées en Europe, aucune facture stockée
RuntimeUne JVM ou Saxon à opérer en productionAucun

Si votre produit émet quelques factures par an, la bibliothèque suffit. S'il en émet pour vos clients, c'est la maintenance de la conformité qui coûte, pas la première génération.

Générer une facture en Python

Aucune dépendance exotique : un POST JSON, une réponse en octets. Cet exemple utilise httpx, mais requests ou urllib fonctionnent à l'identique.

import httpx

API = "https://confactura.fr"
KEY = "df_live_…"          # POST /v1/signup pour en obtenir une (gratuit)

invoice = {
    "number": "2026-0042",
    "issue_date": "2026-09-01",
    "due_date": "2026-09-30",
    "seller": {
        "name": "Ma Société",
        "address_line": "1 rue X",
        "postcode": "75001",
        "city": "Paris",
        "siren": "123456789",
        "vat_id": "FR32123456789",
        "electronic_address": "[email protected]",
    },
    "buyer": {
        "name": "Client SARL",
        "address_line": "2 av. Y",
        "postcode": "69001",
        "city": "Lyon",
        "electronic_address": "[email protected]",
    },
    "lines": [
        {"description": "Presta dev", "quantity": 5, "unit_price": "450.00"},
    ],
}

r = httpx.post(
    f"{API}/v1/invoices/facturx",
    headers={"X-API-Key": KEY},
    json=invoice,
    timeout=60,
)

if r.status_code == 422:
    # Facture non conforme : rapport détaillé, aucun PDF produit.
    for err in r.json()["errors"]:
        print("règle en échec :", err)
else:
    r.raise_for_status()
    with open("facture-2026-0042.pdf", "wb") as f:
        f.write(r.content)     # PDF/A-3b, XML CII embarqué

Le 422 est une réponse métier, pas une panne

C'est le point le plus important de cette intégration : une facture qui ne passe pas XSD + Schematron n'est jamais livrée. Votre code doit traiter le 422 comme un cas normal — typiquement en le remontant à l'utilisateur qui a saisi la facture — et non comme une erreur serveur à retenter en boucle.

Les champs que la réforme française rend obligatoires

Le profil EN 16931 seul ne suffit pas : le Schematron CTC français ajoute ses propres règles. Trois oublis expliquent la quasi-totalité des 422 au premier essai.

Les mentions légales 2026 — frais de recouvrement, pénalités de retard, escompte, catégorie d'opération — sont ajoutées automatiquement côté serveur. C'est l'objet de la règle BR-FR-05, la plus fréquemment rencontrée par ceux qui construisent leur XML à la main.

Vérifier — sans se croire sur parole

Un PDF qui s'ouvre correctement ne prouve rien du tout. Deux contrôles utiles :

  1. Déposez le fichier produit sur le validateur Factur-X en ligne — gratuit, sans inscription : il ré-extrait le XML embarqué et rejoue XSD + Schematron ;
  2. En intégration continue, faites-le par API :
with open("facture-2026-0042.pdf", "rb") as f:
    report = httpx.post(f"{API}/v1/validate", files={"file": f}).json()

assert report["valid"], report["errors"]

/v1/validate est gratuit, anonyme et ne consomme aucun quota : rien n'empêche de l'appeler à chaque exécution de vos tests.

Récupérer le XML seul

Si vous gardez votre propre mise en page PDF, ou si votre Plateforme Agréée attend du CII brut, POST /v1/invoices/xml renvoie le XML sans le PDF — même corps de requête, mêmes validations.

Essayer maintenant

20 documents par mois gratuits, sans carte bancaire. La clé API est créée en une requête.

Obtenir ma clé API Valider un PDF existant