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éfixeModeEffets
kz_test_TestGratuit, illimité. Documents marqués « TEST », supprimés après 7 jours. Les e-mails ne partent que vers l'adresse du compte.
kz_live_Production1 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.

ChampTypeDétail
filefichierPDF, 10 Mo et 150 pages au maximum. Obligatoire.
signersJSON1 à 10 signataires : name, email, role, round, fields. Obligatoire.
fields[]JSONpage (à 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.
roundentierOrdre de passage. Même rang : signature en parallèle. Rang 2 : invité quand le rang 1 a signé.
titletexteTitre affiché au signataire. Par défaut, le nom du fichier.
messagetexteMot d'accompagnement affiché et repris dans l'e-mail.
sender_nametexteNom affiché au signataire : votre client, pas vous. Par défaut, la raison sociale du compte.
sender_emaile-mailReçoit une copie du document signé et du dossier de preuve, et les avis de refus ou d'expiration.
authenticationtexteemail_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_emailsbooléenfalse : 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_daysentier1 à 90, 14 par défaut.
remindersbooléenRelances automatiques à J+3 et J+7. Actives par défaut.
external_idtexteVotre identifiant interne. Filtrable sur la liste.
metadataJSONObjet libre de 4 Ko au maximum, renvoyé tel quel et dans les webhooks.
redirect_urlURL httpsProposé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

draftsentcompleted, 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éthodeCheminRôle
GET/api/v1/accountSolde de crédits, mode de la clé
POST/api/v1/envelopesCréer, et envoyer
GET/api/v1/envelopesLister (status, external_id, limit, starting_after)
GET/api/v1/envelopes/{id}Lire
POST/api/v1/envelopes/{id}/sendEnvoyer un brouillon
POST/api/v1/envelopes/{id}/cancelAnnuler, crédit restitué
POST/api/v1/envelopes/{id}/remindRelancer, une fois par 20 heures
GET/api/v1/envelopes/{id}/files/original|signed|proofTélécharger les PDF
GET/api/v1/envelopes/{id}/proof.jsonDossier 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":"…"}}.

StatutCodeCause
401unauthorizedClé absente, invalide ou révoquée
402insufficient_creditsPlus de crédit en production
404not_foundDemande inexistante pour cette clé, ou mauvais mode
409invalid_stateAction impossible dans l'état actuel
410files_purgedFichiers supprimés à l'échéance de conservation
413file_too_largePDF au-delà de 10 Mo
422invalid_file, invalid_signer, invalid_fields…Paramètre refusé, le message indique lequel
429rate_limitedPlus 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é.