POST /v1/extract — examples by language

Scope: Factur-X (PDF/A-3 with embedded CII) and standalone CII XML only. UBL extraction is not yet covered — it arrives with Epic 6. Submitting a UBL file to this endpoint fails with a 422 ("invalid or malformed CII"), not a disguised UBL extraction.

Request: the document (Factur-X PDF or CII XML) as a raw body. Response: JSON in the same schema as the input of POST /v1/generate/facturx (symmetric round-trip, FR-6), enriched with digitallySigned/signatureVerified.

Complete example — Factur-X (PDF)

curl

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

Response:

{
  "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('invoice.pdf'),
    CURLOPT_RETURNTRANSFER => true,
]);
$result = json_decode(curl_exec($ch), true);
echo $result['invoice']['invoiceNumber'] . "\n";

Python

import requests, os

with open("invoice.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"], "signed:", result["digitallySigned"])

JavaScript (Node.js)

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

const pdf = await readFile("invoice.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, "signed:", result.digitallySigned);

Go

package main

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

func main() {
	f, _ := os.Open("invoice.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, "signed:", result.DigitallySigned)
}

Complete example — standalone CII XML

Same endpoint, raw XML body instead of a PDF — useful if your plateforme agréée already delivers the CII without the PDF/A-3 wrapping:

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

The response follows exactly the same schema as the PDF example above (digitallySigned is always false for a standalone CII XML — the notion of digital signature applies to the PDF, not to the XML).

Errors

Code Cause Example type (RFC 7807)
422 Encrypted or corrupted PDF corrupted-pdf
422 Valid PDF but no CII attachment (not a Factur-X) no-cii-attachment
422 Malformed CII or invalid XML malformed-cii
413 Document > 20 MB — rejected before any 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..."
}

⚠️ These codes do NOT reference the official BR-* rules (schematron): unlike POST /v1/validate (which actually runs the official FNFE-MPE schematron since Story 3.7, schematronChecked: true), extraction only reports structural errors (unreadable PDF/XML), never a BR-* non-compliance — extraction decodes, it does not validate. To check the BR-* compliance of a document before extracting it, use POST /v1/validate.