Aller au contenu principal
Version: 1.0.0

Webhooks

Les webhooks fournissent des notifications HTTP push en temps réel lorsque des événements d'analyse se produisent, éliminant le besoin de polling. Lorsqu'une analyse se termine, échoue ou déclenche d'autres événements, la plateforme Cert-IX envoie une requête HTTP POST à votre URL enregistrée avec le payload de l'événement.

Pourquoi utiliser les webhooks ?

  • Notifications instantanées — Aucun délai de polling
  • Réduction des appels API — Aucun quota consommé pour les vérifications de statut
  • Architecture événementielle — Déclenchez automatiquement les gates CI/CD, notifications, création de tickets
  • Livraison fiable — Tentatives automatiques avec backoff exponentiel

Enregistrer un webhook

Endpoint

POST /api/v1/webhooks

Portée requise : webhooks:create

Requête

curl -X POST https://api.cert-ix.com/scan-api/api/v1/webhooks \
-H "X-API-Key: $CERTIX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Notifications CI/CD",
"url": "https://votre-serveur.example.com/webhooks/certix",
"events": ["scan.completed", "scan.failed"]
}'

Paramètres de la requête

ChampTypeRequisDescription
namestringOuiNom lisible du webhook (max 255 caractères)
urlstringOuiEndpoint HTTPS pour recevoir les événements (max 2048 caractères)
eventsstring[]NonTypes d'événements à souscrire (défaut : scan.completed, scan.failed)

Réponse (201 Created)

{
"success": true,
"data": {
"id": "wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Notifications CI/CD",
"url": "https://votre-serveur.example.com/webhooks/certix",
"secret": "whsec_a8b2f1d92ffb23344a943df2b6a001fb1028d002e3f4a5b6c7d8",
"events": ["scan.completed", "scan.failed"],
"isActive": true,
"isHealthy": true,
"createdAt": "2026-03-06T10:00:00Z"
}
}
Stockez le secret

Le champ secret est retourné uniquement à la création. Stockez-le en sécurité — vous en aurez besoin pour vérifier les signatures des webhooks.

Événements webhook

ÉvénementDéclencheurDescription
scan.completedL'analyse se termine avec succèsLes résultats sont prêts à être récupérés
scan.failedL'analyse rencontre une erreur fataleDétails d'erreur inclus dans le payload
scan.startedL'analyse commence l'exécutionTransition de queued à running
scan.cancelledL'analyse est annuléeDes résultats partiels peuvent être disponibles

Si events est omis, le webhook souscrit par défaut à ["scan.completed", "scan.failed"].

Format du payload

Lorsqu'un événement se produit, la plateforme envoie un HTTP POST à l'URL de votre webhook.

En-têtes

Content-Type: application/json
X-Webhook-Signature: sha256=a1b2c3d4e5f6...
X-Webhook-Event: scan.completed
X-Webhook-Delivery: del-uuid-ici
X-Webhook-Timestamp: 2026-03-06T10:02:15Z

Corps

{
"event": "scan.completed",
"timestamp": "2026-03-06T10:02:15Z",
"tenantId": "7b5b0610-2947-412f-a869-4683da321fcf",
"data": {
"scanId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"scanType": "nmap",
"name": "Audit réseau hebdomadaire",
"target": "example.com",
"status": "completed",
"progress": 100,
"resultCount": 12,
"durationMs": 135000,
"createdAt": "2026-03-06T10:00:00Z",
"completedAt": "2026-03-06T10:02:15Z"
}
}

Vérification de signature

Chaque livraison de webhook est signée avec votre secret webhook en utilisant HMAC-SHA256. Vérifiez toujours les signatures pour vous assurer que la requête provient de Cert-IX et n'a pas été altérée.

Algorithme de vérification

  1. Extraire l'en-tête X-Webhook-Signature
  2. Obtenir le corps brut de la requête (avant tout parsing JSON)
  3. Calculer HMAC-SHA256(secret, corps) et encoder en hexadécimal
  4. Comparer avec la signature de l'en-tête (utiliser une comparaison en temps constant)

Exemple Python

import hmac
import hashlib

def verifier_webhook(corps_requete: bytes, en_tete_signature: str, secret: str) -> bool:
"""Vérifier la signature du webhook Cert-IX."""
if not en_tete_signature.startswith("sha256="):
return False
recu = en_tete_signature[7:]
attendu = hmac.new(
secret.encode("utf-8"),
corps_requete,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(recu, attendu)

# Exemple Flask
from flask import Flask, request, abort

app = Flask(__name__)
WEBHOOK_SECRET = "whsec_votre_secret_ici"

@app.route("/webhooks/certix", methods=["POST"])
def gerer_webhook():
signature = request.headers.get("X-Webhook-Signature", "")
if not verifier_webhook(request.data, signature, WEBHOOK_SECRET):
abort(401, "Signature invalide")

payload = request.get_json()
evenement = payload["event"]

if evenement == "scan.completed":
scan_id = payload["data"]["scanId"]
# Traiter l'analyse terminée...

return "", 200

Exemple Go

package main

import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"io"
"net/http"
"strings"
)

