Webhooks
Cette documentation explique comment intégrer notre système de webhooks pour recevoir des notifications en temps réel concernant les événements des apprenants dans votre application.
Aperçu
Les webhooks permettent à votre application de recevoir des requêtes HTTP POST chaque fois que des événements spécifiques se produisent dans notre système. Au lieu d'interroger notre API pour détecter les changements, les webhooks fournissent un moyen fiable d'être notifié immédiatement lorsque des événements se produisent.
Types d'Événements
Nous prenons en charge les types d'événements webhook suivants :
| Type d'Événement | Description | Charge Utile |
|---|---|---|
learner.updated | Déclenché quand les informations d'un apprenant sont mises à jour | Objet Learner |
learner.started | Déclenché quand un apprenant commence une nouvelle activité | Objet Learner |
learner.completed | Déclenché quand un apprenant termine une activité | Objet Learner |
Structure de la Charge Utile du Webhook
Toutes les requêtes webhook seront envoyées sous forme de requêtes HTTP POST avec la structure JSON suivante :
Corps
Des types plus détaillés suivent
interface FullLearner {
attempt: {
id: string;
userId: string;
organizationId: string;
moduleId: string;
courseId: string;
completedAt: Date | null;
data: Record<string, string>;
createdAt: Date;
updatedAt: Date;
status: "completed" | "passed" | "failed" | "in-progress" | "not-started";
score?: { raw?: number; max?: number; min?: number };
module: Module;
} | null;
user: {
id: string;
email: string;
name: string;
};
connection: UserToCourseType | UserToCollectionType;
}
Tentative
interface FullLearnerAttempt {
id: string;
userId: string;
organizationId: string;
moduleId: string;
courseId: string;
completedAt: Date | null;
data: Record<string, string>;
createdAt: Date;
updatedAt: Date;
status: "completed" | "passed" | "failed" | "in-progress" | "not-started";
score?: { raw?: number; max?: number; min?: number };
module: Module;
}
Utilisateur
interface FullLearnerUser {
id: string;
email: string;
name: string;
}
Connexion
Soit une connexion à un cours ou à une collection :
Connexion au cours
interface UserToCourseType {
userId: string;
organizationId: string;
courseId: string;
externalId: string | null;
connectType: "invite" | "request";
connectStatus: "pending" | "accepted" | "rejected";
createdAt: Date;
updatedAt: Date;
}
Connexion à la collection
interface UserToCollectionType {
userId: string;
organizationId: string;
collectionId: string;
connectType: "invite" | "request";
connectStatus: "pending" | "accepted" | "rejected";
createdAt: Date;
updatedAt: Date;
}
En-têtes de Requête
Chaque requête webhook inclut les en-têtes suivants :
Content-Type: application/jsonwebhook-timestamp: 2024-01-15T10:30:00.000Z- Horodatage ISO quand le webhook a été envoyéwebhook-signature: <signature>- Signature HMAC-SHA256 pour vérification (voir section Sécurité)- Tous les en-têtes personnalisés que vous avez configurés pour votre endpoint webhook
Sécurité et Vérification
Vérification de Signature
Chaque requête webhook inclut une signature dans l'en-tête webhook-signature. Cette signature est générée en utilisant HMAC-SHA256 avec votre secret webhook.
Génération de signature :
HMAC-SHA256(secret, horodatage + "." + corps_requête)
Exemple de vérification (Node.js) :
const crypto = require("crypto");
function verifyWebhookSignature(secret, timestamp, body, signature) {
const expectedSignature = crypto
.createHmac("sha256", secret)
.update(`${timestamp}.${body}`)
.digest("hex");
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature));
}
// Utilisation dans votre gestionnaire de webhook
app.post("/webhook", (req, res) => {
const timestamp = req.headers["webhook-timestamp"];
const signature = req.headers["webhook-signature"];
const body = JSON.stringify(req.body);
if (!verifyWebhookSignature(webhookSecret, timestamp, body, signature)) {
return res.status(401).send("Non autorisé");
}
// Traiter le webhook
console.log("Événement reçu:", req.body.event);
res.status(200).send("OK");
});
Bonnes Pratiques
- Toujours vérifier les signatures - Ne jamais traiter des webhooks sans vérification de signature
- Vérifier les horodatages - Rejeter les webhooks avec des horodatages trop anciens/futurs
- Répondre rapidement - Répondre avec un code de statut 2xx dans les 10 secondes
- Gérer l'idempotence - Le même événement peut être livré plusieurs fois
Politique de Nouvelle Tentative
Notre système de webhook implémente une stratégie de nouvelle tentative avec backoff exponentiel :
| Tentative | Délai |
|---|---|
| 1ère | Immédiat |
| 2ème | 5 secondes |
| 3ème | 1 minute |
| 4ème | 5 minutes |
| 5ème | 30 minutes |
| 6ème | 2 heures |
| 7ème | 5 heures |
| 8ème | 10 heures |
Notes importantes :
- Les webhooks sont retentés pendant jusqu'à 7 jours
- Une livraison est considérée comme réussie quand votre endpoint retourne un code de statut HTTP 2xx
- Après la tentative finale, la livraison du webhook est marquée comme échouée et ne sera plus retentée
- Les livraisons échouées sont automatiquement nettoyées après la période d'expiration
Exigences des Endpoints
Votre endpoint webhook doit :
- Accepter les requêtes POST avec
Content-Type: application/json - Répondre avec des codes de statut 2xx (200, 201, 204) pour un traitement réussi
- Répondre dans les 10 secondes pour éviter les timeouts
- Utiliser HTTPS pour les environnements de production
- Être publiquement accessible depuis nos serveurs
Tester Votre Intégration
Exemple de Gestionnaire de Webhook
Voici un exemple de gestionnaire de webhook de base :
const express = require("express");
const crypto = require("crypto");
const app = express();
app.use(express.json());
app.post("/webhook", (req, res) => {
try {
// 1. Vérifier la signature
const timestamp = req.headers["webhook-timestamp"];
const signature = req.headers["webhook-signature"];
const body = JSON.stringify(req.body);
if (!verifySignature(timestamp, body, signature)) {
return res.status(401).send("Non autorisé");
}
// 2. Traiter l'événement
const { event, data } = req.body;
switch (event) {
case "learner.updated":
console.log(`L'apprenant ${data.id} a été mis à jour`);
// Votre logique métier ici
break;
case "learner.started":
console.log(`L'apprenant ${data.id} a commencé une activité`);
// Votre logique métier ici
break;
case "learner.completed":
console.log(`L'apprenant ${data.id} a terminé une activité`);
// Votre logique métier ici
break;
default:
console.log(`Type d'événement inconnu: ${event}`);
}
// 3. Répondre rapidement
res.status(200).send("OK");
} catch (error) {
console.error("Erreur de traitement du webhook:", error);
res.status(500).send("Erreur Interne du Serveur");
}
});
function verifySignature(timestamp, body, signature) {
const expectedSignature = crypto
.createHmac("sha256", process.env.WEBHOOK_SECRET)
.update(`${timestamp}.${body}`)
.digest("hex");
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature));
}
app.listen(3000, () => {
console.log("Serveur webhook en cours d'exécution sur le port 3000");
});
Dépannage
Problèmes Courants
Échec des livraisons de webhook :
- Vérifiez que votre endpoint retourne des codes de statut 2xx
- Vérifiez que votre endpoint est publiquement accessible
- Assurez-vous que votre serveur répond dans les 10 secondes
- Vérifiez que la vérification de signature fonctionne correctement
Pas de réception de webhooks :
- Confirmez que votre webhook est activé dans le tableau de bord
- Vérifiez que les bons événements sont sélectionnés
- Vérifiez que l'URL du webhook est correcte et accessible
Événements en double :
- Implémentez l'idempotence dans votre gestionnaire de webhook
- Utilisez l'horodatage de l'événement ou un identifiant unique pour détecter les doublons
Support
Si vous rencontrez des problèmes avec la livraison des webhooks ou avez besoin d'aide pour l'implémentation, veuillez contacter notre équipe de support avec :
- L'URL de votre endpoint webhook
- Les types d'événements spécifiques que vous essayez de recevoir
- Tous messages d'erreur ou logs de votre endpoint
- L'heure approximative où le problème s'est produit
Limites de Débit
- Les livraisons de webhook sont traitées toutes les 5 secondes
- Aucune limite de débit spécifique n'est imposée aux endpoints individuels
- Cependant, les endpoints constamment lents ou défaillants peuvent être temporairement désactivés
N'oubliez pas d'implémenter une gestion d'erreur et une journalisation appropriées dans vos gestionnaires de webhook pour assurer un traitement fiable des événements.