Sign API

Faites signer electroniquement vos documents PDF. Envoyez un PDF, indiquez les signataires, recevez le document signe conforme eIDAS.

URL https://sign.layerone.fr/v1
Auth Cle API dans le header
Format JSON

En 3 etapes

  1. Creez un compte gratuitInscrivez-vous sur dev.layerone.fr.
  2. Recuperez votre cle APIDans la console, cliquez "Nouvelle cle" et choisissez Sign.
  3. Envoyez votre premier documentCopiez la commande ci-dessous avec votre cle et un PDF encode en base64.
# Encoder votre PDF en base64
PDF_B64=$(base64 -i mon_document.pdf)

# Envoyer pour signature
curl -X POST https://sign.layerone.fr/v1/documents/send \
  -H "X-API-Key: VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d "{
    \"pdf_base64\": \"$PDF_B64\",
    \"document_name\": \"Mon_document.pdf\",
    \"signers\": [
      {\"name\": \"Jean Dupont\", \"email\": \"jean@example.com\"}
    ]
  }"

Le signataire recoit un email avec un lien pour signer. Vous recevez une notification quand c'est fait.

Authentification

Ajoutez votre cle API dans le header de chaque requete. Deux formats sont acceptes :

X-API-Key: votre_cle_sign

ou

Authorization: Bearer votre_cle_sign

Cle distincte de DocX. La cle DocX ne fonctionne pas ici. Vous devez creer une cle Sign dans la console.

JSON et form-data. Tous les endpoints POST acceptent le format application/json et multipart/form-data. En form-data, les champs signers et signature_fields doivent etre passes en tant que chaines JSON.

Endpoints

GET /v1/health Verifier que le service fonctionne ▶

Aucune authentification necessaire.

GEThttps://sign.layerone.fr/v1/health
Exemple complet
curl https://sign.layerone.fr/v1/health
Reponse
{
  "status": "ok",
  "service": "sign-api",
  "version": "1.0.0"
}
POST /v1/documents/send Envoyer pour signature ▶

Envoyez un PDF et la liste des personnes qui doivent signer.

POSThttps://sign.layerone.fr/v1/documents/send
X-API-Key: VOTRE_CLE

Parametres

Nom Type Description
pdf_base64 * texte Le contenu de votre PDF, encode en base64
document_name * texte Le nom du document. Ex: "Devis_001.pdf"
signers * liste Les personnes qui doivent signer (voir ci-dessous)
note opt. texte Message envoye par email aux signataires
expiry_days opt. nombre Jours avant expiration (defaut: 30)
send_email opt. oui/non Envoyer un email d'invitation (defaut: oui)
signature_fields opt. liste Positions des zones de signature (voir Zones de signature). Si absent, les balises du PDF sont detectees automatiquement.
company_name opt. texte Nom de l'entreprise expeditrice (defaut: "LayerOne")
sender_name opt. texte Nom de l'expediteur affiche dans l'email
valid_until opt. date ISO Date limite de validite du document. Passe cette date, l'envoi est refuse (409) sauf si accept_expired vaut true.
accept_expired opt. oui/non Force l'envoi malgre un valid_until depasse (defaut: non)
source_id opt. texte Identifiant de tracabilite cote appelant (informatif, non interprete)
source_type opt. texte Type de tracabilite associe a source_id (informatif, non interprete)

Chaque signataire

Nom Type Description
name * texte Nom complet
email * texte Adresse email
role opt. texte Role (defaut: "Client"). Sert a associer les zones de signature dans le PDF.
phone opt. texte Numero de telephone au format international (ex: +33612345678). Active la verification OTP par SMS.

Verification OTP par SMS (optionnelle) : par defaut, le signataire recoit un email avec un lien pour signer. Si vous ajoutez le champ phone, un code SMS sera envoye au signataire avant qu'il puisse signer — c'est une couche de securite supplementaire. Vous pouvez mixer les deux dans un meme document : certains signataires avec OTP, d'autres sans.

Exemples

cURL
Python
Exemple complet
curl -X POST https://sign.layerone.fr/v1/documents/send \
  -H "X-API-Key: VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{
    "pdf_base64": "JVBERi0xLjQK...",
    "document_name": "Devis_001.pdf",
    "signers": [
      {"name": "Jean Dupont", "email": "jean@example.com", "role": "Client"}
    ],
    "note": "Merci de signer ce devis.",
    "expiry_days": 14
  }'
Exemple complet
import requests, base64

# Encoder le PDF
with open("devis.pdf", "rb") as f:
    pdf_b64 = base64.b64encode(f.read()).decode()

