Aller au contenu

Recevoir des webhooks

Un webhook, c’est AssinaJá qui frappe à la porte de votre système lorsqu’il se passe quelque chose sur un document, au lieu que votre système vienne poser la question. Il s’agit d’une requête POST que la plateforme envoie à une adresse qui vous appartient.

Cette page s’adresse aux personnes qui intègrent AssinaJá à un autre programme. Si vous voulez seulement voir ce qui s’est passé sur un document, consultez l’historique du document.

Les webhooks de l’organisation se configurent dans Paramètres → Développeurs → Webhooks, et seul le Créateur de l’organisation a accès à cet onglet. La page comporte trois parties : Adresse et événements, Secret du webhook et, en dessous, Envois.

Dans Adresse et événements :

  1. Dans Adresse du webhook, saisissez l’adresse de votre système — “HTTPS, port 443 ou 8443, sur une adresse publique. Les noms internes et les adresses privées sont refusés.”
  2. Dans Événements à recevoir, choisissez les événements — voir Les événements. “Sans événement sélectionné, rien n’est envoyé. Choisissez-en au moins un.”
  3. Vérifiez que Envoi actif est activé, puis cliquez sur Enregistrer.

Envoyer un événement de test envoie une requête à l’adresse et indique ce qu’elle a répondu — “L’adresse a répondu {code}.” ou “L’envoi de test a échoué : {erreur}”.

L’adresse n’est pas libre. La plateforme la valide avant de l’enregistrer, pour qu’elle ne puisse pas servir à atteindre des machines qui ne vous appartiennent pas :

  • HTTPS, toujours.
  • Port 443 ou 8443, et aucun autre.
  • Un hôte public : ni localhost, ni *.localhost, ni *.internal, ni metadata.google.internal.
  • Une adresse publique. Si le nom se résout vers une adresse privée ou réservée — 10.x, 172.16–31.x, 192.168.x, 127.x, 169.254.x, 100.64.x, multicast, ou leurs équivalents IPv6 — elle est refusée. Toutes les adresses vers lesquelles le nom se résout sont vérifiées, pas seulement la première.

Le refus s’affiche dans votre langue :

Refus Que faire
“Indiquez l’adresse du webhook.” le champ est vide
“L’adresse n’est pas une URL valide.” il manque le schéma, ou il y a une faute de frappe
“L’adresse doit utiliser HTTPS.” remplacez http:// par https://
“Le port doit être 443 ou 8443.” retirez le port de l’adresse, ou utilisez l’un de ceux-ci
“L’hôte est réservé (localhost, .internal, métadonnées cloud) et ne peut pas recevoir de webhooks.” utilisez un nom joignable depuis Internet
“L’adresse IP n’est pas publique.” vous avez saisi directement une adresse IP privée
“Le nom d’hôte ne se résout vers aucune adresse.” vérifiez le DNS
“Impossible de résoudre le nom d’hôte.” le DNS a échoué ; réessayez
“L’hôte se résout vers une adresse non publique.” le nom pointe vers l’intérieur de votre réseau

Lors du choix des événements, “L’un des événements choisis n’est pas reconnu.” signifie que la liste envoyée contient un nom que la plateforme ne connaît pas — vérifiez-le dans le tableau des événements, plus bas. Et “Aucune adresse de webhook configurée — indiquez-en une ou enregistrez d’abord l’abonnement.” s’affiche lorsque vous tentez de vous abonner à des événements avant qu’une adresse existe.

Événement À l’écran Quand il est envoyé
document.completed Document terminé Tout le monde a signé et le document final est prêt
document.rejected Document refusé Un signataire a refusé
document.canceled Document annulé Le document a été annulé
document.expired Document expiré Le délai est passé sans que le document soit finalisé
document.pdf_application_failed Échec de l’application des signatures au PDF La signature n’a pas pu être appliquée au PDF
recipient.signed Signataire a signé Un signataire a signé — une fois par signataire
document.sent Document envoyé pour signature Le document a été publié et les invitations sont parties

Les deux derniers ne sont pas finaux : le document continue d’évoluer ensuite. Ne traitez aucun événement comme « c’est terminé » — consultez le statut du document qui figure dans le corps de la requête.

document.pdf_application_failed est celui qu’il ne faut pas ignorer : il signifie que quelqu’un a signé, mais que la signature n’a pas été intégrée au fichier. Dans AssinaJá, cela apparaît comme Problème technique dans le détail du document, avec Réessayer — voir Suivre et gérer les documents.

L’en-tête Idempotency-Key permet à votre système d’écarter les doublons, mais il n’a pas une forme unique. Elle dépend de la destination de l’événement et de l’événement lui-même :

Destination Événement Clé
Adresse du document (webhookUrl) tous, sauf recipient.signed {documentPublicId}:{event}
Adresse du document recipient.signed {documentPublicId}:{event}:{recipientId}
Adresse de l’organisation tous, sauf recipient.signed {documentPublicId}:{event}:org
Adresse de l’organisation recipient.signed {documentPublicId}:{event}:{recipientId}:org

