Documentation de l'API EasyParafe
Démarrer
Un seul appel crée la demande, place les champs de signature, et envoie l'invitation. Il n'y a pas d'étape intermédiaire à orchestrer : tout réussit, ou rien n'existe.
curl https://easyparafe.fr/api/v1/requests \
-H "Authorization: Bearer pf_live_votre_secret" \
-H "Idempotency-Key: dossier-4821-envoi-1" \
-H "Content-Type: application/json" \
-d '{
"title": "Contrat de bail",
"document": "JVBERi0xLjQK…",
"signers": [{
"name": "Camille Durand",
"email": "camille@exemple.fr",
"fields": [
{"kind": "signature", "page": 0, "x": 0.62, "y": 0.78, "w": 0.25, "h": 0.08},
{"kind": "date", "page": 0, "x": 0.62, "y": 0.88, "w": 0.20, "h": 0.03}
]
}]
}'Le document est le PDF encodé en base64. Les coordonnées sont
normalisées : 0 et 1 désignent les bords de la
page, l'origine est en haut à gauche, et page commence à
0. Chaque signataire doit avoir exactement un champ
signature.
Authentification
Chaque appel porte votre clé en en-tête :
Authorization: Bearer pf_live_…Le secret ne vous est montré qu'une fois, à la délivrance : nous n'en conservons qu'une empreinte, et nous ne pouvons pas vous le rappeler. Une clé perdue se révoque et se remplace.
Une clé inconnue et une clé révoquée rendent la même erreur, volontairement. La clé porte votre palier et votre compte émetteur : les demandes créées par l'API appartiennent à ce compte et apparaissent dans son espace.
Vos conditions générales doivent rester acceptées. À la publication d'une
nouvelle version, l'API continue de répondre pendant
30 jours en ajoutant un en-tête
X-EasyParafe-Warning à ses réponses, et nous prévenons par
e-mail le titulaire du compte. Passé ce délai, les appels sont refusés
jusqu'à l'acceptation depuis l'espace émetteur.
Idempotence
L'en-tête Idempotency-Key est obligatoire sur la
création. Il n'est pas optionnel parce que le dommage qu'il évite est
irrattrapable : un timeout réseau chez vous, une requête rejouée, et le
document part une seconde fois au signataire.
Choisissez une valeur stable pour l'acte métier — un identifiant de dossier, pas un horodatage. Rejouer la même clé avec le même corps rend la réponse mémorisée, à l'identique et sans rien recréer. La même clé avec un corps différent rend une erreur. Les clés sont conservées 24 heures.
Créer une demande — POST /api/v1/requests
| Champ | Type | Détail |
|---|---|---|
title | chaîne | obligatoire, 255 caractères au plus |
document | chaîne | obligatoire, PDF en base64, 10 Mo au plus une fois décodé |
signers | tableau | obligatoire, au moins un ; l'ordre du tableau est l'ordre de signature |
signers[].name | chaîne | obligatoire |
signers[].email | chaîne | obligatoire |
signers[].fields | tableau | kind (signature, date, paraphe), page, x, y, w, h |
notify | booléen | true par défaut : l'invitation part par e-mail |
redirect_url | chaîne | https:// exigé, 500 caractères au plus |
metadata | objet | rendu tel quel à chaque lecture, 4096 octets au plus |
La réponse est un 201 portant la demande — le même objet que
celui rendu par la lecture :
{
"id": "3f1c…",
"status": "sent",
"title": "Contrat de bail",
"created_at": "2026-08-13T10:24:31+02:00",
"sent_at": "2026-08-13T10:24:32+02:00",
"completed_at": null,
"metadata": {"dossier": "4821"},
"signers": [
{"order": 0, "name": "Camille Durand", "email": "camille@exemple.fr",
"status": "pending", "signed_at": null, "sign_url": null}
]
}Avec notify: false, aucun e-mail ne part et
sign_url vous est rendue pour le signataire dont c'est le
tour : vous l'ouvrez dans votre propre parcours. Cette URL vaut session de
signature — traitez-la comme un secret, et ne la journalisez pas.
notify: false ne vaut que pour le premier signataire.
Dans une chaîne à plusieurs signataires, les suivants reçoivent leur
invitation par e-mail au fur et à mesure des signatures. Si votre
parcours doit rester entièrement chez vous, prévoyez-le.
redirect_url est proposée au signataire en bouton sur
l'écran de confirmation, après la signature. Ce n'est jamais une
redirection automatique : cet écran est le seul endroit où le signataire
récupère son document signé et son dossier de preuve.
Lire une demande — GET /api/v1/requests/{id}
Rend le même objet que la création, avec l'état à jour. Tant que le webhook n'existe pas, c'est ainsi que vous apprenez qu'un document est signé : interrogez-nous à un rythme raisonnable — quelques appels par minute suffisent, une signature humaine ne va pas plus vite.
status vaut draft, sent,
viewed, in_progress, signed,
declined ou expired. Chaque signataire porte le
sien, et sa date de signature.
Une demande qui appartient à un autre compte est introuvable, pas
interdite : la réponse est identique à celle d'un identifiant qui n'existe
pas. La lecture ne rend jamais sign_url, même pour une demande
créée avec notify: false.
Le motif d'un refus de signature n'est pas exposé au lot 1 : la
lecture vous dit declined, et le motif saisi par le
signataire figure dans le dossier de preuve. Il rejoindra la réponse
avec le webhook.
Erreurs
Toutes les erreurs ont la même forme. code est un identifiant
stable, destiné à votre code ; message est en français,
destiné à un humain ; field désigne le champ fautif quand il
y en a un.
{"error": {"code": "invalid_signer",
"message": "L'adresse e-mail du signataire est invalide.",
"field": "signers[0].email"}}| Statut | Code | Quand |
|---|---|---|
| 400 | invalid_request | corps illisible, champ absent ou mal formé |
| 400 | invalid_document | base64 illisible, ou fichier qui n'est pas un PDF |
| 400 | document_too_large | PDF décodé au-delà de 10 Mo |
| 400 | invalid_signer | signataire absent, sans nom, ou e-mail invalide |
| 400 | unknown_field_kind | kind hors signature, date, paraphe |
| 400 | missing_signature_field | un signataire sans champ signature |
| 400 | page_out_of_range | page au-delà du document |
| 400 | field_out_of_page | champ qui déborde de la page |
| 400 | missing_idempotency_key | en-tête Idempotency-Key absent |
| 401 | missing_api_key | en-tête Authorization absent ou mal formé |
| 401 | invalid_api_key | clé inconnue, révoquée, ou compte désactivé |
| 402 | subscription_inactive | aucun compte de facturation rattaché à l'émetteur |
| 403 | terms_acceptance_required | délai de grâce des conditions dépassé |
| 404 | request_not_found | demande inexistante, ou appartenant à un autre compte |
| 404 | not_found | chemin inconnu sous /api/v1/ |
| 405 | method_not_allowed | verbe HTTP non accepté sur cette ressource |
| 409 | idempotency_conflict | clé déjà utilisée avec un autre corps, ou requête encore en cours |
| 500 | internal_error | erreur interne ; l'incident est signalé, rejouez avec la même clé d'idempotence |
| 503 | delivery_unavailable | l'invitation n'a pas pu être remise ; réessayez |
Toute réponse de /api/v1/ est du JSON, y compris les erreurs
et les chemins inconnus — à une exception près, décrite dans les
limites ci-dessous. Nous ne redirigeons jamais : un
client qui suit une redirection recevrait une page HTML avec un statut de
succès.
Limites et forfait
- PDF : 10 Mo une fois décodé.
- Titre : 255 caractères.
redirect_url: 500.metadata: 4096 octets sur le JSON sérialisé. - L'unité décomptée est le document envoyé, quel que soit le nombre de signataires ou de champs.
- Un document refusé par le signataire ou archivé ensuite reste décompté : c'est l'envoi qui compte, et le compteur ne redescend jamais en cours de mois.
- Le décompte du forfait se fait par émetteur, sur le mois calendaire : si votre compte porte plusieurs clés, elles partagent le même compteur.
- Un dépassement ne coupe rien : nous vous contactons. Votre production ne s'arrête pas sur un sujet commercial.
- Les appels sont limités par adresse IP, très au-dessus
d'un usage normal — création comme relecture. Au-delà, la réponse est
un 429 en JSON portant le code
rate_limited: patientez quelques secondes, puis réessayez. - Au-delà de 25 Mo de corps de requête, celle-ci est refusée par le serveur d'entrée avant d'atteindre l'API : la réponse est un 413, et c'est le seul cas où elle n'est pas du JSON. Il ne survient pas si votre PDF respecte la limite de 10 Mo ci-dessus.
Ce qui n'est pas encore là
Nous préférons l'écrire plutôt que vous le laisser découvrir.
- Le webhook. Il arrive, et nous ne publierons son contrat que lorsqu'il émettra vraiment. En attendant, la lecture d'une demande est le moyen d'apprendre qu'elle est signée.
- Le motif d'un refus dans la réponse de lecture. Il figure dans le dossier de preuve.
- Un bac à sable et un écran de gestion des clés. En bêta, les clés sont délivrées par nos soins et le premier mois est offert : il remplace le bac à sable.
Une question, un cas qui ne rentre pas ? Écrivez-nous : en bêta, vous avez un interlocuteur direct.