POST /v1/extract — exemples par langage

Périmètre : Factur-X (PDF/A-3 + CII embarqué) et CII XML autonome uniquement. L'extraction UBL n'est pas encore couverte — elle arrive avec Epic 6. Soumettre un fichier UBL à cet endpoint échoue avec un 422 (« CII invalide ou mal formé »), pas une extraction UBL déguisée.

Requête : le document (PDF Factur-X ou XML CII) brut en corps. Réponse : JSON au même schéma que l'entrée de POST /v1/generate/facturx (aller-retour symétrique, FR-6), enrichi de digitallySigned/signatureVerified.

Exemple complet — Factur-X (PDF)

curl

curl -X POST "https://api.example/v1/extract" \
  -H "Authorization: Bearer $FACTURX_API_KEY" \
  --data-binary @facture.pdf

Réponse :

{
  "invoice": {
    "invoiceNumber": "F-2026-001",
    "issueDate": "2026-07-21",
    "currencyCode": "EUR",
    "invoiceTypeCode": "380",
    "seller": { "name": "Vendeur SARL", "street": "", "city": "", "postalCode": "", "countryCode": "" },
    "buyer": { "name": "Acheteur SAS", "street": "", "city": "", "postalCode": "", "countryCode": "" },
    "lines": [{ "id": "1", "itemName": "Prestation", "quantity": 1, "unitPrice": 100, "vatRate": 20 }],
    "vatBreakdown": [{ "category": "S", "taxableAmount": 100, "vatAmount": 20 }],
    "totals": { "totalWithoutVat": 100, "totalVat": 20, "totalWithVat": 120, "amountDue": 120 }
  },
  "digitallySigned": false,
  "signatureVerified": false
}

PHP

<?php
$ch = curl_init('https://api.example/v1/extract');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('FACTURX_API_KEY')],
    CURLOPT_POSTFIELDS => file_get_contents('facture.pdf'),
    CURLOPT_RETURNTRANSFER => true,
]);
$result = json_decode(curl_exec($ch), true);
echo $result['invoice']['invoiceNumber'] . "\n";

Python

import requests, os

with open("facture.pdf", "rb") as f:
    resp = requests.post(
        "https://api.example/v1/extract",
        headers={"Authorization": f"Bearer {os.environ['FACTURX_API_KEY']}"},
        data=f,
    )
result = resp.json()
print(result["invoice"]["invoiceNumber"], "signé:", result["digitallySigned"])

JavaScript (Node.js)

import { readFile } from "node:fs/promises";

const pdf = await readFile("facture.pdf");
const resp = await fetch("https://api.example/v1/extract", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.FACTURX_API_KEY}` },
  body: pdf,
});
const result = await resp.json();
console.log(result.invoice.invoiceNumber, "signé:", result.digitallySigned);

Go

package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
)

func main() {
	f, _ := os.Open("facture.pdf")
	defer f.Close()

	req, _ := http.NewRequest(http.MethodPost, "https://api.example/v1/extract", f)
	req.Header.Set("Authorization", "Bearer "+os.Getenv("FACTURX_API_KEY"))

	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()

	var result struct {
		Invoice struct {
			InvoiceNumber string `json:"invoiceNumber"`
		} `json:"invoice"`
		DigitallySigned bool `json:"digitallySigned"`
	}
	json.NewDecoder(resp.Body).Decode(&result)
	fmt.Println(result.Invoice.InvoiceNumber, "signé:", result.DigitallySigned)
}

Exemple complet — CII XML autonome

Même endpoint, corps XML brut au lieu d'un PDF — utile si votre plateforme agréée vous livre déjà le CII sans l'emballage PDF/A-3 :

curl -X POST "https://api.example/v1/extract" \
  -H "Authorization: Bearer $FACTURX_API_KEY" \
  -H "Content-Type: application/xml" \
  --data-binary @facture-cii.xml

La réponse suit exactement le même schéma que l'exemple PDF ci-dessus (digitallySigned est toujours false pour un CII XML autonome — la notion de signature électronique s'applique au PDF, pas au XML).

Erreurs

Code Cause Exemple type (RFC 7807)
422 PDF chiffré ou corrompu corrupted-pdf
422 PDF valide mais sans pièce jointe CII (pas un Factur-X) no-cii-attachment
422 CII mal formé ou XML invalide malformed-cii
413 Document > 20 Mo — rejeté avant tout parsing
{
  "type": "no-cii-attachment",
  "title": "Aucun CII embarqué trouvé",
  "status": 422,
  "detail": "ce PDF ne semble pas être un Factur-X (pièce jointe factur-x.xml absente)",
  "instance": "01H..."
}

⚠️ Ces codes ne référencent PAS les règles BR-* officielles (schematron) : contrairement à POST /v1/validate (qui exécute réellement le schematron officiel FNFE-MPE depuis Story 3.7, schematronChecked: true), l'extraction ne signale que des erreurs structurelles (PDF/XML illisible), jamais une non-conformité BR-* — l'extraction décode, elle ne valide pas. Pour vérifier la conformité BR-* d'un document avant de l'extraire, utilisez POST /v1/validate.