DocX API

Generez des documents PDF et DOCX a partir de templates Word. Envoyez un fichier Word avec des variables, ajoutez vos donnees en JSON, recevez le document final.

URL https://docx.layerone.fr
Auth Cle API dans le header
Format multipart/form-data

En 3 etapes

  1. Creez un compte gratuitInscrivez-vous sur dev.layerone.fr — 20 requetes/mois incluses.
  2. Recuperez votre cle APIDans la console, cliquez "Nouvelle cle" et choisissez DocX.
  3. Generez votre premier PDFCopiez la commande ci-dessous et lancez-la dans votre terminal.
# Remplacez VOTRE_CLE par la cle obtenue a l'etape 2
curl -X POST https://docx.layerone.fr/render-document \
  -H "X-API-Key: VOTRE_CLE" \
  -F "template=@mon_template.docx" \
  -F 'json_data={"client": "Acme Corp", "montant": "1 500 EUR"}' \
  -o resultat.pdf

Si tout fonctionne, vous obtenez un fichier resultat.pdf avec vos donnees injectees.

Authentification

Ajoutez votre cle API dans le header X-API-Key de chaque requete :

X-API-Key: votre_cle_api

Ne partagez jamais votre cle. Ne la mettez pas dans du code frontend (site web, app mobile). Utilisez-la uniquement depuis votre serveur.

Endpoints

GET /__health Verifier que le service fonctionne ▶

Aucune authentification necessaire. Utile pour monitorer la disponibilite.

GEThttps://docx.layerone.fr/__health
Exemple complet
curl https://docx.layerone.fr/__health
Reponse
{
  "status": "ok",
  "time": "2026-04-13T12:00:00Z",
  "storage": { "templates_writable": true },
  "libreoffice": { "binary_found": true }
}

Ajoutez ?deep=true pour un diagnostic complet (base de donnees, espace disque).

GET /usage-stats Voir votre quota ▶

Consultez combien de requetes vous avez utilisees ce mois-ci et votre limite.

GEThttps://docx.layerone.fr/usage-stats
X-API-Key: VOTRE_CLE
Exemple complet
curl https://docx.layerone.fr/usage-stats \
  -H "X-API-Key: VOTRE_CLE"
Reponse
{
  "success": true,
  "stats": {
    "plan": "gratuit",
    "quota": {
      "limit": 20,
      "used": 12,
      "remaining": 8
    },
    "rate_limit": "5/minute",
    "max_concurrent": 1,
    "usage": {
      "hourly": 3,
      "daily": 12,
      "burst_5min": 1
    },
    "thresholds": {
      "hourly": 500,
      "daily": 2000,
      "burst": 50
    },
    "current_concurrent": 0
  }
}

Le quota se reinitialise sur un cycle glissant de 30 jours a partir de votre souscription (pas le 1er du mois). Quand vous atteignez la limite, les requetes retournent une erreur 429 "Quota mensuel atteint".

POST /client/templates Enregistrer un template ▶

Enregistrez un template pour ne pas le renvoyer a chaque requete. Vous recevez un template_id a reutiliser.

POSThttps://docx.layerone.fr/client/templates
X-API-Key: VOTRE_CLE
Exemple complet
curl -X POST https://docx.layerone.fr/client/templates \
  -H "X-API-Key: VOTRE_CLE" \
  -F "template=@mon_template.docx"
Reponse
{
  "template_id": "abc123",
  "name": "mon_template.docx",
  "status": "created",
  "client_name": "mon_template",
  "detected_tags": ["client_nom", "montant_ht", "lignes"],
  "validation": "ok"
}
PUT /client/templates/{id} Remplacer un template ▶

Remplace le fichier d'un template existant par une nouvelle version.

PUThttps://docx.layerone.fr/client/templates/{id}
X-API-Key: VOTRE_CLE
Exemple complet
curl -X PUT https://docx.layerone.fr/client/templates/abc123 \
  -H "X-API-Key: VOTRE_CLE" \
  -F "template=@nouveau_template.docx"
GET /client/templates/{id} Telecharger un template ▶

Telecharge le fichier Word d'un template enregistre.

