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.