response = requests.post(
    "https://sign.layerone.fr/v1/documents/send",
    headers={
        "X-API-Key": "VOTRE_CLE",
        "Content-Type": "application/json"
    },
    json={
        "pdf_base64": pdf_b64,
        "document_name": "Devis_001.pdf",
        "signers": [
            {"name": "Jean Dupont", "email": "jean@example.com"}
        ]
    }
)

data = response.json()
print("Document ID:", data["document_id"])
Reponse
{
  "success": true,
  "document_id": "244",
  "signing_urls": {
    "jean@example.com": "https://sign.layerone.fr/sign/abc123..."
  },
  "original_pdf_hash": "a1b2c3d4e5f6...",
  "message": "Document cree avec 2 champ(s)",
  "otp_required": false
}

Champs de la reponse

ChampDescription
document_idIdentifiant du document (a conserver pour les autres endpoints)
signing_urlsURL de signature par signataire (email → lien)
original_pdf_hashHash SHA-256 du PDF original (preuve d'integrite)
messageMessage descriptif
otp_requiredtrue si un signataire necessite une verification OTP par SMS
DELETE /v1/documents/{id} Annuler une demande ▶

Annulez une demande de signature en cours. Les signataires ne pourront plus acceder au document.

DELETEhttps://sign.layerone.fr/v1/documents/{id}
X-API-Key: VOTRE_CLE
Exemple complet
curl -X DELETE https://sign.layerone.fr/v1/documents/{id} \
  -H "X-API-Key: VOTRE_CLE"
GET /v1/documents/{id} Voir le statut ▶

Verifiez ou en est la signature d'un document.

GEThttps://sign.layerone.fr/v1/documents/{id}
X-API-Key: VOTRE_CLE
Exemple complet
curl https://sign.layerone.fr/v1/documents/{id} \
  -H "X-API-Key: VOTRE_CLE"
Reponse
{
  "success": true,
  "document_id": "244",
  "title": "Devis_001.pdf",
  "status": "SENT",
  "completed": false,
  "recipients": [
    {
      "email": "jean@example.com",
      "signingStatus": "SENT"
    }
  ]
}

Statuts possibles

Statut Ce que ca veut dire
CREATED Demande creee, pas encore envoyee
SENT Email envoye aux signataires
OPENED Un signataire a ouvert le document
SIGNED Au moins une personne a signe
COMPLETED Tout le monde a signe — vous pouvez telecharger le PDF
REJECTED Quelqu'un a refuse de signer
EXPIRED Le delai est depasse
GET /v1/documents/{id}/download Telecharger le PDF signe ▶

Recuperez le PDF final avec toutes les signatures. Disponible uniquement quand le statut est COMPLETED.

GEThttps://sign.layerone.fr/v1/documents/{id}/download
X-API-Key: VOTRE_CLE
Exemple complet
curl https://sign.layerone.fr/v1/documents/{id}/download \
  -H "X-API-Key: VOTRE_CLE"
Reponse
{
  "success": true,
  "document_id": "244",
  "title": "Devis_001.pdf",
  "pdf_base64": "JVBERi0xLjQK...",
  "audit_certificate_base64": "JVBERi0xLjQK...",
  "size_bytes": 125430
}

Le PDF est retourne encode en base64 dans le champ pdf_base64. Decodez-le pour obtenir le fichier PDF. Le document contient des signatures PAdES-LTA conformes eIDAS avec certificat de preuve et horodatage. Le champ audit_certificate_base64 contient en plus le certificat de preuve, au format PDF encode en base64 (peut etre absent si sa generation a echoue — champ best-effort).

GET /v1/documents/{id}/audit Certificat de preuve ▶

Retourne le certificat de preuve complet d'un document signe : signataires, adresses IP, navigateur, horodatage de chaque action. Disponible uniquement quand le statut est COMPLETED.

GEThttps://sign.layerone.fr/v1/documents/{id}/audit
X-API-Key: VOTRE_CLE
Exemple
curl https://sign.layerone.fr/v1/documents/{id}/audit \
  -H "X-API-Key: VOTRE_CLE"
Reponse
{
  "success": true,
  "certificate": {
    "document_id": "244",
    "title": "Devis_001.pdf",
    "status": "COMPLETED",
    "created_at": "2026-04-14T09:00:00Z",
    "completed_at": "2026-04-14T10:30:00Z",
    "external_id": "244",
    "signature_type": "CAdES/ETSI (Signature Electronique Avancee)",
    "compliance": "eIDAS - Niveau 2 (Signature Avancee)",
    "recipients": [
      {
        "email": "jean@example.com",
        "name": "Jean Dupont",
        "role": "SIGNER",
        "signing_status": "SIGNED",
        "read_status": "OPENED",
        "signed_at": "2026-04-14T10:30:00Z",
        "send_status": "SENT"
      }
    ],
    "fields": [
      {
        "type": "SIGNATURE",
        "page": 3,
        "value": null,
        "inserted": true
      }
    ],
    "audit_trail": [
      {
        "type": "DOCUMENT_CREATED",
        "name": null,
        "email": null,
        "ip_address": "192.168.1.1",
        "user_agent": "Mozilla/5.0...",
        "timestamp": "2026-04-14T09:00:00Z",
        "data": {}
      }
    ],
    "total_events": 1
  },
  "proof_bundle": {
    "document_id": "244",
    "original_pdf_hash": "3f9a1c...",
    "signed_pdf_hash": "8b2e77...",
    "signer_name": "Jean Dupont",
    "otp_verified": true,
    "pades_signed": true
  }
}

Tout est imbrique sous certificate. Les signataires sont dans recipients (pas signers) et le journal d'evenements dans audit_trail (pas audit_log). proof_bundle est un objet optionnel (present si le dossier de preuve cryptographique a pu etre assemble) : le detail ci-dessus n'est qu'un extrait, il porte davantage de champs cryptographiques.

GET /v1/documents/{id}/validate Valider la signature ▶

Verifie l'integrite cryptographique de la signature PAdES embarquee dans le PDF signe. Confirme que le document n'a pas ete modifie apres signature.

GEThttps://sign.layerone.fr/v1/documents/{id}/validate
X-API-Key: VOTRE_CLE
Exemple
curl https://sign.layerone.fr/v1/documents/{id}/validate \
  -H "X-API-Key: VOTRE_CLE"
Reponse
{
  "success": true,
  "document_id": "244",
  "title": "Devis_001.pdf",
  "source": "pades_local",
  "validation": {
    "total_signatures": 1,
    "all_valid": true,
    "signatures": [
      {
        "field_name": "Signature_Client",
        "intact": true,
        "valid": true,
        "trusted": true,
        "type": "signature",
        "signer": "2026-04-14T10:30:00Z",
        "coverage": "ENTIRE_FILE",
        "timestamp_valid": true
      }
    ]
  }
}

source vaut pades_local (PDF signe conserve localement) ou documenso (recupere depuis Documenso). validation porte le verdict cryptographique : integrite (intact), validite de la chaine de certification (valid/trusted) et statut de l'horodatage pour chaque signature.

Utile pour verifier en production qu'un document signe est toujours integre avant de l'archiver.

POST /v1/documents/detect-fields Detecter les balises ▶

Analyse un PDF et retourne les balises de signature detectees ([[SIGNATURE_CLIENT]], etc.), sans creer de demande de signature. Utile pour pre-visualiser les champs avant envoi.

POSThttps://sign.layerone.fr/v1/documents/detect-fields
X-API-Key: VOTRE_CLE

Parametres

NomTypeDescription
pdf_base64 * texte Le PDF encode en base64
Exemple
curl -X POST https://sign.layerone.fr/v1/documents/detect-fields \
  -H "X-API-Key: VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{"pdf_base64": "JVBERi0xLjQK..."}'
Reponse
{
  "success": true,
  "fields_count": 2,
  "fields": [
    {
      "name": "SIGNATURE_CLIENT",
      "type": "SIGNATURE",
      "role": "Client",
      "page": 1,
      "x": 55.2,
      "y": 82.1,
      "width": 25,
      "height": 5
    },
    {
      "name": "DATE_SIGNATURE",
      "type": "DATE",
      "role": "Client",
      "page": 1,
      "x": 55.2,
      "y": 89.0,
      "width": 20,
      "height": 3
    }
  ]
}

Webhooks

Recevez une notification automatique quand le statut d'une signature change.

Votre serveur doit repondre 200 en moins de 10 secondes. Sinon, on reessaie 3 fois (30s, 2min, 5min).

Configurer votre webhook

Reserve aux cles API du portail developpeur (sk_). Une cle = un webhook : PUT /v1/webhooks/me cree ou REMPLACE la configuration (un nouveau secret HMAC est genere a chaque appel), GET /v1/webhooks/me retourne la configuration courante (sans le secret) ainsi que les 20 dernieres livraisons, et DELETE /v1/webhooks/me supprime la configuration.

curl -X PUT https://sign.layerone.fr/v1/webhooks/me \
  -H "Authorization: Bearer VOTRE_CLE_SK" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://votre-serveur.example.com/webhooks/sign",
    "events": ["document.completed", "document.rejected"]
  }'