GEThttps://docx.layerone.fr/client/templates/{id}
X-API-Key: VOTRE_CLE
Exemple complet
curl https://docx.layerone.fr/client/templates/abc123 \
  -H "X-API-Key: VOTRE_CLE" \
  -o template.docx
DELETE /client/templates/{id} Supprimer un template ▶

Supprime definitivement un template enregistre.

DELETEhttps://docx.layerone.fr/client/templates/{id}
X-API-Key: VOTRE_CLE
Exemple complet
curl -X DELETE https://docx.layerone.fr/client/templates/abc123 \
  -H "X-API-Key: VOTRE_CLE"
GET /client/templates Lister vos templates ▶

Retourne la liste de tous vos templates enregistres.

GEThttps://docx.layerone.fr/client/templates
X-API-Key: VOTRE_CLE
Exemple complet
curl https://docx.layerone.fr/client/templates \
  -H "X-API-Key: VOTRE_CLE"
GET /client/templates/{id}/versions Historique des versions d'un template ▶

Liste les versions archivees d'un template (sans le contenu binaire) — triees par version decroissante. Authentifie par la meme cle X-API-Key.

GEThttps://docx.layerone.fr/client/templates/{id}/versions
Exemple complet
curl https://docx.layerone.fr/client/templates/abc123/versions \
  -H "X-API-Key: VOTRE_CLE"
Reponse
{
  "template_id": "abc123",
  "versions_count": 2,
  "versions": [
    {
      "version_id": 12,
      "version_number": 2,
      "content_hash": "a1b2c3...",
      "original_name": "devis_template.docx",
      "size_bytes": 48213,
      "archived_at": "2026-08-01T10:15:00Z"
    },
    {
      "version_id": 11,
      "version_number": 1,
      "content_hash": "9f8e7d...",
      "original_name": "devis_template.docx",
      "size_bytes": 47900,
      "archived_at": "2026-07-15T09:00:00Z"
    }
  ]
}
GET /client/templates/{id}/versions/{version_id} Telecharger une version precise ▶

Telecharge le contenu DOCX d'une version archivee specifique (binaire, avec Content-Disposition attachment).

GEThttps://docx.layerone.fr/client/templates/{id}/versions/{version_id}
Exemple complet
curl https://docx.layerone.fr/client/templates/abc123/versions/11 \
  -H "X-API-Key: VOTRE_CLE" \
  -o template_v1.docx
POST /client/templates/{id}/restore/{version_id} Restaurer une ancienne version ▶

Restaure une version archivee comme contenu actif du template. La version courante est archivee avant l'ecrasement (rollback toujours possible).

POSThttps://docx.layerone.fr/client/templates/{id}/restore/{version_id}
Exemple complet
curl -X POST https://docx.layerone.fr/client/templates/abc123/restore/11 \
  -H "X-API-Key: VOTRE_CLE"
Reponse
{
  "template_id": "abc123",
  "restored_from_version_id": 11,
  "status": "restored"
}
POST /render-document Generer un PDF ou DOCX ▶

Envoyez un template Word + des donnees JSON. L'API remplace les variables et retourne le document.

POSThttps://docx.layerone.fr/render-document
X-API-Key: VOTRE_CLE

Parametres

Nom Type Description
template * fichier Votre fichier Word (.docx) avec des variables {{...}}
template_id opt. texte Ou bien l'ID d'un template deja enregistre (remplace template)
json_data * JSON Les donnees a injecter. Ex: {"client": "Acme"}
output_format opt. texte pdf (par defaut) ou docx
output_filename opt. texte Nom du fichier retourne. Ex: devis_001.pdf
json_data_base64 opt. texte Alternative a json_data — transmettez vos donnees JSON encodees en base64. Utile lorsque le JSON contient des caracteres speciaux.
document_type opt. texte Type de document pour filtrer le template.
compress_pdf opt. booleen Compresse le PDF genere via Ghostscript (qualite "ebook"). Par defaut : true.
return_signature_fields opt.
(parametre d'URL, pas de formulaire)
booleen Passe en query string dans l'URL : ?return_signature_fields=true (ce n'est PAS un champ -F du formulaire). Si true, retourne les positions des champs de signature detectes dans la reponse. Par defaut : false.
Format de reponse dual :
• Si ?return_signature_fields=true est passe dans l'URL ET que des champs sont trouves : retourne un JSON contenant pdf_base64 et signature_fields.
• Sinon : retourne directement le fichier binaire PDF ou DOCX.
Exemple avec detection des signatures
curl -X POST "https://docx.layerone.fr/render-document?return_signature_fields=true" \
  -H "X-API-Key: VOTRE_CLE" \
  -F "template=@devis_template.docx" \
  -F 'json_data={"client": "Acme Corp"}'
