La réforme française de la facturation électronique impose, à partir du 1er septembre 2026, l'obligation de recevoir des factures électroniques pour toutes les entreprises assujetties à la TVA, et de les émettre pour les grandes entreprises et ETI (impots.gouv.fr). Pour un développeur, la première brique technique est claire : savoir produire un fichier Factur-X conforme, c'est-à-dire un PDF/A-3 contenant un XML structuré.

Ce tutoriel montre, code à l'appui, comment générer une facture Factur-X en PHP pur puis dans Laravel, avec la librairie open-source horstoeko/zugferd. On couvre le choix du profil, la construction du XML Cross Industry Invoice (CII), l'embarquement dans le PDF/A-3 et l'intégration propre dans une application Eloquent. Contenu neutre, sans vendre d'API : juste le code.

L'essentiel en 5 points

Qu'est-ce qu'une facture Factur-X exactement ?

Factur-X est le format hybride franco-allemand de facture électronique, identique sur le plan technique au format ZUGFeRD côté allemand. Un fichier Factur-X est un PDF/A-3 (norme d'archivage ISO 19005-3) qui autorise l'embarquement de pièces jointes, dans lequel on glisse un fichier XML structuré conforme à la norme européenne EN 16931.

Le XML embarqué suit la syntaxe UN/CEFACT Cross Industry Invoice (CII). Il porte toujours le nom de fichier factur-x.xml et une relation d'association (AFRelationship) de type Data ou Alternative. C'est ce double visage qui rend Factur-X universel : un comptable l'ouvre comme un PDF classique, un logiciel l'analyse comme une donnée structurée.

Les 6 profils Factur-X

Factur-X définit plusieurs profils, du plus léger au plus riche. Le choix du profil détermine quels champs le XML doit contenir.

ProfilDétail des lignesConforme EN 16931Usage type
MINIMUMNonNonDonnées comptables minimales
BASIC WLNon (sans lignes)NonEn-tête seul
BASICOuiOuiFactures simples
EN 16931 (COMFORT)OuiOuiRecommandé B2B France
EXTENDEDOui + données métierOuiCas complexes, multi-pays
XRECHNUNGOuiOuiSecteur public allemand

Notre recommandation : partez sur le profil EN 16931. Il couvre l'écrasante majorité des cas B2B français, contient tous les champs obligatoires et reste accepté par les plateformes partenaires. Réservez EXTENDED aux factures avec données analytiques poussées.

Quelle librairie PHP choisir pour Factur-X ?

Deux librairies open-source dominent l'écosystème PHP. Inutile de payer une API propriétaire pour la seule génération : ces deux projets sont matures, gratuits et largement utilisés en production.

LibrairieLicenceGénérationLecturePDF/A-3
horstoeko/zugferdMITOui (tous profils)OuiOui (builder dédié)
atgp/factur-xMITOuiOuiOui (via fusion PDF)

Nous utilisons horstoeko/zugferd au quotidien : API fluide, support de tous les profils, gestion native de l'export XML et de l'embarquement PDF/A-3 via ZugferdDocumentPdfBuilder. Le dépôt est maintenu activement sur GitHub.

Comment installer horstoeko/zugferd ?

L'installation se fait via Composer. La librairie exige PHP 8.1 ou supérieur et les extensions ext-dom et ext-libxml, présentes par défaut dans la plupart des distributions.

Terminal
# Installation de la librairie de base
composer require horstoeko/zugferd

# Optionnel : visualiseur HTML/PDF pour contrôle
composer require horstoeko/zugferdvisualizer

Comment générer le XML d'une facture Factur-X ?

On construit le document avec ZugferdDocumentBuilder en précisant le profil. On renseigne ensuite l'en-tête (numéro, type, date, devise), le vendeur, l'acheteur, puis chaque ligne avec sa TVA, et enfin les totaux. Voici un exemple complet et fonctionnel.

PHP — génération du XML CII (profil EN 16931)
use horstoeko\zugferd\ZugferdDocumentBuilder;
use horstoeko\zugferd\ZugferdProfiles;
use horstoeko\zugferd\codelists\ZugferdInvoiceType;

// 1. Créer le document avec le profil recommandé
$document = ZugferdDocumentBuilder::createNew(ZugferdProfiles::PROFILE_EN16931);

// 2. En-tête de facture
$document
    ->setDocumentInformation(
        "FA-2026-0001",        // numéro
        ZugferdInvoiceType::INVOICE, // type 380 = facture
        new \DateTime(),            // date d'émission
        "EUR"                       // devise
    )
    // 3. Vendeur (votre société)
    ->setDocumentSeller("Comall Agency", "SIREN-123456789")
    ->addDocumentSellerTaxRegistration("VA", "FR12123456789")
    ->setDocumentSellerAddress("1 rue Exemple", "", "", "44000", "Nantes", "FR")
    // 4. Acheteur (le client)
    ->setDocumentBuyer("Client SAS", "SIREN-987654321")
    ->setDocumentBuyerAddress("5 avenue Test", "", "", "75001", "Paris", "FR");

// 5. Une ligne de prestation
$document
    ->addNewPosition("1")
    ->setDocumentPositionProductDetails("Développement sur-mesure", "", "DEV-01")
    ->setDocumentPositionNetPrice(1000.0)
    ->setDocumentPositionQuantity(1, "C62")        // C62 = unité
    ->addDocumentPositionTax("S", "VAT", 20.0)       // TVA 20 %
    ->setDocumentPositionLineSummation(1000.0);

// 6. TVA et totaux (HT, TVA, TTC)
$document
    ->addDocumentTax("S", "VAT", 1000.0, 200.0, 20.0)
    ->setDocumentSummation(1200.0, 1200.0, 1000.0, 0.0, 0.0, 1000.0, 200.0, null, 0.0);

// 7. Exporter le XML conforme EN 16931
$document->writeFile(__DIR__ . "/factur-x.xml");

À ce stade, vous disposez d'un XML CII valide. Reste à le marier à un PDF lisible pour obtenir le vrai fichier Factur-X.

Comment embarquer le XML dans un PDF/A-3 ?

Factur-X exige un PDF conforme PDF/A-3. Vous générez d'abord la version visuelle de la facture (avec mPDF, TCPDF ou Dompdf en mode PDF/A), puis vous fusionnez le XML grâce à ZugferdDocumentPdfBuilder. La librairie injecte le fichier factur-x.xml et les métadonnées XMP requises.

PHP — fusion XML + PDF/A-3 = Factur-X final
use horstoeko\zugferd\ZugferdDocumentPdfBuilder;

// $document = l'objet ZugferdDocumentBuilder créé plus haut
// "facture-visuelle.pdf" = votre PDF/A-3 lisible (mPDF, TCPDF...)

$pdfBuilder = new ZugferdDocumentPdfBuilder(
    $document,
    __DIR__ . "/facture-visuelle.pdf"
);

$pdfBuilder
    ->generateDocument()
    ->saveDocument(__DIR__ . "/FA-2026-0001-facturx.pdf");

// Résultat : un PDF/A-3 avec factur-x.xml embarqué = Factur-X conforme

Piège fréquent : un PDF généré en mode classique n'est pas du PDF/A-3. Si votre moteur ne produit pas du PDF/A-3, le fichier sera rejeté par les validateurs. Activez explicitement le mode PDF/A-3b dans mPDF ('PDFA' => true) ou TCPDF avant la fusion.

Comment intégrer la génération Factur-X dans Laravel ?

Dans Laravel, on isole la logique dans un service ou une action, résolu par le conteneur. Les données viennent des modèles Eloquent. On boucle sur les lignes de facture, on alimente le builder, puis on stocke le fichier via le disque de stockage Laravel.

PHP — app/Services/FacturXService.php
namespace App\Services;

use App\Models\Invoice;
use horstoeko\zugferd\ZugferdDocumentBuilder;
use horstoeko\zugferd\ZugferdProfiles;
use horstoeko\zugferd\ZugferdDocumentPdfBuilder;
use Illuminate\Support\Facades\Storage;

class FacturXService
{
    public function generate(Invoice $invoice): string
    {
        $doc = ZugferdDocumentBuilder::createNew(ZugferdProfiles::PROFILE_EN16931);

        $doc->setDocumentInformation(
            $invoice->number, "380", $invoice->issued_at, "EUR"
        )
        ->setDocumentSeller(config("company.name"), config("company.siren"))
        ->addDocumentSellerTaxRegistration("VA", config("company.vat"))
        ->setDocumentBuyer($invoice->client->name, $invoice->client->siren);

        // Lignes Eloquent
        foreach ($invoice->lines as $i => $line) {
            $doc->addNewPosition((string)($i + 1))
                ->setDocumentPositionProductDetails($line->label)
                ->setDocumentPositionNetPrice($line->unit_price)
                ->setDocumentPositionQuantity($line->qty, "C62")
                ->addDocumentPositionTax("S", "VAT", $line->vat_rate)
                ->setDocumentPositionLineSummation($line->total_ht);
        }

        $doc->setDocumentSummation(
            $invoice->total_ttc, $invoice->total_ttc,
            $invoice->total_ht, 0.0, 0.0,
            $invoice->total_ht, $invoice->total_vat, null, 0.0
        );

        $pdfPath = Storage::path("invoices/{$invoice->number}.pdf");
        $out     = "invoices/{$invoice->number}-facturx.pdf";

        (new ZugferdDocumentPdfBuilder($doc, $pdfPath))
            ->generateDocument()
            ->saveDocument(Storage::path($out));

        return $out;
    }
}

On appelle ensuite ce service depuis un contrôleur ou un job en file d'attente : app(FacturXService::class)->generate($invoice). La génération étant potentiellement lourde sur de gros volumes, passez par un Job Laravel pour la traiter en arrière-plan.

Comment valider une facture Factur-X générée ?

Ne livrez jamais en production sans validation. Trois contrôles s'imposent avant toute transmission via une plateforme partenaire.

Pour le détail de la lecture et de l'extraction côté réception, consultez notre guide dédié : lire et extraire les données d'un Factur-X en PHP.

Générer le Factur-X suffit-il pour être conforme en 2026 ?

Non, et c'est l'erreur classique. Produire un fichier Factur-X valide est nécessaire mais pas suffisant. À compter du calendrier 2026-2027, les factures entre assujettis français doivent transiter par une Plateforme de Dématérialisation Partenaire (PDP) immatriculée par l'administration fiscale. L'envoi direct par e-mail entre entreprises ne sera plus juridiquement valable.

ÉchéanceRecevoir des e-facturesÉmettre des e-factures
1er sept. 2026Toutes les entreprisesGrandes entreprises & ETI
1er sept. 2027PME & microentreprises

Le développeur doit donc gérer deux briques : la génération du format (ce tutoriel) et le raccordement à une PDP via son API. Sur ce second point, lisez notre article connecter un logiciel métier à une PDP sans devenir PDP.

FAQ : générer du Factur-X en PHP / Laravel

Quelle librairie PHP utiliser pour générer du Factur-X ?

Les deux références open-source sont horstoeko/zugferd et atgp/factur-x. horstoeko/zugferd est la plus complète : tous les profils, lecture et écriture du XML CII, et embarquement PDF/A-3 via ZugferdDocumentPdfBuilder. Elle s'installe via Composer et fonctionne en PHP 8.1+ comme dans Laravel.

Quel profil Factur-X choisir pour la réforme 2026 ?

Le profil EN 16931 (ex-COMFORT) est recommandé : il porte tous les champs obligatoires de la norme européenne et couvre la majorité des cas B2B français. BASIC suffit pour des factures simples, EXTENDED ajoute des données métier. MINIMUM et BASIC WL ne contiennent pas le détail des lignes et sont insuffisants.

Factur-X est-il un PDF ou un XML ?

Les deux. C'est un format hybride : un PDF/A-3 lisible par un humain dans lequel est embarqué un XML structuré Cross Industry Invoice nommé factur-x.xml, lisible par une machine. Ce double visage en fait le format pivot de la facturation électronique française et de son équivalent allemand ZUGFeRD.

Peut-on envoyer directement une facture Factur-X à un client en 2026 ?

Non. Les factures B2B en France doivent transiter par une Plateforme de Dématérialisation Partenaire (PDP) immatriculée. Générer un Factur-X conforme est la première brique, mais l'émission et la réception passent obligatoirement par une PDP. L'envoi direct par e-mail ne sera plus valable entre assujettis.

Comment intégrer la génération Factur-X dans Laravel ?

On encapsule horstoeko/zugferd dans un service injecté via le conteneur. Les données viennent des modèles Eloquent (facture, client, lignes). Le PDF/A-3 lisible se génère avec mPDF ou TCPDF puis se fusionne avec le XML. Le fichier final est stocké via Storage et transmis à la PDP par API, idéalement dans un Job en file d'attente.

Mon développeur est bloqué sur la conformité Factur-X, que faire ?

La difficulté vient rarement du code mais de la cartographie métier : mappage EN 16931, gestion des taux de TVA, choix du profil et connexion à une PDP. ComAll Agency intervient en mission d'intégration : audit, implémentation de la génération et de la lecture Factur-X, raccordement à une plateforme partenaire. Devis gratuit sous 24h.

Conclusion : du fichier conforme à la conformité réelle

Générer une facture Factur-X en PHP ou Laravel est aujourd'hui un problème résolu : la librairie horstoeko/zugferd produit un XML CII valide et l'embarque dans un PDF/A-3 en quelques dizaines de lignes. Le vrai travail d'ingénierie se situe en amont (mappage métier vers les champs EN 16931) et en aval (validation et raccordement à une PDP).

Si votre équipe est bloquée sur l'un de ces maillons, ou si vous devez fiabiliser une chaîne de facturation avant l'échéance du 1er septembre 2026, nous intervenons en mission d'intégration sur-mesure. Demandez un devis gratuit sous 24h.

Bloqué sur l'intégration Factur-X ?

Mission d'intégration sur-mesure : génération, lecture et raccordement PDP. Devis sous 24h.

Demander un devis gratuit →