Approbation de documents et signature
Outre le consentement aux cookies, le SDK peut enregistrer qu’une personne a approuvé une version précise d’un document — des conditions d’utilisation, un contrat de vente à distance, une notice d’information sur la protection des données, ou un document généré par votre propre système.
Le code d’approbation ne fait pas partie de cmp.js. Il est chargé automatiquement la première fois que vous appelez l’une des deux méthodes ci-dessous (ou d’emblée avec data-modules="documents") ; voir Bundles et modules à la demande.
Deux façons de recueillir une approbation
Section intitulée « Deux façons de recueillir une approbation »1. CMP.showDocumentApproval(slug, options) — la boîte de dialogue de HashEntry
Section intitulée « 1. CMP.showDocumentApproval(slug, options) — la boîte de dialogue de HashEntry »Charge la version active du document, l’affiche dans une boîte de dialogue avec les boutons « Accepter » et « Refuser », et enregistre l’approbation lorsque la personne accepte.
const result = await CMP.showDocumentApproval('distance-sales-agreement', { language: 'en', // facultatif, par défaut la langue du SDK metadata: { order_id: 'ORD-54321' }, // facultatif approvalToken: tokenFromYourBackend // facultatif / requis, voir ci-dessous});
if (result.success && result.decision === 'accepted') { continueCheckout(result.consent_token);} else if (result.decision === 'rejected') { // la personne a refusé} else { showError(result.error); // { code, status, message }}| Option | Description |
|---|---|
language | Langue de la version du document à afficher. |
metadata | Paires clé/valeur stockées avec l’enregistrement (fusionnées avec CMP.setMetadata). |
approvalToken | Jeton d’approbation à usage unique émis par votre backend. |
Par souci de rétrocompatibilité, un objet simple ne contenant aucune de ces clés est traité comme metadata.
Un refus ferme la boîte de dialogue et déclenche document:rejected ; aucun enregistrement n’est envoyé au serveur. Si l’enregistrement échoue avec une erreur temporaire, la boîte de dialogue reste ouverte et la personne peut appuyer de nouveau sur « Accepter » — la nouvelle tentative utilise la même clé d’idempotence (et le même jeton).
2. CMP.approveDocument(slug, options) — votre propre interface
Section intitulée « 2. CMP.approveDocument(slug, options) — votre propre interface »Enregistre une approbation sans rien afficher, pour une case à cocher dans votre formulaire, votre propre visionneuse de contrats ou un pavé de signature que vous affichez vous-même.
const result = await CMP.approveDocument('terms-of-service', { approvalToken: tokenFromYourBackend, metadata: { order_id: 'ORD-54321' }});| Option | Envoyé en tant que | Description |
|---|---|---|
version_id | document_version_id | Version à approuver. Si elle est omise, le SDK détermine la version active pour language. |
version | — | Libellé de version renvoyé dans le résultat lorsque vous transmettez version_id. |
language | language | Langue de la version. |
decision | decision | 'accepted' (par défaut) ou 'rejected'. |
visitor_id | visitor_id | Votre référence pour la personne (100 caractères max.). Ignoré lorsqu’un jeton d’approbation est utilisé — c’est le subject du jeton qui est stocké à la place. |
approvalToken | approval_token | Jeton d’approbation à usage unique. |
document_content_base64 | custom_document_content | Contenu d’un document généré par votre système (HTML, texte brut ou PDF ; jusqu’à environ 500 Ko une fois décodé). |
document_mime_type | custom_document_mime_type | text/html, text/plain ou application/pdf. |
signature | champs de premier niveau | Voir Champs de signature. |
metadata | metadata | Paires clé/valeur stockées avec l’enregistrement. |
Deux appels pour le même document, la même version et la même décision qui se chevauchent dans le temps partagent une seule requête et un seul résultat ; un double clic ne crée donc pas deux enregistrements.
Jetons d’approbation à usage unique
Section intitulée « Jetons d’approbation à usage unique »Le SDK navigateur signe ses requêtes avec la clé API du site, qui est visible dans le code source de votre page. Une approbation de document envoyée depuis un navigateur prouve donc que quelqu’un ayant accès à votre page l’a envoyée ; le nom ou l’adresse e-mail qu’elle contient est simplement ce qui a été saisi.
Un jeton d’approbation permet à votre backend de se porter garant de l’identité de la personne qui approuve :
- Votre backend — qui connaît l’utilisateur connecté — appelle
POST /tool/v1/s2s/approval-tokens(voir API REST) et reçoit un jeton (hat_…). - Vous transmettez le jeton à la page et le remettez au SDK en tant que
approvalToken. - Le SDK l’envoie en tant que champ de premier niveau
approval_token. Le serveur le consomme de manière atomique, tire l’identité de la personne du jeton plutôt que du navigateur, et stocke l’enregistrement avecidentity_assurance: tenant_attested.
Règles :
- Un jeton est valable pour un seul site et un seul document (éventuellement une seule version), pour une durée limitée (10 minutes par défaut, 1 heure au maximum), et une seule fois.
- Un document peut être configuré dans le tableau de bord pour exiger un jeton. Pour un tel document, le SDK échoue immédiatement, sans envoyer de requête, lorsqu’aucun jeton n’est fourni :
error.code = "APPROVAL_TOKEN_REQUIRED". Le serveur applique la même règle. - Les codes du serveur sont transmis tels quels :
APPROVAL_TOKEN_REQUIRED,APPROVAL_TOKEN_INVALID(inconnu, expiré, déjà utilisé, ou émis pour un autre site/document),APPROVAL_TOKEN_CONFLICT(un champ du signataire ou le contenu du document envoyé par le navigateur contredit ce dont le jeton se porte garant). - En cas de défaillance réseau ou de réponse 5xx, le SDK réessaie avec le même jeton et la même clé d’idempotence ; le serveur traite la répétition comme la même requête. Après une réponse 4xx définitive, rien n’est retenté, et les approbations ne sont jamais stockées dans la file d’attente hors ligne. Émettez un nouveau jeton pour réessayer.
Champs de signature
Section intitulée « Champs de signature »approveDocument accepte un objet signature pour les approbations recueillies avec une signature dessinée ou une déclaration explicite. Le SDK n’inclut pas de pavé de signature : vous affichez le pavé (ou la case à cocher de déclaration) et transmettez le résultat.
await CMP.approveDocument('service-contract', { approvalToken: tokenFromYourBackend, signature: { image_base64: canvas.toDataURL('image/png'), mime_type: 'image/png', signer_name: 'Jane Doe', declaration_text: 'I have read and accept the service contract.', input_type: 'touch', stroke_count: 14, drawing_duration_ms: 3200, screen_resolution: '390x844' }});| Champ | Envoyé en tant que | Remarques |
|---|---|---|
image_base64 | signature_image | PNG, JPEG ou WebP ; jusqu’à environ 150 Ko une fois décodé. |
mime_type | signature_mime_type | |
signer_name, signer_email, signer_phone, signer_id_number | mêmes noms | Ce que le signataire déclare à son propre sujet, sauf si un jeton d’approbation s’en porte garant. |
declaration_text | declaration_text | La phrase à laquelle la personne a donné son accord (1000 caractères max.). |
input_type | input_type | touch, mouse ou pen. |
stroke_count, drawing_duration_ms, strokes_data | mêmes noms | Télémétrie du tracé. |
screen_resolution | screen_resolution |
Tous ces éléments sont envoyés en tant que champs de premier niveau de la requête, et non à l’intérieur de metadata. Les champs otp_verified / otp_reference ne sont pas acceptés depuis un navigateur ; ils ne sont pris en compte que sur la route serveur à serveur ou par l’intermédiaire d’un jeton d’approbation.
Ce que signifie ici “signature électronique simple”
Section intitulée « Ce que signifie ici “signature électronique simple” »Un enregistrement créé de cette manière est une signature électronique simple : des données sous forme électronique (l’image dessinée, la déclaration, le contexte technique) qui sont jointes à une version précise d’un document et que le signataire a utilisées pour signer. Ce n’est pas une signature électronique avancée ou qualifiée — aucun certificat n’est délivré au signataire, et HashEntry ne vérifie pas l’identité du signataire.
Ce que montre la preuve :
- quelle version du document (par hash de contenu) a été approuvée, quand, depuis quelle adresse IP et quel user agent, et avec quelles informations déclarées sur le signataire ;
- que l’enregistrement n’a pas été modifié depuis son écriture (voir Vérifier une preuve hors ligne) ;
- dans quelle mesure l’identité est étayée, dans le champ
identity_assurance:
| Valeur | Signification |
|---|---|
self_declared | Les informations sur le signataire proviennent du navigateur. Personne ne les a vérifiées. |
tenant_attested | Votre backend s’est porté garant de la personne, soit avec un jeton d’approbation à usage unique, soit en déclarant une vérification OTP effectuée sur la route serveur à serveur. L’assurance est la vôtre : HashEntry enregistre que vous l’avez attestée, et non que HashEntry l’a vérifiée. |
Le fait qu’une signature électronique simple soit suffisante pour un contrat donné dépend du droit applicable et du type d’opération ; certaines opérations exigent une forme particulière. Demandez à votre conseil juridique quel niveau il vous faut.
Lorsque la version du document change
Section intitulée « Lorsque la version du document change »Si le serveur répond 409 CONFIG_OUTDATED, le SDK relit la version active du document :
- inchangée (le cache du serveur était à froid) → la même requête est envoyée une fois de plus ;
- modifiée → l’approbation n’est pas renvoyée. Le résultat est
success: falseavecerror.code = "DOCUMENT_VERSION_CHANGED", etdocument:errorse déclenche.
Dans le second cas, affichez de nouveau le document (la personne n’a pas vu la nouvelle version) et recueillez une nouvelle approbation — avec un nouveau jeton si vous utilisez des jetons.
Résultats, événements et erreurs
Section intitulée « Résultats, événements et erreurs »CMP.on('document:approved', ({ slug, version, consentId }) => {});CMP.on('document:rejected', ({ slug, version }) => {});CMP.on('document:error', ({ slug, version, code, status, message }) => {});error.code | Que faire |
|---|---|
MODULE_LOAD_FAILED | Le fichier du module n’a pas pu être chargé (réseau, bloqueur de publicité, CSP). Appelez de nouveau la méthode pour réessayer. |
DOCUMENT_NOT_FOUND, VERSION_NOT_FOUND | Vérifiez le slug, que le document est rattaché au site et qu’il possède une version active dans la langue demandée. |
APPROVAL_TOKEN_REQUIRED | Émettez un jeton sur votre backend et transmettez-le. |
APPROVAL_TOKEN_INVALID, APPROVAL_TOKEN_CONFLICT | Émettez un nouveau jeton ; assurez-vous que les champs du signataire correspondent au jeton. |
DOCUMENT_VERSION_CHANGED | Affichez de nouveau le document. |
CONFIG_OUTDATED | La version que vous avez transmise n’est pas active et n’a pas pu être revérifiée. |
NETWORK_ERROR, TIMEOUT, RATE_LIMIT_EXCEEDED, QUEUE_OVERLOADED | Temporaire. Laissez la personne réessayer. |
VALIDATION_ERROR et erreurs de taille (SIGNATURE_IMAGE_TOO_LARGE, CUSTOM_DOCUMENT_TOO_LARGE, …) | Corrigez la requête. |
Ne considérez une approbation comme donnée que lorsque result.success === true. Conservez result.consent_token : il identifie l’enregistrement pour une vérification et un export de preuve ultérieurs.