Conservez et comparez la clé entière, comme une chaîne opaque. Ne la découpez pas. Si vous avez une contrainte d’unicité sur (document, événement) dans votre base de données, elle refusera des livraisons légitimes : recipient.signed arrive une fois par signataire, et un document disposant de sa propre adresse, dans une organisation qui a aussi une adresse configurée, produit deux livraisons du même événement, avec des clés différentes.

Le secret vous permet d’être certain que la requête provient bien d’AssinaJá. Il se trouve dans Paramètres → Développeurs, dans l’onglet Webhooks, sur la carte Secret du webhook. Seul le Créateur de l’organisation le voit.

Secret du webhook :

Le secret sert à vérifier la signature des événements envoyés à votre webhook.

Utilisez Générer un secret la première fois, et Copier pour le conserver. Ensuite, la carte affiche le secret masqué, avec Copier et Renouveler. Ne quittez pas cette page sans l’avoir conservé :

Conservez cette valeur maintenant — elle ne sera plus affichée.

Renouveler génère un nouveau secret sans interrompre les livraisons :

Voulez-vous vraiment renouveler le secret ? L’ancien secret restera valable 24 heures.

Pendant ces 24 heures — “Ancien secret valable encore 24 h.” — les requêtes sont signées avec les deux secrets, séparés par une virgule dans le même en-tête. C’est pourquoi la vérification doit accepter une liste, et non une valeur unique. Passé ce délai, seul le nouveau est utilisé.

Chaque requête contient ces en-têtes :

En-tête De quoi il s’agit
X-AssinaJa-Signature La signature, v1=<hex>, ou plusieurs séparées par une virgule pendant un renouvellement
X-AssinaJa-Event Le nom de l’événement
X-AssinaJa-Delivery Un identifiant nouveau à chaque tentative — il ne sert pas à écarter les doublons
X-AssinaJa-Timestamp L’heure, en secondes Unix
Idempotency-Key Voir le tableau ci-dessus — quatre formes possibles

La signature est un HMAC-SHA256 calculé sur l’heure et le corps de la requête reliés par un point — {timestamp}.{corps} — en hexadécimal minuscule et préfixé par v1=.

La clé n’est pas le secret tel que vous l’avez copié. Le secret est encodé en base64url ; la clé du HMAC, ce sont les octets obtenus en le décodant. Passer le texte directement à la fonction HMAC produit une signature qui ne correspond jamais — c’est la cause la plus fréquente d’échec de la vérification.

const crypto = require('crypto');
function verifyWebhookSignature(secret, timestamp, body, signatureHeader) {
const message = `${timestamp}.${body}`;
// o segredo é base64url — a chave são os bytes descodificados, não o texto
const secretBytes = Buffer.from(secret, 'base64url');
const expected = 'v1=' + crypto
.createHmac('sha256', secretBytes)
.update(message)
.digest('hex');
// durante uma rotação vêm as duas assinaturas
const signatures = signatureHeader.split(',').map(s => s.trim());
return signatures.some(sig => sig === expected);
}

Utilisez le corps tel qu’il est arrivé, brut. Si vous le faites passer par un analyseur JSON puis le resérialisez, les octets changent et la signature ne correspond plus.

Votre réponse Ce qui se passe
2xx Livré. Pas de nouvelle tentative. Le corps de la réponse doit tenir dans 4 Ko.
3xx Nouvelle tentative — les redirections ne sont pas suivies.
4xx Nouvelle tentative, comme pour un 5xx.
5xx Nouvelle tentative.
Pas de réponse en 10 secondes Nouvelle tentative.

Seule une réponse 2xx compte comme livrée. Aucun code ne fait renoncer volontairement la plateforme : si vous voulez qu’une livraison s’arrête, répondez 2xx et ignorez le contenu de votre côté.

Les tentatives sont espacées de 1 min, 2 min, 5 min, 15 min, 30 min, 60 min et 60 min. Il y en a huit au total, et la huitième est une vraie livraison — ce n’est que lorsqu’elle échoue que la livraison est marquée comme en échec.

Le détail de chaque document affiche la dernière livraison de ce document, quel que soit l’événement, sur la carte Intégration — avec Webhook (le nom de l’événement), Statut, Tentatives, Livré le et, en cas d’échec, l’Erreur. C’est le moyen le plus rapide de distinguer « AssinaJá n’a pas envoyé » de « mon serveur n’a pas accepté ». Cette carte ne comporte pas de bouton de renvoi.

Pour consulter l’historique complet de l’organisation et renvoyer les livraisons en échec, allez dans Paramètres → Développeurs → Webhooks, section Envois, sous l’adresse et le secret :

Chaque événement envoyé, avec la réponse de votre adresse. Les envois en échec peuvent être relancés.

Chaque ligne comporte Événement, Adresse, Statut (Remis ou Échec), Tentatives, Date et Dernière erreur ; les lignes en échec proposent Renvoyer, qui répond “Envoi relancé. L’adresse a répondu {code}.” Seul le Créateur de l’organisation a accès à cet écran.

Lorsque le renvoi n’aboutit pas, l’écran indique pourquoi :

Cet envoi n’existe plus.

Cet envoi a déjà été reçu — seuls les envois en échec peuvent être renvoyés.

Impossible de renvoyer cet envoi pour le moment.