La reponse contient un champ secret, affiche une seule fois : conservez-le, il sert a verifier la signature de chaque notification recue (voir plus bas). Le parametre events est optionnel : sans lui, la cle est abonnee a tous les evenements.

Evenements

Evenement Quand ?
document.sent L'email a ete envoye aux signataires
document.opened Quelqu'un a ouvert le document
document.signed Quelqu'un a signe
document.completed Tout le monde a signe
document.rejected Quelqu'un a refuse
document.cancelled Le document a ete annule

Exemple de notification recue

{
  "event": "document.completed",
  "document_id": "244",
  "title": "Devis_001.pdf",
  "status": "COMPLETED",
  "recipients": [
    {
      "email": "jean@example.com",
      "status": "SIGNED",
      "signed_at": "2026-04-14T10:30:00Z"
    }
  ],
  "occurred_at": "2026-04-14T10:30:01Z",
  "download_url": "https://sign.layerone.fr/v1/documents/244/download"
}

Le champ download_url n'est present que pour l'evenement document.completed. Le champ recipients ne porte pas le nom du signataire, seulement son email, son status et sa date de signature.

Securite des notifications

Chaque notification est signee : l'en-tete X-Sign-Signature contient sha256= suivi du HMAC-SHA256 hexadecimal du corps brut de la requete, calcule avec votre secret webhook. Avant de traiter une notification, recalculez ce HMAC sur le corps brut recu et comparez-le (en temps constant) a la valeur de l'en-tete : si elle ne correspond pas, rejetez la requete.

