API REST à intégrer dans votre workflow d'export — pas un plugin maintenu par FacturX API.

Brancher Dolibarr à un moteur Factur-X EN16931 via API REST

Intégrateurs Dolibarr, éditeurs et ESN métier : appelez FacturX API depuis un module ou un hook Dolibarr pour diagnostiquer un export, transformer un PDF en Factur-X avec compléments invoice_data, réparer un XML CII récupérable ou extraire le XML d'un Factur-X reçu — avant remise au parcours PA/SC du client.

API REST appelable depuis un module ou un hook Dolibarr (PHP)
Mode invoice_data JSON pour compléter SIREN, schemeID, taux TVA absents de l'export
Liberté du choix de Plateforme Agréée — FacturX API n'est pas PA

Exemple cURL /convert

multipart/form-data — /convert + invoice_data JSON
set -euo pipefail
FACTURX_FILE='./facture-dolibarr.pdf'
FACTURX_OUTPUT='facturx_pdfa3'
FACTURX_VALIDATION_TARGET='en16931'
FACTURX_INVOICE_DATA='{"invoice_number":"FA-2026-042","issue_date":"2026-04-01","invoice_type":"380","currency":"EUR","seller":{"name":"Ma Societe SAS","siret":"10000000900017","vat_id":"FR88100000009","address":{"street":"10 rue de Rivoli","city":"Paris","postal_code":"75001","country":"FR"}},"buyer":{"name":"Client SA","siret":"10000001700010","address":{"street":"20 rue de la Republique","city":"Lyon","postal_code":"69002","country":"FR"}},"references":{"buyer_reference":"SERVICE-ACHATS","purchase_order_reference":"PO-2026-0017","contract_reference":"CTR-2026-04"},"totals":{"net":"970.00","tax":"194.00","gross":"1164.00","prepaid_amount":"100.00","rounding_amount":"0.00","due":"1064.00"},"tax_breakdown":[{"rate":"20.00","category":"S","base":"970.00","amount":"194.00"}],"line_items":[{"number":"1","description":"Prestation conseil","quantity":"10","unit":"C62","unit_price":"100.00","net_amount":"970.00","vat_rate":"20.00","vat_category":"S","purchase_order_line_reference":"10","gross_unit_price":"120.00","price_discount":"20.00","allowances":[{"amount":"50.00","reason":"Remise ligne","reason_code":"95"}],"charges":[{"amount":"20.00","reason":"Supplement urgent"}]}],"payment":{"due_date":"2026-05-01","terms":"Paiement a 30 jours","iban":"FR7630006000011234567890189"},"delivery":{"date":"2026-04-01","address":{"street":"20 rue de la Republique","city":"Lyon","postal_code":"69002","country":"FR"}},"invoicing_period":{"start_date":"2026-04-01","end_date":"2026-04-30"}}'
test -f "$FACTURX_FILE" && test -r "$FACTURX_FILE"
FACTURX_FILE_SNAPSHOT=$(mktemp "${TMPDIR:-/tmp}/facturx-upload.XXXXXX.pdf")
trap 'rm -f "$FACTURX_FILE_SNAPSHOT"' EXIT
cp -- "$FACTURX_FILE" "$FACTURX_FILE_SNAPSHOT"
FACTURX_FILE_DIGEST=$(openssl dgst -sha256 -r "$FACTURX_FILE_SNAPSHOT" | awk '{print $1}')
printf '%s' "$FACTURX_FILE_DIGEST" | grep -Eq '^[0-9a-fA-F]{64}$'
FACTURX_OPERATION_IDENTITY=$(printf '%s\0%s\0%s\0%s'   "$FACTURX_OUTPUT" "$FACTURX_VALIDATION_TARGET" "$FACTURX_INVOICE_DATA" "$FACTURX_FILE_DIGEST"   | openssl dgst -sha256 -r | awk '{print $1}')
FACTURX_IDEMPOTENCY_KEY="convert-$FACTURX_OPERATION_IDENTITY"
printf '%s' "$FACTURX_OPERATION_IDENTITY" | grep -Eq '^[0-9a-fA-F]{64}$'

