Faites signer electroniquement vos documents PDF. Envoyez un PDF, indiquez les signataires, recevez le document signe conforme eIDAS.
# 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.
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.
Aucune authentification necessaire.
curl https://sign.layerone.fr/v1/health
{
"status": "ok",
"service": "sign-api",
"version": "1.0.0"
}
Envoyez un PDF et la liste des personnes qui doivent signer.
| 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) |
| 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.
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
}'
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"])
{
"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
}
| Champ | Description |
|---|---|
| document_id | Identifiant du document (a conserver pour les autres endpoints) |
| signing_urls | URL de signature par signataire (email → lien) |
| original_pdf_hash | Hash SHA-256 du PDF original (preuve d'integrite) |
| message | Message descriptif |
| otp_required | true si un signataire necessite une verification OTP par SMS |
Annulez une demande de signature en cours. Les signataires ne pourront plus acceder au document.
curl -X DELETE https://sign.layerone.fr/v1/documents/{id} \
-H "X-API-Key: VOTRE_CLE"
Verifiez ou en est la signature d'un document.
curl https://sign.layerone.fr/v1/documents/{id} \
-H "X-API-Key: VOTRE_CLE"
{
"success": true,
"document_id": "244",
"title": "Devis_001.pdf",
"status": "SENT",
"completed": false,
"recipients": [
{
"email": "jean@example.com",
"signingStatus": "SENT"
}
]
}
| 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 |
Recuperez le PDF final avec toutes les signatures. Disponible
uniquement quand le statut est COMPLETED.
curl https://sign.layerone.fr/v1/documents/{id}/download \
-H "X-API-Key: VOTRE_CLE"
{
"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).
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.
curl https://sign.layerone.fr/v1/documents/{id}/audit \
-H "X-API-Key: VOTRE_CLE"
{
"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.
Verifie l'integrite cryptographique de la signature PAdES embarquee dans le PDF signe. Confirme que le document n'a pas ete modifie apres signature.
curl https://sign.layerone.fr/v1/documents/{id}/validate \
-H "X-API-Key: VOTRE_CLE"
{
"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.
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.
| Nom | Type | Description |
|---|---|---|
| pdf_base64 * | texte | Le PDF encode en base64 |
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..."}'
{
"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
}
]
}
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).
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.
| 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 |
{
"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.
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.
Si vous utilisez aussi la DocX API, voici le flux recommande :
POST https://docx.layerone.fr/render-document
POST https://sign.layerone.fr/v1/documents/send
GET https://sign.layerone.fr/v1/documents/{id}/download
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.
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)
|
— |
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.
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"]) |
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.
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.
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. |