MeetingHub MeetingHub Télécharger la collection Postman

Webhooks

Être prévenu quand il y a quelque chose à dire.

Sans webhook, votre système devrait interroger MeetingHub en boucle pour savoir si une feuille de présence est prête : du trafic pour rien, et une information toujours en retard. Avec un webhook, c'est MeetingHub qui appelle votre système, une fois, quand il y a quelque chose à dire. Chaque champ est détaillé dans la référence : Webhooks.

Poser un webhook

Un administrateur de l'établissement le pose, avec sa session :

POST /api/institutions/:institutionId/webhooks
{ "url": "https://ent.mon-lycee.fr/hooks/meetinghub",
  "events": ["attendance.closed"],
  "label": "ENT — émargement" 
}

:institutionId est l'identifiant de l'établissement, que GET /api/me rend dans institutions. Une clé d'établissement ne pose pas d'alerte : c'est une décision de son administration.

Vous êtes éditeur partenaire ? Posez plutôt le webhook une fois pour tous vos établissements, avec votre clé mhp_…, par POST /api/partner/webhooks : voir Éditeurs partenaires.

La réponse contient le secret de signature, et c'est la seule fois. Copiez-le dans la configuration de votre système : il sert à vérifier que les appels viennent bien de MeetingHub.

L'adresse doit être en HTTPS et joignable depuis Internet. Une adresse interne — localhost, une adresse privée, un nom en .local ou .internal — est refusée : c'est le serveur de MeetingHub qui irait la chercher, et ce serait une porte ouverte sur son propre réseau. Le contrôle est refait à chaque envoi, sur l'adresse que le nom désigne à ce moment-là.

Un webhook ne reçoit que les événements auxquels il est abonné. Une liste vide veut dire aucun, pas tous.

Les événements

ÉvénementQuand
attendance.closedUne feuille de présence vient d'être arrêtée
session.cancelledUn cours vient d'être annulé, un par un
roster.importedUne liste d'inscrits vient d'être appliquée

Une annulation faite par votre propre système dans un dépôt d'emploi du temps, ou par la ref du cours, n'envoie pas session.cancelled : votre système la connaît déjà.

Vérifier la signature

Chaque appel porte un en-tête x-meetinghub-signature de la forme t=1760436000,v1=…. v1 est un HMAC-SHA256 de t, d'un point, puis du corps brut de la requête, calculé avec votre secret.

Vérifiez-la sur le corps BRUT, tel que reçu, et non sur un JSON relu puis réécrit : le moindre espace change le résultat.

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

function verifier(corpsBrut, entete, secret) {
  const parts = new Map(entete.split(',').map((p) => p.split('=', 2)));
  const t = Number(parts.get('t'));
  // La fenêtre est ce qui empêche de rejouer un appel intercepté.
  if (Math.abs(Date.now() / 1000 - t) > 300) return false;
  const attendu = createHmac('sha256', secret).update(`${t}.${corpsBrut}`).digest('hex');
  const a = Buffer.from(parts.get('v1') ?? '', 'utf8');
  const b = Buffer.from(attendu, 'utf8');
  return a.length === b.length && timingSafeEqual(a, b);

}

Le secret s'utilise tel qu'il vous a été rendu, préfixe whsec_ compris.

Ce que votre serveur doit faire

Répondre vite. Au-delà de dix secondes, la tentative est abandonnée. Répondez 200 dès réception, et traitez ensuite.

Dédoublonner. Si votre réponse se perd en route, le même événement est renvoyé. L'en-tête x-meetinghub-delivery est identique à chaque tentative : gardez-le, et ignorez un appel déjà traité — sans quoi vous compteriez deux fois la même feuille.

Ne pas compter sur l'ordre. Les appels partent en parallèle : deux événements proches peuvent arriver dans le désordre.

Si votre serveur ne répond pas

Une tentative échouée est réessayée — sans réponse, ou avec un code 5xx, 408 ou 429 — mais pas longtemps : après six tentatives, en une à deux minutes environ, la livraison est abandonnée. Un autre code 4xx l'abandonne tout de suite. Les redirections ne sont pas suivies : l'adresse doit être la bonne.

Après 20 tentatives échouées d'affilée, le webhook est coupé, et le motif est noté dans disabledReason. On le réactive avec PATCH /api/institutions/:institutionId/webhooks/:webhookId et { "enabled": true } ; les livraisons encore en attente repartent alors.

Une interruption de votre serveur fait donc manquer des événements. Pour rattraper, relisez l'emploi du temps de la période avec GET /api/institutions/:institutionId/lessons?from=…&to=… : un cours à l'état held a sa feuille dès qu'il y avait de quoi l'établir, et vous pouvez la récupérer comme d'habitude.

Diagnostiquer

GET /api/institutions/:institutionId/webhooks/:webhookId/deliveries

Chaque livraison porte son statut, son nombre de tentatives, le code de réponse de votre serveur et un extrait de son corps d'erreur. C'est là que se trouve la réponse à « pourquoi la feuille de mardi n'est-elle pas chez nous ? ». Un webhook posé par un éditeur partenaire apparaît là aussi, dans chacun de ses établissements, avec ses propres livraisons.