Exemples de Charges Utiles
Cette page fournit des exemples complets et réels de charges utiles webhook pour chaque type d'événement. Utilisez ces exemples pour comprendre la structure des données et construire vos gestionnaires de webhook.
Structure de Requête
Toutes les notifications webhook sont envoyées comme des requêtes HTTP POST avec les caractéristiques suivantes :
Méthode HTTP : POST Content-Type : application/json Authentification : Méthode d'authentification configurée (Bearer, Basic Auth, Clé API, etc.)
Exemple d'En-têtes de Requête
POST /webhooks/beedeez HTTP/1.1
Host: api.votreentreprise.com
Content-Type: application/json
Authorization: Bearer votre-token-bearer-secret
X-Webhook-Source: beedeez
Content-Length: 1234
Événement Certificat Complété
Déclenché lorsqu'un utilisateur complète avec succès un certificat.
Type d'Événement
certificate_completed
Exemple de Charge Utile Complète
{
"_id": "507f1f77bcf86cd799439011",
"_userId": "507f191e810c19729de860ea",
"_ownerId": "507f191e810c19729de860eb",
"_badgeId": "507f191e810c19729de860ec",
"creationDate": "2024-11-27T10:30:00.000Z",
"expires": "2025-11-27T10:30:00.000Z",
"disabled": false,
"expiryReminderSent": false,
"_lessonActiveIds": [
"507f191e810c19729de860ed",
"507f191e810c19729de860ee",
"507f191e810c19729de860ef"
],
"ruleData": {
"type": "certification",
"name": "Certificat Formation Sécurité",
"description": "Compléter tous les modules de formation sécurité",
"validityDurationDays": 365
},
"createdAt": "2024-11-27T10:30:00.000Z",
"updatedAt": "2024-11-27T10:30:00.000Z",
"__v": 0
}
Description des Champs
| Champ | Type | Description |
|---|---|---|
_id | ObjectId | Identifiant unique pour cette instance de badge/certificat |
_userId | ObjectId | ID de l'utilisateur qui a obtenu le certificat |
_ownerId | ObjectId | ID de l'organisation/propriétaire |
_badgeId | ObjectId | ID de la définition/modèle du badge |
creationDate | Date ISO 8601 | Quand l'utilisateur a complété les exigences du certificat |
expires | Date ISO 8601 | Quand le certificat expire (null si pas d'expiration) |
disabled | Boolean | Si le certificat a été désactivé/révoqué |
expiryReminderSent | Boolean | Si un rappel d'expiration a été envoyé |
_lessonActiveIds | Array\<ObjectId> | IDs des activités de leçon qui ont validé ce certificat |
ruleData | Object | Données supplémentaires de la définition de la règle du badge |
createdAt | Date ISO 8601 | Quand cet enregistrement de certificat a été créé dans la base de données |
updatedAt | Date ISO 8601 | Quand cet enregistrement de certificat a été mis à jour pour la dernière fois |
__v | Number | Clé de version MongoDB |
Exemple de Cas d'Usage
Scénario : Notifier le système RH quand un employé complète une certification de sécurité
// Gestionnaire de webhook Node.js
app.post('/webhooks/beedeez/certificats', async (req, res) => {
const certificate = req.body;
if (certificate.ruleData.type === 'certification') {
await systemeRH.mettreAJourDossierEmploye({
employeId: certificate._userId,
certification: {
nom: certificate.ruleData.name,
dateCompletion: certificate.creationDate,
dateExpiration: certificate.expires,
certificatId: certificate._id,
},
});
// Envoyer une notification au manager
await serviceNotification.envoyer({
destinataire: 'manager@entreprise.com',
sujet: 'Certification Employé Complétée',
corps: `L'employé a complété ${certificate.ruleData.name}`,
});
}
res.status(200).json({ received: true });
});
Événement Certificat Expiré
Déclenché lorsqu'un certificat atteint sa date d'expiration.
Type d'Événement
certificate_expired
Exemple de Charge Utile Complète
{
"_id": "507f1f77bcf86cd799439011",
"_userId": "507f191e810c19729de860ea",
"_ownerId": "507f191e810c19729de860eb",
"_badgeId": "507f191e810c19729de860ec",
"creationDate": "2023-11-27T10:30:00.000Z",
"expires": "2024-11-27T10:30:00.000Z",
"disabled": false,
"expiryReminderSent": true,
"_lessonActiveIds": ["507f191e810c19729de860ed", "507f191e810c19729de860ee"],
"ruleData": {
"type": "certification",
"name": "Certification Premiers Secours",
"description": "Formation premiers secours et intervention d'urgence",
"validityDurationDays": 365
},
"createdAt": "2023-11-27T10:30:00.000Z",
"updatedAt": "2024-11-27T10:30:00.000Z",
"__v": 0
}
Description des Champs
Les champs sont identiques à l'événement certificate_completed. Différences clés :
- La date
expiresest dans le passé (le certificat a expiré) expiryReminderSentest typiquementtrue(un rappel a été envoyé avant l'expiration)creationDatemontre la date de complétion originale (il y a 1 an dans cet exemple)
Exemple de Cas d'Usage
Scénario : Déclencher un workflow de re-certification quand un certificat expire
// Gestionnaire de webhook Node.js
app.post('/webhooks/beedeez/certificats', async (req, res) => {
const certificate = req.body;
// Vérifier si le certificat a expiré
const maintenant = new Date();
const dateExpiration = new Date(certificate.expires);
if (dateExpiration < maintenant) {
// Déclencher le workflow de re-certification
await moteurWorkflow.demarrer({
workflow: 'recertification',
userId: certificate._userId,
certificateId: certificate._badgeId,
certificatNom: certificate.ruleData.name,
dateExpiration: certificate.expires,
});
// Mettre à jour le suivi de conformité
await systemeConformite.marquerCommeExpire({
employeId: certificate._userId,
certificatId: certificate._id,
necessiteRenouvellement: true,
});
// Envoyer une notification à l'employé et au manager
await serviceNotification.envoyerAlerteCertificatExpire({
userId: certificate._userId,
certificatNom: certificate.ruleData.name,
dateExpiration: certificate.expires,
});
}
res.status(200).json({ received: true });
});
Gestion de Plusieurs Types d'Événements
Si votre point de terminaison webhook gère plusieurs types d'événements, vous pouvez les différencier en utilisant la structure de la charge utile ou des métadonnées supplémentaires.
Exemple : Gestionnaire Multi-Événements
app.post('/webhooks/beedeez', async (req, res) => {
const payload = req.body;
// Déterminer le type d'événement basé sur les caractéristiques de la charge utile
const maintenant = new Date();
const dateExpiration = payload.expires ? new Date(payload.expires) : null;
let typeEvenement;
if (dateExpiration && dateExpiration < maintenant) {
typeEvenement = 'certificate_expired';
} else {
typeEvenement = 'certificate_completed';
}
// Router vers le gestionnaire approprié
switch (typeEvenement) {
case 'certificate_completed':
await gererCertificatComplete(payload);
break;
case 'certificate_expired':
await gererCertificatExpire(payload);
break;
default:
console.warn("Type d'événement inconnu:", typeEvenement);
}
res.status(200).json({ received: true, eventType: typeEvenement });
});
async function gererCertificatComplete(certificate) {
console.log('Certificat complété:', certificate._id);
// Logique de gestion de la complétion...
}
async function gererCertificatExpire(certificate) {
console.log('Certificat expiré:', certificate._id);
// Logique de gestion de l'expiration...
}
Réponses d'Erreur
Votre point de terminaison webhook doit retourner des codes de statut HTTP appropriés :
Réponse de Succès
HTTP/1.1 200 OK
Content-Type: application/json
{
"received": true,
"message": "Webhook traité avec succès",
"eventId": "507f1f77bcf86cd799439011"
}
Réponses d'Erreur
Échec d'Authentification :
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
"error": "Non autorisé",
"message": "Identifiants d'authentification invalides"
}
Charge Utile Invalide :
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": "Mauvaise Requête",
"message": "Structure de charge utile invalide"
}
Erreur Serveur Interne :
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
"error": "Erreur Serveur Interne",
"message": "Échec du traitement du webhook"
}
Retournez uniquement des codes de statut 2xx si le webhook a été reçu et traité avec succès. Retourner 2xx empêche Beedeez de réessayer la livraison.
Gestion de l'Idempotence
Puisque les webhooks peuvent être livrés plusieurs fois, implémentez l'idempotence :
Exemple : Gestionnaire Idempotent
const webhooksTraites = new Set(); // En production, utilisez une base de données
app.post('/webhooks/beedeez', async (req, res) => {
const certificate = req.body;
const webhookId = certificate._id;
// Vérifier si déjà traité
if (webhooksTraites.has(webhookId)) {
console.log('Webhook dupliqué, déjà traité:', webhookId);
return res.status(200).json({
received: true,
duplicate: true,
});
}
try {
// Traiter le webhook
await traiterCertificat(certificate);
// Marquer comme traité
webhooksTraites.add(webhookId);
res.status(200).json({ received: true });
} catch (error) {
console.error('Erreur de traitement du webhook:', error);
res.status(500).json({ error: 'Échec du traitement' });
}
});
Idempotence Basée sur Base de Données
// Utilisation d'une base de données pour suivre les webhooks traités
app.post('/webhooks/beedeez', async (req, res) => {
const certificate = req.body;
const webhookId = certificate._id;
// Vérifier la base de données
const existant = await db.logsWebhook.findOne({ webhookId });
if (existant) {
return res.status(200).json({
received: true,
duplicate: true,
});
}
try {
// Traiter le webhook
await traiterCertificat(certificate);
// Stocker dans la base de données
await db.logsWebhook.insert({
webhookId,
recuLe: new Date(),
payload: certificate,
traite: true,
});
res.status(200).json({ received: true });
} catch (error) {
console.error('Erreur de traitement du webhook:', error);
res.status(500).json({ error: 'Échec du traitement' });
}
});
Test des Webhooks
Test Manuel avec curl
# Tester l'événement certificate_completed
curl -X POST https://votre-endpoint.com/webhooks/beedeez \
-H "Authorization: Bearer votre-token" \
-H "Content-Type: application/json" \
-d '{
"_id": "507f1f77bcf86cd799439011",
"_userId": "507f191e810c19729de860ea",
"_ownerId": "507f191e810c19729de860eb",
"_badgeId": "507f191e810c19729de860ec",
"creationDate": "2024-11-27T10:30:00.000Z",
"expires": "2025-11-27T10:30:00.000Z",
"disabled": false,
"expiryReminderSent": false,
"_lessonActiveIds": ["507f191e810c19729de860ed"],
"ruleData": {
"type": "certification",
"name": "Certificat Test",
"validityDurationDays": 365
},
"createdAt": "2024-11-27T10:30:00.000Z",
"updatedAt": "2024-11-27T10:30:00.000Z"
}'
Test avec Postman
- Créez une nouvelle requête POST
- Définissez l'URL vers votre point de terminaison webhook
- Ajoutez l'en-tête d'authentification (Bearer token, clé API, etc.)
- Définissez Content-Type à
application/json - Collez l'exemple de charge utile dans le corps
- Envoyez la requête et vérifiez la réponse
Exemple d'Intégration Complète
Voici un gestionnaire de webhook complet et prêt pour la production :
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());
// Configuration
const WEBHOOK_TOKEN = process.env.BEEDEEZ_WEBHOOK_TOKEN;
const WEBHOOK_SECRET = process.env.BEEDEEZ_WEBHOOK_SECRET;
// Middleware : Authentification
function authentifierWebhook(req, res, next) {
const authHeader = req.headers.authorization;
if (!authHeader || authHeader !== `Bearer ${WEBHOOK_TOKEN}`) {
return res.status(401).json({ error: 'Non autorisé' });
}
next();
}
// Middleware : Valider la charge utile
function validerChargeUtile(req, res, next) {
const payload = req.body;
if (!payload._id || !payload._userId || !payload._ownerId) {
return res.status(400).json({ error: 'Charge utile invalide' });
}
next();
}
// Gestionnaire de webhook
app.post(
'/webhooks/beedeez',
authentifierWebhook,
validerChargeUtile,
async (req, res) => {
const certificate = req.body;
try {
// Déterminer le type d'événement
const maintenant = new Date();
const dateExpiration = certificate.expires
? new Date(certificate.expires)
: null;
const estExpire = dateExpiration && dateExpiration < maintenant;
// Logger la réception
console.log('Webhook reçu:', {
certificateId: certificate._id,
userId: certificate._userId,
eventType: estExpire ? 'expired' : 'completed',
});
// Répondre immédiatement
res.status(200).json({
received: true,
certificateId: certificate._id,
});
// Traiter de manière asynchrone
if (estExpire) {
await gererCertificatExpire(certificate);
} else {
await gererCertificatComplete(certificate);
}
} catch (error) {
console.error('Erreur de traitement du webhook:', error);
// Retourner quand même 200 si on l'a reçu avec succès
// Logger l'erreur pour investigation
}
},
);
async function gererCertificatComplete(certificate) {
// Mettre à jour le système RH
await mettreAJourSystemeRH(certificate);
// Envoyer un email de félicitations
await envoyerEmailFelicitations(certificate);
// Mettre à jour les analytiques
await suivreCompletionCertificat(certificate);
}
async function gererCertificatExpire(certificate) {
// Marquer comme expiré dans le système de conformité
await marquerCertificatExpire(certificate);
// Déclencher le workflow de re-certification
await declencherRecertification(certificate);
// Envoyer un rappel de renouvellement
await envoyerRappelRenouvellement(certificate);
}
// Démarrer le serveur
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Serveur webhook en écoute sur le port ${PORT}`);
});
Prochaines Étapes
- Consultez le Guide de Configuration pour configurer votre webhook
- Apprenez l'Authentification pour sécuriser votre point de terminaison
- Lisez Types d'Événements pour comprendre tous les événements disponibles
- Consultez l'Introduction pour les concepts et bonnes pratiques des webhooks