Webhooks sortants HMAC
Recevez une notification HTTP signée à chaque événement métier.
Les webhooks sortants permettent à PV-Express de notifier votre infrastructure (n8n, Zapier, PMS interne, Slack...) à chaque événement métier : création de dossier, génération d'un PV, signature complétée, etc. Chaque requête est signée en HMAC-SHA256 pour garantir son origine.
Configurer un endpoint
Direction Settings → Intégrations → Webhooks sortants, puis cliquez sur Ajouter un endpoint. Renseignez :
- URL HTTPS — votre endpoint receveur (HTTP non chiffré refusé)
- Description — libellé interne (ex. "n8n prod", "Slack alertes")
- Événements souscrits — cochez les événements à recevoir
À la création, PV-Express génère un secret HMAC affiché une seule
fois. Stockez-le dans votre vault (Vault, Doppler, .env chiffré).
Vous pouvez le rotater à tout moment depuis la même interface — l'ancien
secret reste valide 24h pour assurer le rolling update côté receveur.
Seuls les membres avec le rôle admin ou propriétaire du cabinet peuvent gérer les webhooks (voir Permissions et rôles).
Les 8 événements typés
| Événement | Déclenché quand |
|---|---|
dossier.created | Un dossier AGOA est créé (manuellement ou via OCR) |
dossier.deleted | Un dossier est supprimé définitivement |
dossier.pv_generated | Le PV est généré et téléchargeable |
dossier.pochette_generated | La pochette ZIP complète est prête |
signature.requested | Une demande de signature Yousign est envoyée |
signature.completed | Tous les signataires ont signé |
company.created | Une nouvelle société est ajoutée au cabinet |
* | Wildcard, reçoit l'intégralité des événements |
Le wildcard est pratique pour un endpoint d'archivage exhaustif (data lake, audit trail). Pour un endpoint métier précis, sélectionnez uniquement les événements pertinents — le volume sera plus faible et le routing côté receveur plus simple.
Sécurité HMAC : vérifier la signature
Chaque requête POST porte trois headers techniques :
X-PvExpress-Signature: t=<timestamp_unix>,v1=<hex_signature>X-PvExpress-Event: dossier.pv_generated(nom de l'événement)X-PvExpress-Timestamp: 1735689600(timestamp Unix en secondes)
La signature v1 est le HMAC-SHA256 de la chaîne <timestamp>.<body_brut>
en utilisant votre secret. Vérifier côté receveur protège contre :
- Les requêtes forgées par un tiers (sans le secret)
- Les attaques par rejeu (le timestamp doit être < 5 minutes)
Exemple Node.js
import crypto from "crypto";
function verifyPvExpressSignature(req, secret) {
const sigHeader = req.headers["x-pvexpress-signature"];
if (!sigHeader) return false;
const parts = Object.fromEntries(
sigHeader.split(",").map((kv) => kv.split("="))
);
const timestamp = parts.t;
const expected = parts.v1;
// Anti-replay : rejeter si > 5 min
const ageSeconds = Math.abs(Date.now() / 1000 - Number(timestamp));
if (ageSeconds > 300) return false;
const payload = `${timestamp}.${req.rawBody}`;
const computed = crypto
.createHmac("sha256", secret)
.update(payload)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected, "hex"),
Buffer.from(computed, "hex")
);
}
req.rawBody doit être le corps brut avant parsing JSON — la plupart
des frameworks (Express, Fastify) exposent un middleware rawBody ou un
parser custom. C'est crucial : si vous re-sérialisez le JSON, l'ordre
des clés peut changer et la signature ne matchera plus.
Logs de delivery
Chaque tentative d'envoi est tracée côté DB (webhook_deliveries) avec :
status—success,failed,pendinghttp_status— code retour de votre endpoint (200, 4xx, 5xx)error— message d'erreur si échec (timeout, DNS, 5xx)duration_ms— durée de l'appelattempt— numéro de tentative (retry 3x avec backoff exponentiel)
Les 100 dernières deliveries par endpoint sont consultables depuis Settings → Intégrations → Webhooks → Voir les logs. En cas d'échec récurrent, l'endpoint passe en état suspendu au bout de 50 échecs consécutifs et un email est envoyé à l'admin du cabinet.
Bonnes pratiques
- Répondre 2xx rapidement — votre endpoint doit acquitter en < 5s. Pour un traitement long, queue le job en async et retournez 200 immédiatement.
- Idempotence — chaque payload contient un
event_idUUID. Stockez-le pour ignorer les doublons en cas de retry. - Rotation du secret — planifiez une rotation tous les 6 mois minimum, ou immédiatement en cas de suspicion de fuite.
- Endpoint de test — utilisez un service comme webhook.site pour inspecter le payload avant de coder l'intégration finale.
Pour des recettes prêtes à l'emploi, voir Brancher n8n, Zapier, Make sur PV-Express.