Flux complet : generer + signer

Si vous utilisez aussi la DocX API, voici le flux recommande :

1
Generez le PDF avec DocX API
POST https://docx.layerone.fr/render-document
↓
2
Envoyez pour signature avec Sign API
POST https://sign.layerone.fr/v1/documents/send
↓
3
Le signataire signe en cliquant sur le lien dans l'email
↓
4
Vous recevez la notification webhook DOCUMENT_COMPLETED
↓
5
Telechargez le PDF signe
GET https://sign.layerone.fr/v1/documents/{id}/download

Zones de signature dans le PDF

Deux methodes pour positionner les champs de signature, date, initiales, etc. Si aucune methode n'est utilisee, un champ signature est place en bas de la derniere page par defaut.

Methode 1 : Balises dans le PDF (recommandee)

Placez des balises en texte directement dans votre PDF ou template Word. L'API les detecte et positionne les champs automatiquement a leur emplacement exact. Les balises sont effacees du PDF final.

Balise Type de champ
[[SIGNATURE_CLIENT]] Zone de signature
[[DATE_SIGNATURE]] Date de signature (remplie automatiquement)
[[INITIALES]] Paraphe / initiales
[[LU_ET_APPROUVE;type=TEXT]] Champ texte libre
[[CASE_A_COCHER;type=CHECKBOX]] Case a cocher
[[CASE_CLIENT]] Case a cocher — ecriture courte (depuis le 2026-09-01), equivalente a [[CASE_CLIENT;type=CHECKBOX]]. Toute balise dont le nom commence par CASE_ est reconnue comme case a cocher (ex: [[CASE_ENTR_3]]).

Format etendu — pour controler le type, la taille et le role :

[[NOM_DU_CHAMP;type=TYPE;role=ROLE;width=LARGEUR;height=HAUTEUR;options=A,B,C]]
Option Valeurs possibles Defaut
type SIGNATURE, DATE, INITIALS (alias INITIALES), NAME (alias NOM), EMAIL, TEXT (alias TEXTE), CHECKBOX, DROPDOWN (alias SELECT, LISTE), RADIO SIGNATURE
role Le role du signataire (ex: Client, Fournisseur, Entreprise_3). Si absent, deduit automatiquement du nom du champ — voir l'encart ci-dessous. Client
width Largeur du champ. Un nombre nu est en points (ex: width=120). Ajoutez le suffixe % pour un pourcentage de la page (ex: width=40%), ou pt pour l'expliciter (width=120pt). 25% (auto)
height Hauteur du champ. Meme regle : nombre nu = points (ex: height=20), suffixe % pour un pourcentage (ex: height=5%). 5% (auto)
options Choix proposes pour DROPDOWN/RADIO, separes par des virgules (ex: options=Oui,Non,À étudier) —
Exemples de balises dans un template
Signature du client :       [[SIGNATURE_CLIENT]]
Date :                      [[DATE_SIGNATURE]]
Lu et approuve :            [[LU_ET_APPROUVE;type=TEXT;width=120;height=20]]
Signature fournisseur :     [[SIGNATURE_FOURNISSEUR;type=SIGNATURE;role=Fournisseur]]
Signature entreprise 3 :    [[SIGNATURE_ENTREPRISE_3]]
Menu deroulant :            [[ACCEPTE;type=DROPDOWN;options=Oui,Non,À étudier]]