Exemple complet
cURL
Python
JavaScript
curl -X POST https://docx.layerone.fr/render-document \
  -H "X-API-Key: VOTRE_CLE" \
  -F "template=@devis_template.docx" \
  -F 'json_data={
    "client": "Acme Corp",
    "adresse": "12 rue de Paris, 75001",
    "lignes": [
      {"description": "Prestation A", "prix": "500 EUR"},
      {"description": "Prestation B", "prix": "1 000 EUR"}
    ],
    "total": "1 500 EUR"
  }' \
  -o devis.pdf
import requests, json

response = requests.post(
    "https://docx.layerone.fr/render-document",
    headers={"X-API-Key": "VOTRE_CLE"},
    files={"template": open("devis_template.docx", "rb")},
    data={"json_data": json.dumps({
        "client": "Acme Corp",
        "total": "1 500 EUR"
    })}
)

with open("devis.pdf", "wb") as f:
    f.write(response.content)
const form = new FormData();
form.append("template", fichierWord);
form.append("json_data", JSON.stringify({
  client: "Acme Corp",
  total: "1 500 EUR"
}));

const res = await fetch("https://docx.layerone.fr/render-document", {
  method: "POST",
  headers: { "X-API-Key": "VOTRE_CLE" },
  body: form
});

const pdf = await res.blob();
Reponse

En cas de succes (200), le corps de la reponse contient directement le fichier PDF ou DOCX.

POST /render-facturx Generer une facture Factur-X ▶

Comme /render-document, mais produit un PDF conforme a la norme Factur-X (PDF/A-3 + XML). Obligatoire pour la facturation electronique B2B en France.

POSThttps://docx.layerone.fr/render-facturx
X-API-Key: VOTRE_CLE

Parametres differents de /render-document : pas de output_format, pas de return_signature_fields, pas de compress_pdf. Seuls template ou template_id, json_data (ou json_data_base64), output_filename et document_type sont acceptes. Le XML Factur-X est genere automatiquement.

Exemple complet
curl -X POST https://docx.layerone.fr/render-facturx \
  -H "X-API-Key: VOTRE_CLE" \
  -F "template=@facture_template.docx" \
  -F 'json_data={
    "numero_facture": "FA-2024-001",
    "date_facture": "2024-03-15",
    "client": {
      "nom": "Acme Corp",
      "adresse": "12 rue de Paris",
      "code_postal": "75001",
      "ville": "Paris",
      "siret": "12345678901234"
    },
    "montant_ht_total": "1250.00",
    "montant_tva_total": "250.00",
    "montant_ttc_total": "1500.00"
  }' \
  -o facture.pdf

Le PDF est valide VeraPDF (PDF/A-3) et accepte par les plateformes comme Chorus Pro.

POST /attach-facturx Rendre Factur-X un PDF deja genere ▶

Transforme un PDF deja mis en page (par exemple une facture generee par votre propre application) en Factur-X conforme (PDF/A-3 + XML EN 16931), sans repasser par un template. Le PDF fourni est converti en PDF/A-3 et le XML (derive de json_data) y est attache.

POSThttps://docx.layerone.fr/attach-facturx
X-API-Key: VOTRE_CLE

Parametres

Nom Type Description
pdf * fichier Le PDF deja mis en page (facture existante).
json_data * JSON Memes cles que /render-facturx (fournisseur, client, lignes, montants, numero_facture, date_facture).
json_data_base64 opt. texte Alternative a json_data en base64.
output_filename opt. texte Nom du fichier retourne.
Exemple complet
curl -X POST https://docx.layerone.fr/attach-facturx \
  -H "X-API-Key: VOTRE_CLE" \
  -F "pdf=@facture_deja_generee.pdf" \
  -F 'json_data={
    "numero_facture": "FA-2024-001",
    "date_facture": "2024-03-15",
    "client": {
      "nom": "Acme Corp",
      "siret": "12345678901234"
    },
    "montant_ht_total": "1250.00",
    "montant_tva_total": "250.00",
    "montant_ttc_total": "1500.00"
  }' \
  -o facture_facturx.pdf

