Documentation
Brancher la signature dans votre logiciel
Une API REST, un widget, des webhooks signés. Le PDF entre, le document signé et son dossier de preuve sortent. Essayez sans compte avec la clé publique ci-dessous.
Démarrer en deux minutes
Clé publique de démonstration, partagée, limitée à 15 demandes par heure et par adresse IP. Les documents sont marqués « DÉMONSTRATION », aucun e-mail ne part, les liens de signature sont renvoyés dans la réponse, et tout est supprimé sous 24 heures.
kz_test_WIvwwwjV5Alafl6nHa6NNTKAIw5hPDMW
# 1. Récupérer un PDF d'exemple
curl -o devis.pdf https://claude.kaezia.fr/demo/devis-exemple.pdf
# 2. Créer une demande de signature
curl https://claude.kaezia.fr/api/v1/envelopes \
-H "Authorization: Bearer kz_test_WIvwwwjV5Alafl6nHa6NNTKAIw5hPDMW" \
-F file=@devis.pdf \
-F title="Devis 2026-114" \
-F 'signers=[{"name":"Claire Martin","email":"claire@client.fr",
"fields":[{"page":1,"x":0.55,"y":0.63,"w":0.36,"h":0.09}]}]'
# 3. Ouvrir le lien signers[0].signing_url renvoyé, signer, puis :
curl https://claude.kaezia.fr/api/v1/envelopes/env_xxx -H "Authorization: Bearer kz_test_WIvwwwjV5Alafl6nHa6NNTKAIw5hPDMW"
curl -O -J https://claude.kaezia.fr/api/v1/envelopes/env_xxx/files/signed -H "Authorization: Bearer kz_test_WIvwwwjV5Alafl6nHa6NNTKAIw5hPDMW"
Pour vos propres essais, ouvrez un compte : la clé de test est gratuite et illimitée, et les e-mails partent vers votre adresse.
Authentification et modes
En-tête Authorization: Bearer <clé>. Deux modes, séparés de bout en bout : une clé de test ne voit jamais les demandes de production.
| Préfixe | Mode | Effets |
|---|---|---|
| kz_test_ | Test | Gratuit, illimité. Documents marqués « TEST », supprimés après 7 jours. Les e-mails ne partent que vers l'adresse du compte. |
| kz_live_ | Production | 1 crédit par document signé. Conservation selon votre paramètre (5 ans par défaut). |
Limite de débit : 120 requêtes par minute et par clé. Au-delà, réponse 429.
Créer une demande
POST /api/v1/envelopes en multipart/form-data (champ file) ou en JSON (file_base64). La demande part immédiatement, sauf draft=1.
| Champ | Type | Détail |
|---|---|---|
| file | fichier | PDF, 10 Mo et 150 pages au maximum. Obligatoire. |
| signers | JSON | 1 à 10 signataires : name, email, role, round, fields. Obligatoire. |
| fields[] | JSON | page (à partir de 1), x, y, w, h en fractions de page, origine en haut à gauche. Sans zone, la signature figure sur le certificat ajouté en dernière page. |
| round | entier | Ordre de passage. Même rang : signature en parallèle. Rang 2 : invité quand le rang 1 a signé. |
| title | texte | Titre affiché au signataire. Par défaut, le nom du fichier. |
| message | texte | Mot d'accompagnement affiché et repris dans l'e-mail. |
| sender_name | texte | Nom affiché au signataire : votre client, pas vous. Par défaut, la raison sociale du compte. |
| sender_email | Reçoit une copie du document signé et du dossier de preuve, et les avis de refus ou d'expiration. | |
| authentication | texte | email_otp (défaut) : code à usage unique envoyé au signataire. none : votre application a déjà identifié la personne ; le dossier de preuve le mentionne. |
| send_emails | booléen | false : aucun e-mail d'invitation, vous distribuez signing_url vous-même. Le code de vérification part quand même si email_otp est actif. |
| expires_in_days | entier | 1 à 90, 14 par défaut. |
| reminders | booléen | Relances automatiques à J+3 et J+7. Actives par défaut. |
| external_id | texte | Votre identifiant interne. Filtrable sur la liste. |
| metadata | JSON | Objet libre de 4 Ko au maximum, renvoyé tel quel et dans les webhooks. |
| redirect_url | URL https | Proposée au signataire après la signature. |
Réponse 201 avec l'objet complet, dont signers[].signing_url et signers[].embed_url.
Cycle de vie
draft → sent → completed, ou declined, expired, cancelled. Le crédit est réservé à l'envoi, consommé quand tous ont signé, restitué dans les autres cas. Le scellement et le dossier de preuve sont produits juste après la dernière signature, en quelques secondes : proof passe de null à un objet, et le webhook envelope.completed part à ce moment-là.
Points d'entrée
| Méthode | Chemin | Rôle |
|---|---|---|
| GET | /api/v1/account | Solde de crédits, mode de la clé |
| POST | /api/v1/envelopes | Créer, et envoyer |
| GET | /api/v1/envelopes | Lister (status, external_id, limit, starting_after) |
| GET | /api/v1/envelopes/{id} | Lire |
| POST | /api/v1/envelopes/{id}/send | Envoyer un brouillon |
| POST | /api/v1/envelopes/{id}/cancel | Annuler, crédit restitué |
| POST | /api/v1/envelopes/{id}/remind | Relancer, une fois par 20 heures |
| GET | /api/v1/envelopes/{id}/files/original|signed|proof | Télécharger les PDF |
| GET | /api/v1/envelopes/{id}/proof.json | Dossier de preuve structuré |
Spécification complète : openapi.yaml (OpenAPI 3.1).
Widget de signature intégrée
Pour faire signer sans quitter votre application. Déclarez d'abord l'origine de votre application dans les paramètres du compte, sinon le navigateur refusera l'affichage.
<script src="https://claude.kaezia.fr/embed.js"></script>
<script>
KaeziaSign.open(embedUrl, { // signers[].embed_url renvoyé par l'API
onSigned: (e) => console.log('signé', e.ref),
onCompleted: (e) => location.reload(),
onDeclined: (e) => console.log('refusé'),
onClose: () => console.log('fenêtre fermée'),
});
</script>
Le widget ouvre la page de signature dans une fenêtre modale et communique par postMessage. Ne vous fiez pas à ces événements pour valider une signature côté serveur : utilisez le webhook.
Webhooks
Renseignez une URL https dans les paramètres du compte. Événements : envelope.sent, signer.signed, envelope.completed, envelope.declined, envelope.expired, envelope.cancelled.
Chaque envoi porte l'en-tête Kaezia-Signature: t=<horodatage>,v1=<hmac>, où le HMAC-SHA256 porte sur la chaîne t.corps avec le secret du compte. Reprises en cas d'échec : 1 min, 5 min, 30 min, 2 h, 6 h, 12 h, 24 h.
<?php
$body = file_get_contents('php://input');
if (!KaeziaSignature::verifyWebhook($_SERVER['HTTP_KAEZIA_SIGNATURE'] ?? '', $body, $secret)) {
http_response_code(400);
exit;
}
$event = json_decode($body, true);
if ($event['type'] === 'envelope.completed') {
$id = $event['data']['envelope']['id'];
file_put_contents("/archives/$id-signe.pdf", $kaezia->downloadFile($id, 'signed'));
file_put_contents("/archives/$id-preuve.pdf", $kaezia->downloadFile($id, 'proof'));
}
http_response_code(200);
Client PHP
Un fichier, sans dépendance, licence MIT : KaeziaSignature.php.
<?php
require 'KaeziaSignature.php';
$kaezia = new KaeziaSignature('kz_live_…');
$envelope = $kaezia->createEnvelope('/var/devis/2026-114.pdf', [
['name' => 'Claire Martin', 'email' => 'claire@client.fr', 'role' => 'Gérante',
'fields' => [['page' => 1, 'x' => 0.55, 'y' => 0.63, 'w' => 0.36, 'h' => 0.09]]],
], [
'title' => 'Devis 2026-114',
'sender_name' => 'Cuisines Durand', // votre client, affiché au signataire
'sender_email' => 'contact@cuisines-durand.fr',
'external_id' => 'DEV-114',
]);
echo $envelope['signers'][0]['signing_url'];
Dans Symfony, déclarez le client comme service et injectez la clé depuis une variable d'environnement. Pour PrestaShop, appelez createEnvelope() depuis un hook sur la validation d'un devis, en stockant external_id dans la commande.
Erreurs
Toutes les erreurs renvoient {"error":{"code":"…","message":"…"}}.
| Statut | Code | Cause |
|---|---|---|
| 401 | unauthorized | Clé absente, invalide ou révoquée |
| 402 | insufficient_credits | Plus de crédit en production |
| 404 | not_found | Demande inexistante pour cette clé, ou mauvais mode |
| 409 | invalid_state | Action impossible dans l'état actuel |
| 410 | files_purged | Fichiers supprimés à l'échéance de conservation |
| 413 | file_too_large | PDF au-delà de 10 Mo |
| 422 | invalid_file, invalid_signer, invalid_fields… | Paramètre refusé, le message indique lequel |
| 429 | rate_limited | Plus de 120 requêtes par minute |
Ce que vous récupérez comme preuve
Pour chaque document signé : le PDF scellé au format PAdES et horodaté, un dossier de preuve PDF (journal chaîné, identification des signataires, horodatages, notifications) avec en pièces jointes le journal JSON et le document d'origine, et le même journal par GET /proof.json. Détail du procédé : politique de signature et de preuve.
Composants libres utilisés
Construit sur mesure en PHP 8.3 et Symfony 7.4 (MIT). Le moteur PDF assemble pyHanko (MIT) pour le scellement PAdES et l'horodatage, pypdf (BSD-3) et ReportLab (BSD) pour la composition, Pillow (MIT-CMU) pour les images de signature. L'affichage des PDF dans le navigateur utilise pdf.js (Apache-2.0), la signature saisie la police Great Vibes (SIL OFL 1.1). Aucun composant sous AGPL n'est utilisé.