docs · pour les développeurs

Webhooks

Des notifications push pour ce qui intéresse vos systèmes : un scan terminé, un nouveau traceur, une version publiée, un export de preuve achevé. Signées, retentées et inspectables.

Endpoints

Créez des endpoints sous Paramètres de l’espace de travail → Développeurs → Webhooks ou via l’API. Seules les URL https sur des hôtes publics sont acceptées ; les adresses privées et internes sont refusées à l’enregistrement. Le secret de signature (whsec_…) est affiché une fois à la création et peut être tourné à tout moment ; après une rotation, vérifiez contre les deux secrets jusqu’à ce que votre déploiement ait rattrapé.

Événements

Douze types d’événements, souscriptibles individuellement ou avec * :

scan.completed · scan.failed · tracker.new · issue.opened · issue.resolved · alert.raised · config.published · version.promoted · export.completed · declaration.updated · install.broken · plan.changed

Vérifier une livraison

Les livraisons suivent la convention Standard Webhooks. Trois en-têtes arrivent avec chaque POST :

webhook-id:        <delivery id>
webhook-timestamp: <unix seconds>
webhook-signature: v1,<base64(hmac_sha256(key, id.timestamp.body))>

La clé HMAC est la partie base64 de votre secret whsec_, décodée en octets bruts. Recalculez la signature sur id + "." + timestamp + "." + body, comparez en temps constant, et rejetez tout ce qui a plus de cinq minutes :

import { createHmac, timingSafeEqual } from 'node:crypto';

function verify(secret, headers, rawBody) {
  const key = Buffer.from(secret.slice('whsec_'.length), 'base64');
  const msg = headers['webhook-id'] + '.' + headers['webhook-timestamp'] + '.' + rawBody;
  const want = createHmac('sha256', key).update(msg).digest();
  const got = Buffer.from(headers['webhook-signature'].split(',')[1], 'base64');
  const fresh = Math.abs(Date.now() / 1000 - Number(headers['webhook-timestamp'])) < 300;
  return fresh && want.length === got.length && timingSafeEqual(want, got);
}

Nouvelles tentatives et relivraison

Une livraison échouée est retentée avec backoff : 1 minute, puis 5 minutes, 30 minutes, 2 heures, 6 heures ; ensuite elle est marquée morte. Chaque tentative, code de réponse et prochaine tentative est visible dans le journal de livraison de l’endpoint, et toute livraison peut être renvoyée à la main ; une relivraison référence l’original. L’historique des livraisons est conservé 90 jours.

Répondre

Répondez rapidement par n’importe quel 2xx et faites le vrai travail en asynchrone ; tout le reste compte comme un échec et planifie une nouvelle tentative. Les livraisons peuvent arriver dans le désordre et, rarement, plus d’une fois ; utilisez webhook-id pour l’idempotence.