Role deduit automatiquement : si role= n'est pas precise, le nom de la balise suffit. SIGNATURE_FOURNISSEUR vise le role Fournisseur, SIGNATURE_ENTREPRISE_3 (ou SIGN_ENTR_3) vise le role Entreprise_3 (la 3e entreprise signataire), et une balise sans segment reconnu vise Client.

Astuce : dans votre template Word, mettez les balises en police tres petite (2pt) ou en couleur blanche pour qu'elles soient invisibles dans le PDF final.

Methode 2 : Parametre signature_fields dans l'API

Si vous ne pouvez pas modifier le PDF, passez les positions manuellement via le parametre signature_fields. Les coordonnees x et y sont en pourcentage de la page (0 a 100).

Champ Type Description
name texte Nom du champ (ex: "Signature")
type texte SIGNATURE, DATE, INITIALS, NAME, EMAIL, TEXT, CHECKBOX, DROPDOWN, RADIO
role texte Role du signataire concerne (defaut: "Client")
page nombre Numero de page (commence a 1)
x nombre Position horizontale en % (0 = gauche, 100 = droite)
y nombre Position verticale en % (0 = haut, 100 = bas)
width nombre Largeur en % (defaut: 25)
height nombre Hauteur en % (defaut: 5)
options liste Choix pour DROPDOWN/RADIO (ex: ["Oui", "Non", "À étudier"])
Exemple avec signature_fields
curl -X POST https://sign.layerone.fr/v1/documents/send \
  -H "X-API-Key: VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{
    "pdf_base64": "JVBERi0xLjQK...",
    "document_name": "Contrat.pdf",
    "signers": [
      {"name": "Jean Dupont", "email": "jean@example.com", "role": "Client"}
    ],
    "signature_fields": [
      {
        "name": "Signature",
        "type": "SIGNATURE",
        "role": "Client",
        "page": 3,
        "x": 55,
        "y": 80,
        "width": 30,
        "height": 8
      },
      {
        "name": "Date",
        "type": "DATE",
        "role": "Client",
        "page": 3,
        "x": 55,
        "y": 90,
        "width": 20,
        "height": 3
      }
    ]
  }'

Priorite : si vous passez signature_fields ET que le PDF contient des balises, les deux sont utilises. Les balises du PDF sont detectees en plus des champs passes en parametre.

Limites de debit

Chaque endpoint a une limite de requetes par minute par cle API. Si vous depassez la limite, vous recevez une erreur 429 Too Many Requests.

Endpoint Methode Limite
/v1/documents/send POST 30 req/min
/v1/documents/{id} GET 60 req/min
/v1/documents/{id}/download GET 10 req/min
/v1/documents/{id}/audit GET 30 req/min
/v1/documents/{id}/validate GET 10 req/min
/v1/documents/{id} DELETE 10 req/min
/v1/documents/detect-fields POST 10 req/min

Les headers X-RateLimit-Limit et X-RateLimit-Remaining sont inclus dans chaque reponse pour suivre votre consommation.

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 —
400 Requete invalide Verifiez les parametres.
401 Cle API invalide Verifiez le header X-API-Key.
403 Acces interdit a ce document La cle utilisee n'est pas celle qui a cree ce document.
404 Document introuvable Verifiez le document_id.
409 Document hors validite La date valid_until est depassee. Faites accepter le document a nouveau puis renvoyez avec accept_expired=true.
413 Requete ou PDF trop volumineux Reduisez la taille du PDF envoye.
422 Donnees invalides JSON mal forme, PDF manquant, email invalide...
429 Trop de requetes, OU quota mensuel atteint (2 causes metier sans rapport avec le debit) Debit depasse : attendez avant de reessayer, voir Limites de debit. Quota de signatures du mois ou plafond de SMS du mois atteint : attendre ne resout rien, il faut changer de forfait ou attendre le mois suivant.
500 Erreur serveur Reessayez. Si ca persiste, contactez le support.
502 Source de telechargement invalide ou document trop volumineux Le PDF source ne peut pas etre recupere en toute securite ou depasse la taille autorisee.
503 Dependance de signature indisponible (avec en-tete Retry-After) Panne temporaire. Reessayez apres le delai indique par Retry-After.