curl -X POST https://api.facturxapi.com/api/v1/convert \
  -H "Authorization: Bearer $FACTURX_API_KEY" \
  -H "Idempotency-Key: $FACTURX_IDEMPOTENCY_KEY" \
  -F "file=@$FACTURX_FILE_SNAPSHOT" \
  -F "output=$FACTURX_OUTPUT" \
  -F "validation_target=$FACTURX_VALIDATION_TARGET" \
  -F "invoice_data=$FACTURX_INVOICE_DATA"

Snippet Dolibarr

Hook Dolibarr — appel /api/v1/convert
<?php

/**
 * Hook Dolibarr custom — appel FacturX API /convert
 * Place ce code dans un module Dolibarr custom (htdocs/custom/yourmodule/)
 * et déclenche-le depuis BILL_VALIDATE ou un cron.
 */

use Symfony\Component\HttpClient\HttpClient;

// FACTURX_OPERATION_KEY_START
function facturx_operation_key(string $output, string $target, string $invoiceData, string $fileDigest = ''): string
{
    return 'convert-' . hash('sha256', implode("\0", [$output, $target, $invoiceData, $fileDigest]));
}
// FACTURX_OPERATION_KEY_END

function facturx_convert_dolibarr_invoice(string $pdfPath, array $invoice): array
{
    // Dans un module réel, construisez ce JSON depuis la facture Dolibarr.
    // Gardez toutes les racines : seller, buyer, totals, tax_breakdown, line_items.
    $invoiceData = json_encode($invoice, JSON_THROW_ON_ERROR);
    $output = 'facturx_pdfa3';
    $validationTarget = 'en16931';
    if (! is_file($pdfPath) || ! is_readable($pdfPath)) {
        throw new RuntimeException('Le PDF source est absent ou illisible');
    }
    $pdfSnapshotPath = tempnam(sys_get_temp_dir(), 'facturx-upload-');
    if ($pdfSnapshotPath === false) {
        throw new RuntimeException('Impossible de réserver le snapshot PDF à envoyer');
    }
    $pdfStream = null;

    try {
        if (! copy($pdfPath, $pdfSnapshotPath)) {
            throw new RuntimeException('Impossible de créer le snapshot PDF à envoyer');
        }
        $idempotencyKey = facturx_operation_key(
            $output,
            $validationTarget,
            $invoiceData,
            hash_file('sha256', $pdfSnapshotPath)
        );

        $client = HttpClient::create([
            'timeout' => 20,
            'headers' => [
                'Authorization' => 'Bearer ' . getenv('FACTURX_API_KEY'),
                'Accept-Language' => 'fr',
                'Idempotency-Key' => $idempotencyKey,
            ],
        ]);

        $pdfStream = fopen($pdfSnapshotPath, 'r');
        if ($pdfStream === false) {
            throw new RuntimeException('Impossible de lire le snapshot PDF à envoyer');
        }
        $response = $client->request('POST', 'https://api.facturxapi.com/api/v1/convert', [
            'body' => [
                'file' => $pdfStream,
                'output' => $output,
                'validation_target' => $validationTarget,
                'invoice_data' => $invoiceData,
            ],
        ]);

        return $response->toArray(false);
    } finally {
        if (is_resource($pdfStream)) {
            fclose($pdfStream);
        }
        if (is_file($pdfSnapshotPath)) {
            unlink($pdfSnapshotPath);
        }
    }
}

Parcours conseillé — générer puis contrôler

Commencez par /convert pour produire un livrable Factur-X contrôlé, puis utilisez /validate comme précontrôle ou contrôle indépendant.

POST /api/v1/convert

PDF → Factur-X PDF/A-3

Génère un Factur-X PDF/A-3 à partir d'un PDF visuel et de données invoice_data. Les livrables ne sont exposés que si la cible demandée est vérifiée.

