Menu de la documentation

Webhooks de consentement : des événements signés vers votre serveur

Recevez les événements consent.recorded et consent.withdrawn sur votre serveur, vérifiez la signature HMAC avec le SDK et testez la livraison signée.

Sur cette page

Les webhooks de consentement poussent chaque décision vers votre serveur sous forme de POST HTTP signé : consent.recorded quand un visiteur accorde au moins une catégorie, consent.withdrawn quand il refuse ou se rétracte. C'est ce qui rend le droit de retrait applicable côté serveur : quand un visiteur se rétracte, votre serveur l'apprend et peut purger ou cesser le traitement.

Créer un webhook

Deux chemins, même contrat :

  • Dans l'app : l'assistant de configuration sur la page Intégration du Builder : saisissez l'URL de réception (endpoint), avec la possibilité de limiter le webhook à une seule bannière (par défaut : tout l'espace de travail).
  • Via MCP : l'outil configure_consent_webhook, si vous pilotez FlowConsent depuis Claude ou un autre client MCP.

Dans les deux cas, vous recevez un secret de signature au format whsec_….

La signature

Chaque livraison porte un en-tête X-FlowConsent-Signature, sur le modèle de Stripe :

X-FlowConsent-Signature: t=1722326400,v1=5f8a1c…

où t est un horodatage Unix et v1 = HMAC-SHA256(secret, "<t>.<corps brut>"). L'horodatage limite le rejeu : rejetez les livraisons dont le t est trop ancien.

Vérifier avec le SDK serveur

@flowconsent/server-sdk fournit verifyWebhookSignature : comparaison en temps constant, tolérance de rejeu de 300 s par défaut :

app/api/flowconsent-webhook/route.ts
ts
import { verifyWebhookSignature } from '@flowconsent/server-sdk'
 
export async function POST(request: Request) {
  const rawBody = await request.text() // corps brut, avant tout JSON.parse
  const check = await verifyWebhookSignature(
    rawBody,
    request.headers.get('X-FlowConsent-Signature'),
    process.env.FLOWCONSENT_WEBHOOK_SECRET!,
  )
  if (!check.valid) {
    // check.reason : 'missing_header', 'malformed_header',
    // 'timestamp_out_of_tolerance', 'signature_mismatch'
    return new Response('invalid signature', { status: 400 })
  }
 
  const event = JSON.parse(rawBody)
  if (event.test) return new Response('ok') // événement de test du wizard : jamais un vrai consentement
 
  if (event.type === 'consent.withdrawn') {
    // arrêter les traitements pour event.visitor_id, purger les systèmes aval…
  }
  return new Response('ok')
}

Les événements

consent.recorded : format exact de livraison
json
{
  "id": "5f0e0a1c-…",
  "type": "consent.recorded",
  "banner": "FC-A1B2C3",
  "visitor_id": "v_8f3d…",
  "action": "accept_all",
  "categories": {
    "functional": true,
    "analytics": true,
    "marketing": false,
    "preferences": false
  },
  "services": { "google-analytics": true },
  "policy_version": "3",
  "occurred_at": "2026-07-30T09:41:22.000Z"
}
  • type vaut consent.recorded quand au moins une des catégories analytics, marketing, preferences est accordée ; sinon consent.withdrawn.
  • banner est le code de licence public de la bannière : les identifiants internes ne sont jamais exposés.
  • visitor_id est l'identifiant pseudonyme que l'on retrouve dans les journaux de consentement et dans le decision.visitorId du SDK serveur.
  • occurred_at est en ISO 8601.

Tester la livraison

Le « test d'envoi » de l'assistant envoie un événement consent.test à votre URL de réception, signé avec votre vrai secret et portant un marqueur explicite "test": true : ne le traitez jamais comme un consentement réel. Il confirme, de bout en bout, que votre serveur reçoit, vérifie et répond. Le résultat de livraison (statut HTTP, durée) s'affiche dans l'app.

Livraison et réessais

  • 3 tentatives par livraison, avec un délai croissant entre elles (250 ms, 500 ms, 1 s) et un délai maximal de 5 s chacune.
  • Une réponse 4xx (hors 429) arrête les réessais : réessayer n'y changerait rien.
  • Répondez 2xx vite et traitez en asynchrone : tout le reste compte comme une livraison échouée.
  • Le statut et l'heure de la dernière livraison sont visibles sur chaque webhook dans l'app.

Mettez votre site en conformité aujourd'hui.

Gratuit jusqu'à 25 000 sessions par mois. Sans carte bancaire, sans engagement.