Utilisez fetch natif (Node 18+) ou Axios, streamez vos PDF, recevez un JSON propre.

Intégrer FacturX API avec Node.js

Fonctionne avec Next.js, NestJS, Cloudflare Workers ou scripts CLI.

Compatibilité TypeScript
Gestion des secrets via process.env ou Cloudflare KV
Idéal pour pipelines serverless

Exemple cURL /convert

multipart/form-data — /convert + invoice_data
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 $FACTURX_API_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"

Snippet Node.js

fetch — génération /api/v1/convert
import { createHash } from 'node:crypto';

// FACTURX_OPERATION_KEY_START
function facturxOperationKey(output: string, target: string, invoiceJson: string, fileDigest = ''): string {
  const operationIdentity = createHash('sha256')
    .update([output, target, invoiceJson, fileDigest].join('\0'))
    .digest('hex');
  return `convert-${operationIdentity}`;
}
// FACTURX_OPERATION_KEY_END

const invoiceData = {
  "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"
  }
} as const;
const output = 'facturx_pdfa3';
const validationTarget = 'en16931';
const invoiceJson = JSON.stringify(invoiceData);
const idempotencyKey = facturxOperationKey(output, validationTarget, invoiceJson);

const response = await fetch('https://api.facturxapi.com/api/v1/convert', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.FACTURX_API_KEY}`,
    'Accept-Language': 'fr',
    'Idempotency-Key': idempotencyKey
  },
  body: await (async () => {
    const form = new FormData();
    form.append('output', output);
    form.append('validation_target', validationTarget);
    form.append('invoice_data', invoiceJson);
    return form;
  })()
});

const payload = await response.json();
if (!payload.success) {
  console.error('Conversion non vérifiée', payload.target, payload.issues);
}

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

  • Toujours lire le stream en mode bufferisé pour éviter les fuites

  • Limiter la taille via formidable/multer

  • Tracer request_id côté observabilité (Datadog, Sentry)

Retries & timeouts

Utilisez p-retry ou ky pour rejouer 429/502 avec jitter.

  • • Timeout fetch : 20 s
  • • Utiliser AbortController pour annuler les validations lentes
  • • Réutiliser exactement la même Idempotency-Key seulement pour la même opération
  • • Logger les erreurs 4xx pour support FacturX

Erreurs fréquentes

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

Code API public

413 file_too_large

PDF au-dessus de la limite acceptée par l’API.

💡 Compressez le scan ou rejetez le fichier avant l’appel API.

Code API public

415 unsupported_media_type

Content-Type ou fichier non accepté par l’API.

💡 Laisser FormData gérer le boundary et les headers multipart.

Règle EN16931

BR-CO-15

Erreur métier EN16931 sur le total TTC.

💡 Afficher issues[].code, issues[].message et le champ concerné pour guider l'équipe finance.

FAQ

Peut-on intégrer dans un worker Cloudflare ?

Oui, utilisez fetch + FormData natif, tout se fait côté edge.

Comment suivre les quotas ?

Sur un succès /convert, exposez les headers X-Quota-Limit, X-Quota-Remaining et X-Quota-Reset quand ils sont présents, et lisez aussi result.processedInvoicesCharged / result.remainingInvoices dans le corps de réponse.

Documentation API

Référence complete

Pricing

Quotas & SLA

Errors library

Codes BR-xx prêts à analyser