Reponse identique a /render-facturx : le fichier PDF/A-3 conforme est retourne directement.

Comment creer un template

Un template est un fichier Word (.docx) classique avec des variables entre doubles accolades. L'API les remplace par vos donnees.

Exemple simple

Dans votre fichier Word, ecrivez :

Bonjour {{client}},

Veuillez trouver ci-joint votre devis d'un montant de {{total}}.

Date : {{date}}
Reference : {{reference}}

Et envoyez ce JSON :

{
  "client": "Acme Corp",
  "total": "1 500 EUR",
  "date": "15/03/2024",
  "reference": "DEV-2024-001"
}

Variables imbriquees

Vous pouvez utiliser la notation a points pour acceder a des sous-objets :

# Dans le Word
Client : {{client.nom}}
Ville : {{client.adresse.ville}}

# Dans le JSON
{
  "client": {
    "nom": "Acme Corp",
    "adresse": { "ville": "Paris" }
  }
}

Tableaux (lignes repetees)

Pour generer plusieurs lignes (ex: lignes de devis), le moteur (docxtpl/Jinja2) exige une syntaxe precise : 3 lignes de tableau Word distinctes (3 balises <w:tr> separees). Un simple {{lignes.description}} pose dans une seule cellule ne fonctionnera pas — l'API ne duplique rien toute seule sans cette syntaxe.

Ligne 1 du tableau Word (cellule vide, juste le tag) :

{%tr for item in lignes %}

Ligne 2 du tableau Word (les donnees, une cellule par colonne) :

{{ item.description }}  |  {{ item.prix }}

Ligne 3 du tableau Word (cellule vide, juste le tag) :

{%tr endfor %}

Et le JSON correspondant :

# JSON
{
  "lignes": [
    {"description": "Prestation A", "prix": "500 EUR"},
    {"description": "Prestation B", "prix": "1 000 EUR"}
  ]
}

Important : chacune des 3 lignes doit etre une vraie ligne de tableau Word separee. Ne mettez jamais {%tr for %} et {%tr endfor %} dans la meme ligne de tableau — le rendu echouera.

Listes (a puces ou numerotees)

Pour repeter un paragraphe entier (ex: une liste a puces ou numerotee), le moteur (docxtpl/Jinja2) propose l'equivalent de {%tr%} mais au niveau du paragraphe : 3 paragraphes Word distincts avec les balises {%p for %} / {%p endfor %}. Un simple {{liste}} pose dans un seul paragraphe ne fonctionnera pas — l'API ne duplique rien toute seule sans cette syntaxe.

Paragraphe 1 du document Word (paragraphe vide, juste le tag) :

{%p for prestation in prestations %}

Paragraphe 2 du document Word (les donnees — c'est ce paragraphe qui doit deja porter le style Word "Liste a puces" ou "Liste numerotee", applique dans Word avant d'inserer la balise) :

{{ prestation }}

Paragraphe 3 du document Word (paragraphe vide, juste le tag) :

{%p endfor %}

Et le JSON correspondant (liste de textes simples) :

# JSON
{
  "prestations": [
    "Nettoyage de chantier",
    "Evacuation des gravats",
    "Controle final"
  ]
}

Variante avec des objets (une balise par champ dans le paragraphe 2, ex : {{ prestation.nom }} — {{ prestation.duree }}) :

# JSON
{
  "prestations": [
    {"nom": "Nettoyage de chantier", "duree": "2h"},
    {"nom": "Evacuation des gravats", "duree": "1h30"}
  ]
}

Les filtres de casse (maj, min, cap, titre — voir la section "Filtres disponibles" plus bas) s'appliquent aussi bien dans une liste que partout ailleurs, y compris sur un champ imbrique (paragraphe 2 du document Word) :

{{ prestation.nom | maj }} — {{ prestation.duree }}

La notation a points fonctionne comme partout ailleurs (voir "Variables imbriquees" plus haut) : chaque element de la liste peut etre un objet avec des sous-champs, y compris imbriques.

