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);
}
}
}