FACTURX_OUTPUT='facturx_pdfa3'
FACTURX_VALIDATION_TARGET='en16931'
FACTURX_INVOICE_DATA='{"invoice_number":"FA-2026-042","issue_date":"2026-04-01","invoice_type":"380","currency":"EUR","seller":{"name":"Ma Societe SAS","siret":"10000000900017","vat_id":"FR88100000009","address":{"street":"10 rue de Rivoli","city":"Paris","postal_code":"75001","country":"FR"}},"buyer":{"name":"Client SA","siret":"10000001700010","address":{"street":"20 rue de la Republique","city":"Lyon","postal_code":"69002","country":"FR"}},"references":{"buyer_reference":"SERVICE-ACHATS","purchase_order_reference":"PO-2026-0017","contract_reference":"CTR-2026-04"},"totals":{"net":"970.00","tax":"194.00","gross":"1164.00","prepaid_amount":"100.00","rounding_amount":"0.00","due":"1064.00"},"tax_breakdown":[{"rate":"20.00","category":"S","base":"970.00","amount":"194.00"}],"line_items":[{"number":"1","description":"Prestation conseil","quantity":"10","unit":"C62","unit_price":"100.00","net_amount":"970.00","vat_rate":"20.00","vat_category":"S","purchase_order_line_reference":"10","gross_unit_price":"120.00","price_discount":"20.00","allowances":[{"amount":"50.00","reason":"Remise ligne","reason_code":"95"}],"charges":[{"amount":"20.00","reason":"Supplement urgent"}]}],"payment":{"due_date":"2026-05-01","terms":"Paiement a 30 jours","iban":"FR7630006000011234567890189"},"delivery":{"date":"2026-04-01","address":{"street":"20 rue de la Republique","city":"Lyon","postal_code":"69002","country":"FR"}},"invoicing_period":{"start_date":"2026-04-01","end_date":"2026-04-30"}}'
FACTURX_OPERATION_IDENTITY=$(printf '%s\0%s\0%s'   "$FACTURX_OUTPUT" "$FACTURX_VALIDATION_TARGET" "$FACTURX_INVOICE_DATA"   | openssl dgst -sha256 -r | awk '{print $1}')
FACTURX_IDEMPOTENCY_KEY="convert-$FACTURX_OPERATION_IDENTITY"

curl -X POST https://api.facturxapi.com/api/v1/convert \
  -H "Authorization: Bearer $KEY" \
  -H "Accept-Language: fr" \
  -H "Idempotency-Key: $FACTURX_IDEMPOTENCY_KEY" \
  -F "output=$FACTURX_OUTPUT" \
  -F "validation_target=$FACTURX_VALIDATION_TARGET" \
  -F "invoice_data=$FACTURX_INVOICE_DATA"

POST /api/v1/validate

Précontrôle technique

Contrôle un PDF Factur-X ou un XML CII déjà produit. Retourne un rapport JSON structuré avec codes BR-* par ligne/champ.

curl -X POST https://api.facturxapi.com/api/v1/validate?validation_target=en16931 \
  -H "Authorization: Bearer $KEY" \
  -F "file=@./facture.pdf"

POST /api/v1/extract

XML CII embarqué → JSON

Extrait le XML CII d'un PDF Factur-X reçu. Paramètre validate=true combine extraction + validation en une requête.

curl -X POST "https://api.facturxapi.com/api/v1/extract?validate=true&lang=fr" \
  -H "Authorization: Bearer $KEY" \
  -F "file=@./facture-recue.pdf"

POST /api/v1/repair

Corrections déterministes

Corrige automatiquement les erreurs réparables d'un XML CII (dates, décimaux, namespaces, schemeID). Retour : diff + XML réparé.

curl -X POST https://api.facturxapi.com/api/v1/repair \
  -H "Authorization: Bearer $KEY" \
  -F "file=@./facture-invalide.xml"