Important : chacun des 3 paragraphes doit etre un vrai paragraphe Word separe, et chaque paragraphe {%p for %} / {%p endfor %} ne doit contenir que le tag — aucun autre texte. Un mot ajoute dans le meme paragraphe que {%p for %} ou {%p endfor %} est supprime silencieusement du rendu final (il disparait, sans erreur). Ne mettez jamais {%p for %} et {%p endfor %} dans le meme paragraphe — le rendu echouera.

C'est le style du paragraphe (celui qui contient {{ prestation }}) qui donne la puce ou le numero, pas la syntaxe Jinja. Si ce paragraphe n'a pas de style de liste dans Word, vous obtiendrez des lignes de texte simples, repetees mais sans puce ni numero.

Enregistrer un template

Plutot que de renvoyer le fichier Word a chaque fois, enregistrez-le une fois avec POST /client/templates et reutilisez son template_id dans vos appels.

Images et photos

Vous pouvez inserer des images dynamiques dans vos templates grace au filtre photo(). Les images sont envoyees en fichiers joints (multipart) et inserees a la taille souhaitee.

Envoyer des images

Ajoutez vos images comme fichiers multipart dans la requete, avec des noms comme photo_0, photo_1, etc. Dans le JSON, referencez-les par leur nom :

curl -X POST https://docx.layerone.fr/render-document \
  -H "X-API-Key: votre_cle" \
  -F "template_id=abc123" \
  -F 'json_data={"photos": [{"image": "photo_0"}, {"image": "photo_1"}]}' \
  -F "photo_0=@photo1.jpg" \
  -F "photo_1=@photo2.jpg" \
  -F "output_format=pdf"

