Webhooks sortants HMAC

Recevez une notification HTTP signée à chaque événement métier.

Mis à jour le 1 mai 2026

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énementDéclenché quand
dossier.createdUn dossier AGOA est créé (manuellement ou via OCR)
dossier.deletedUn dossier est supprimé définitivement
dossier.pv_generatedLe PV est généré et téléchargeable
dossier.pochette_generatedLa pochette ZIP complète est prête
signature.requestedUne demande de signature Yousign est envoyée
signature.completedTous les signataires ont signé
company.createdUne 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 :

  1. Les requêtes forgées par un tiers (sans le secret)
  2. 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 :

  • statussuccess, failed, pending
  • http_status — code retour de votre endpoint (200, 4xx, 5xx)
  • error — message d'erreur si échec (timeout, DNS, 5xx)
  • duration_ms — durée de l'appel
  • attempt — 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_id UUID. 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.