Checklist intégration

  • Stocker FACTURX_API_KEY hors du dépôt Dolibarr (vault, env serveur, conf/conf.php override)

  • Appeler FacturX API depuis un hook BILL_VALIDATE ou un cron, pas dans la transaction métier

  • Conserver le request_id retourné pour corréler avec vos logs Dolibarr (rowid facture)

  • Pour les exports incomplets, compléter via invoice_data JSON plutôt que de modifier le générateur PDF Dolibarr

Retries & timeouts

Configurez un retry exponentiel (max 3 tentatives) côté module Dolibarr sur 429/502, et traitez 402 (quota) comme un signal business — pas comme une erreur transitoire.

  • • Timeout HttpClient recommandé : 20 s (PDF + Schematron peuvent monter à 10 s sur gros PDF)
  • • Backoff : 1s, 3s, 9s — utiliser le retry intégré de Symfony HttpClient
  • • Réutiliser exactement la même Idempotency-Key seulement pour la même opération
  • • Tracer request_id dans la table llx_facture_extrafields pour audit ultérieur

Erreurs fréquentes

Mappez vos logs sans confondre codes API publics, exceptions client locales et règles métier EN16931.

Règle EN16931

BR-CO-26

Aucun identifiant vendeur (BT-29, BT-30, BT-31) présent. Cas fréquent sur les exports Dolibarr où le SIREN société est vide ou son schemeID="0002" absent.

💡 Renseigner le SIREN dans Société -> Configuration générale, OU compléter via invoice_data.seller.siren au moment de l’appel /convert.

Règle EN16931

BR-CO-15

Somme des lignes différente du total HT déclaré. Lié aux arrondis multi-taux TVA dans Dolibarr.

💡 Vérifier la précision monétaire MAIN_MAX_DECIMALS_UNIT et MAIN_MAX_DECIMALS_TOT avant de relancer /validate.

Code API public

422 invalid_invoice_data

Le JSON invoice_data envoyé à /convert ne respecte pas le contrat public.

💡 Valider les champs localement et envoyer invoice_data comme champ texte JSON du multipart.

Code API public

402 quota_exceeded

Sandbox saturé.

💡 Passer sur Launch ou cadrer un Pilote accompagné. Surfacer le warning côté Dolibarr via Notifications module.

FAQ

Est-ce un plugin Factur-X officiel pour Dolibarr ?

Non. FacturX API ne distribue pas de module DoliStore. C'est une API REST que vous appelez depuis un module Dolibarr custom ou un hook. Si vous cherchez un module communautaire à configurer, voir notre guide /blog/dolibarr-facturx-2026-module-validation.

Faut-il modifier l'export PDF de Dolibarr pour utiliser FacturX API ?

Non. Vous envoyez le PDF tel que généré par Dolibarr et complétez les champs manquants via le paramètre invoice_data JSON de /convert. Aucun fork du générateur Dolibarr n'est requis.

FacturX API est-elle une Plateforme Agréée (PA) ?

Non. FacturX API est un moteur de diagnostic, conversion et réparation EN16931. L'envoi réglementaire à l'administration et au destinataire reste à la charge de la Plateforme Agréée choisie par votre client final.

FacturX API archive-t-elle mes factures ?

Non. Pas d'archivage légal, pas de valeur probante NF Z42-013. Les fichiers transitent en mémoire et ne sont pas stockés. L'archivage légal reste de la responsabilité de votre PA et de votre solution d'archivage.

Mon client est-il obligé de choisir une PA spécifique ?

Non. FacturX API n'impose aucune Plateforme Agréée — votre client garde la main sur ce choix. Notre brique technique se branche en amont, avant l'envoi réglementaire.

URN, XSD et Schematron Factur-X

Référence rapide des profils, URN canoniques et règles Schematron EN16931.

Dolibarr & Factur-X 2026 (guide)

Configurer un module Factur-X communautaire et corriger les erreurs EN16931 les plus fréquentes.

France CTC / EN16931

Comprendre la séparation socle européen / profil Factur-X / contraintes françaises.