Formats acceptes : JPEG et PNG uniquement (verifies sur le contenu reel du fichier, pas seulement sur l'extension). Taille maximale : 50 Mo par fichier.

Le filtre photo()

Dans votre template Word, utilisez le filtre photo() pour inserer et redimensionner les images :

Dans le template Resultat
{{ image | photo(120) }} Image a 120 mm de large (hauteur auto)
{{ image | photo(80, 60) }} Image a 80 × 60 mm (largeur × hauteur)
{{ image | photo }} Taille par defaut (80 mm de large)
{{ image | photo(160) }} Pleine largeur A4 (~160 mm)
{{ image | photo(40) }} Miniature 40 mm

Mise en page : photos empilees

Par defaut, les photos s'empilent verticalement :

# Dans le template Word
{% for p in photos %}
{{ p.image | photo(120) }}
{% endfor %}

Mise en page : grille 2 colonnes

Pour afficher les photos cote a cote, inserez un tableau Word a 2 colonnes dans votre template et placez les tags dans les cellules :

# Tableau Word avec 2 cellules par ligne
| {{ row.0.image | photo(75) }} | {{ row.1.image | photo(75) }} |

Envoyez les photos regroupees par lignes de 2 dans le JSON :

{
  "rows": [
    [{"image": "photo_0"}, {"image": "photo_1"}],
    [{"image": "photo_2"}, {"image": "photo_3"}]
  ]
}

Mise en page automatique : {{ reportage_photos }}

Pour un reportage photo multi-niveaux (ex : plusieurs zones d'un chantier, chacune avec ses propres photos), placez le tag {{ reportage_photos }} seul dans un paragraphe de votre template. L'API genere automatiquement un tableau par niveau (3 photos par rangee, avec une ligne de description sous chaque rangee), dans des blocs insecables (une rangee de photos ne sera jamais coupee entre deux pages).

Fournissez vos donnees via la cle level_photo_groups dans le JSON : une liste de groupes, chacun avec un level_name (titre du niveau) et une liste photos (chaque photo reference le nom du fichier multipart via image, avec une liste optionnelle non_conformities affichee sous la photo) :

{
  "level_photo_groups": [
    {
      "level_name": "Niveau RDC",
      "photos": [
        {"image": "photo_0", "non_conformities": [
          {"description": "Garde-corps absent", "norm_reference": "NF P01-012"}
        ]},
        {"image": "photo_1"}
      ]
    },
    {
      "level_name": "Niveau R+1",
      "photos": [{"image": "photo_2"}]
    }
  ]
}

Tailles differentes par type

Vous pouvez utiliser des tailles differentes pour chaque image. Exemple : photo panoramique large + photos detail petites :

# Photo panoramique
{{ panorama.image | photo(160) }}

# Photos detail
{% for p in details %}
{{ p.image | photo(60) }}
{% endfor %}

Signatures

Les signatures fonctionnent de la meme maniere. Envoyez-les comme fichiers multipart et utilisez le filtre photo() :

# Dans le template
Signature : {{ signature | photo(50) }}

# curl — le nom du fichier DOIT commencer par "signature_"
-F "signature_0=@signature.png"
-F 'json_data={"signature": "signature_0"}'

Seuls les fichiers dont le nom commence par signature_ (ex : signature_0, signature_1) sont reconnus comme signature. Un champ nomme simplement signature ne sera pas pris en compte.

Signature electronique

DocX propose aussi un service de signature electronique integre (via Documenso), distinct du produit "Sign" (sign.layerone.fr) mais accessible avec la meme cle X-API-Key. Il est facture sur un quota dedie (service_type="sign"), separe de votre quota de generation de documents.

Endpoint Usage
POST /create-signature-request Cree une demande de signature a partir d'un PDF (base64) et d'une liste de signataires. Retourne un document_id et les liens de signature (signing_urls).
GET /signature-status/{document_id} Recupere le statut d'une demande de signature en cours.
POST /detect-placeholders Utilitaire : detecte les emplacements de signature dans un PDF sans creer de demande — utile pour deboguer les positions avant l'envoi.
GET /download-signed-pdf/{document_id} Telecharge le PDF signe (base64) une fois le document COMPLETED.
DELETE /cancel-document/{document_id} Annule une demande de signature en cours et la supprime.

Filtres disponibles

Les filtres transforment vos donnees dans le template. Syntaxe : {{ valeur | filtre }}

Filtre Usage Resultat
photo(l) / photo(l, h) {{ img | photo(80) }} Insere une image (l mm × h mm)
maj {{ nom | maj }} MAJUSCULES
min {{ nom | min }} minuscules
cap {{ nom | cap }} Premiere lettre en majuscule
titre {{ nom | titre }} Chaque Mot En Majuscule
euro {{ montant | euro }} 1 500,00 €
suffix("...") {{ val | suffix(" kg") }} Ajoute un suffixe
prefix("...") {{ val | prefix("N° ") }} Ajoute un prefixe
date_fr {{ date_debut | date_fr }} Formate une date ISO (AAAA-MM-JJ ou ISO datetime) en JJ/MM/AAAA. Chaine vide si non parsable (jamais "N/A").
has_intervention_dates {% if interventions | has_intervention_dates %} Filtre booleen : vrai si la liste contient au moins une intervention avec une date renseignee. Sert a conditionner l'affichage d'un tableau d'interventions.

Codes d'erreur

En cas d'erreur, la reponse contient un champ detail qui explique le probleme.

Code Signification Que faire ?
200 Tout va bien Vous recevez le fichier.
400 Requete invalide Verifiez les parametres envoyes.
401 Cle API manquante ou invalide Verifiez le header X-API-Key.
403 Cle API valide mais pas autorisee pour ce service (ex : une cle du service signature utilisee sur un endpoint document). Verifiez que votre cle correspond au bon service.
404 Endpoint ou ressource introuvable Verifiez l'URL.
413 Requete trop volumineuse (limite de votre forfait) Reduisez la taille du fichier ou passez au plan superieur.
422 Donnees invalides JSON mal forme ou fichier manquant.
429 Trop de requetes — 3 causes possibles : quota mensuel atteint (la plus frequente, verifiez avec /usage-stats), limite de requetes par minute depassee, ou trop de requetes simultanees pour votre plan. Verifiez votre quota. Si le quota est bon, attendez quelques secondes avant de reessayer.
500 Erreur serveur Reessayez. Si ca persiste, contactez le support.
503 Service temporairement indisponible (base de donnees inaccessible) Reessayez dans quelques instants.
504 Conversion PDF trop longue (timeout) Simplifiez le template ou reessayez.
# Exemple d'erreur
{"detail": "Quota mensuel depasse. Passez au plan superieur."}