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
| Champ | Type | Requis | Description |
|---|---|---|---|
name | string | Oui | Nom lisible du webhook (max 255 caractères) |
url | string | Oui | Endpoint HTTPS pour recevoir les événements (max 2048 caractères) |
events | string[] | Non | Types 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"
}
}
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énement | Déclencheur | Description |
|---|---|---|
scan.completed | L'analyse se termine avec succès | Les résultats sont prêts à être récupérés |
scan.failed | L'analyse rencontre une erreur fatale | Détails d'erreur inclus dans le payload |
scan.started | L'analyse commence l'exécution | Transition de queued à running |
scan.cancelled | L'analyse est annulée | Des 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
- Extraire l'en-tête
X-Webhook-Signature - Obtenir le corps brut de la requête (avant tout parsing JSON)
- Calculer
HMAC-SHA256(secret, corps)et encoder en hexadécimal - 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");
});
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 :
| Tentative | Délai | Temps total écoulé |
|---|---|---|
| 1 | Immédiat | 0 |
| 2 | 60 secondes | 1 minute |
| 3 | 120 secondes | 3 minutes |
| 4 (finale) | 240 secondes | 7 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 :
| Champ | Description |
|---|---|
isHealthy | true si les livraisons récentes réussissent |
consecutiveFailures | Nombre d'échecs consécutifs |
lastTriggeredAt | Horodatage de la dernière tentative |
lastStatusCode | Code 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 :
- Corrigez le problème avec votre endpoint
- Réactivez via
PATCHavec{"isActive": true} - 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 :