func verifierWebhook(body []byte, signatureHeader, secret string) bool {
if !strings.HasPrefix(signatureHeader, "sha256=") {
return false
}
recu := signatureHeader[7:]
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(body)
attendu := hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(recu), []byte(attendu))
}

func webhookHandler(w http.ResponseWriter, r *http.Request) {
body, _ := io.ReadAll(r.Body)
signature := r.Header.Get("X-Webhook-Signature")
if !verifierWebhook(body, signature, "whsec_votre_secret_ici") {
http.Error(w, "Signature invalide", http.StatusUnauthorized)
return
}
// Traiter l'événement...
w.WriteHeader(http.StatusOK)
}

Exemple Node.js

const crypto = require("crypto");
const express = require("express");

const app = express();
const WEBHOOK_SECRET = "whsec_votre_secret_ici";

app.post("/webhooks/certix", express.raw({ type: "application/json" }), (req, res) => {
const signature = req.headers["x-webhook-signature"] || "";
if (!signature.startsWith("sha256=")) {
return res.status(401).send("Signature invalide");
}

const recu = signature.slice(7);
const attendu = crypto
.createHmac("sha256", WEBHOOK_SECRET)
.update(req.body)
.digest("hex");

if (!crypto.timingSafeEqual(Buffer.from(recu), Buffer.from(attendu))) {
return res.status(401).send("Signature invalide");
}

const payload = JSON.parse(req.body);
console.log(`Événement : ${payload.event}, Analyse : ${payload.data.scanId}`);
res.status(200).send("OK");
});
Sécurité

Utilisez toujours des fonctions de comparaison en temps constant (hmac.compare_digest en Python, hmac.Equal en Go, crypto.timingSafeEqual en Node.js) pour prévenir les attaques par timing.

Gérer les webhooks

Lister les webhooks

GET /api/v1/webhooks

Portée requise : webhooks:read

Obtenir un webhook

GET /api/v1/webhooks/:webhookId

Mettre à jour un webhook

PATCH /api/v1/webhooks/:webhookId

Portée requise : webhooks:update

Supprimer un webhook

DELETE /api/v1/webhooks/:webhookId

Portée requise : webhooks:delete

Tester un webhook

Envoyez un événement de test pour vérifier que votre endpoint est accessible et correctement configuré.

POST /api/v1/webhooks/:webhookId/test

Portée requise : webhooks:create

Journaux de livraison

Consultez l'historique de livraison d'un webhook, incluant le statut succès/échec, les codes de réponse et les temps de traitement.

GET /api/v1/webhooks/:webhookId/deliveries

Portée requise : webhooks:read

Logique de retry

Les livraisons échouées sont automatiquement retentées avec un backoff exponentiel :

TentativeDélaiTemps total écoulé
1Immédiat0
260 secondes1 minute
3120 secondes3 minutes
4 (finale)240 secondes7 minutes

Une livraison est considérée échouée si :

  • Votre endpoint retourne un code HTTP non-2xx
  • La connexion expire (timeout de 30 secondes)
  • La résolution DNS échoue
  • Le handshake TLS échoue

Surveillance de santé

La plateforme suit la santé des webhooks basée sur le succès des livraisons :

ChampDescription
isHealthytrue si les livraisons récentes réussissent
consecutiveFailuresNombre d'échecs consécutifs
lastTriggeredAtHorodatage de la dernière tentative
lastStatusCodeCode HTTP de la dernière livraison

Désactivation automatique

Si un webhook accumule 10 échecs consécutifs, il est automatiquement désactivé (isActive: false). Pour le réactiver :

  1. Corrigez le problème avec votre endpoint
  2. Réactivez via PATCH avec {"isActive": true}
  3. Envoyez un événement de test pour vérifier

Bonnes pratiques

  • Utilisez HTTPS uniquement — Les URL webhook doivent utiliser https://
  • Vérifiez les signatures à chaque requête
  • Retournez 200 rapidement — Traitez les événements de manière asynchrone pour éviter les timeouts
  • Implémentez l'idempotence — Le même événement peut être livré plus d'une fois lors des retries
  • Validez le type d'événement — Ne traitez que les événements attendus

Prochaines étapes :