MeetingHub MeetingHub Télécharger la collection Postman

Référence — éditeurs partenaires

Les établissements, les centres, les clés, les liens d’entrée, les webhooks et la mesure d’usage.

Ce qu'un éditeur partenaire fait sur /api avec sa clé :

Authorization: Bearer mhp_Q3x9LmPa_…

La clé a la même forme qu'une clé d'intégration, avec le préfixe mhp_. Elle ouvre deux sortes de routes :

Elle n'ouvre ni l'emploi du temps, ni les feuilles de présence, ni les listes d'inscrits : pour cela, l'éditeur pose dans l'établissement une clé mhk_…, et son logiciel l'utilise ensuite. Voir Clés d'intégration.

Un établissement que l'éditeur n'a pas ouvert répond 404, comme s'il n'existait pas. Un établissement en pause ne lui ouvre plus que la lecture : ses écritures y sont refusées en 403, cet accès ne permet pas cela — il faut : institution.manage ou partner.manage. Chaque requête de l'éditeur dans un de ses établissements, lectures comprises, est inscrite au journal de cet établissement, au nom éditeur partenaire « … ».

Les corps JSON font 4 Mo au plus, et chaque éditeur fait 300 requêtes par minute au plus ; au-delà, la réponse est 429. Voir Conventions.

Échecs d'authentification

SituationCodeCorpscode
Clé mal formée401clé d’éditeur partenaire illisibleauth.invalid-key
Clé inconnue, secret faux, ou clé révoquée401clé d’éditeur partenaire inconnue ou révoquéeauth.invalid-key
Aucune clé, sur une route de l'éditeur401identification requiseauth.required
Cookie de session et clé ensemble400une seule identité par requête : …auth.ambiguous

Les réponses 401 d'une clé fautive portent l'en-tête WWW-Authenticate: Bearer error="invalid_token". Une clé d'éditeur n'a pas d'échéance : elle vaut jusqu'à ce que l'exploitant la révoque.

L'objet Établissement

{
  "id": "6c1d3a52-7a0e-4f0b-9c55-0a54c3e1f2b8",
  "slug": "lycee-bilingue-bonamoussadi",
  "name": "Lycée bilingue de Bonamoussadi",
  "kind": "school",
  "status": "active",
  "trialEndsAt": null,
  "createdAt": "2026-10-01T08:00:00.000Z"

}
ChampTypeDescription
iduuidIdentifiant de l'établissement, le :institutionId des routes
slugstringIdentifiant lisible, unique sur le service
namestringLe nom de l'établissement
kindstringschool ou company
statusstringtrial (à l'essai : salles bornées à 10 personnes), active, ou paused (en pause : rien n'est effacé, rien ne s'ouvre)
trialEndsAtdatetime ou nullLa fin de l'essai ; null pour l'essai que vous ouvrez, qui n'expire pas
createdAtdatetimeLa date d'ouverture

GET /api/me

Avec une clé d'éditeur :

{
  "actor": { "kind": "partner-key", "id": "…", "name": "Votre logiciel" },
  "institutions": [{ "id": "6c1d3a52-…", "name": "Lycée bilingue de Bonamoussadi", "status": "active" }],
  "capabilities": ["institution.view", "partner.manage"]

}

actor.id et actor.name sont ceux de l'éditeur, pas de la clé. institutions liste les établissements qu'il a ouverts.

GET /api/institutions

Les établissements que vous avez ouverts, par ordre alphabétique.

Réponse 200 : { "institutions": [Établissement] }. Le status rendu tient compte d'un essai échu.

POST /api/institutions

Ouvre un établissement pour un de vos clients. Exige une clé d'éditeur.

{
  "slug": "lycee-bilingue-bonamoussadi",
  "name": "Lycée bilingue de Bonamoussadi",
  "kind": "school",
  "sandbox": true,
  "admin": { "email": "direction@lycee.cm", "displayName": "Direction" }

}
ChampTypeObligatoireRègles
slugstringouiMis en minuscules. Lettres, chiffres et tirets, de 1 à 40 caractères, sans tiret au début ni à la fin
namestringouiEspaces resserrés, tronqué à 120 caractères
kindstringnonschool (par défaut) ou company
sandboxbooleannontrue ouvre l'établissement à l'essai (status: "trial"), sans échéance ; false par défaut
admin.emailstringnonLe courriel du premier responsable de l'établissement
admin.displayNamestringnonSon nom ; le courriel à défaut

Le premier responsable reçoit le rôle promoter : le Promoteur, qui gouverne l'établissement. S'il n'a pas de compte, un compte est créé, sans mot de passe connu, avec un lien d'activation pour qu'il choisisse le sien.

Réponse 201 :

{
  "organisation": { "id": "…", "slug": "…", "status": "trial", "…": "…" },
  "admin": { "email": "direction@lycee.cm", "invited": true, "link": "https://reunion.exemple.cm/app/?setup=…" }

}
ChampTypeDescription
organisationÉtablissementL'établissement ouvert
adminobject ou nullnull sans responsable demandé
admin.invitedbooleantrue si le compte a été créé ; false s'il existait et a été rattaché
admin.linkstring ou nullLe lien d'activation, quand le courriel n'a pas pu partir. Aujourd'hui, MeetingHub n'en envoie pas : le lien est toujours rendu pour un compte créé. Transmettez-le vous-même, à la seule personne concernée

Vos webhooks d'éditeur sont recopiés dans l'établissement dès son ouverture.

CodeCorpsCause
400identifiant attendu : minuscules, chiffres et tirets, de 1 à 40 caractèresslug absent ou mal formé
400nom de l’établissement requisname absent ou vide
400type inconnu — « school » ou « company »kind invalide
400sandbox attend vrai ou fauxsandbox n'est pas un booléen
400adresse de l’administrateur invalideadmin fourni sans courriel lisible
409un établissement porte déjà cet identifiantslug déjà pris

GET /api/institutions/:institutionId

L'établissement, et ce que vous pouvez y faire.

{
  "institution": { "id": "6c1d3a52-…", "name": "Lycée bilingue de Bonamoussadi", "status": "active", "trialEndsAt": null },
  "capabilities": ["institution.view", "partner.manage"],
  "support": false

}

En pause, capabilities ne contient plus que institution.view.

L'objet Centre

ChampTypeDescription
iduuidIdentifiant du centre
namestringSon nom
referencestring ou nullVotre code pour ce centre, unique dans l'établissement
citystring ou nullSa ville
createdAtdatetimeSa date de création

GET /api/institutions/:institutionId/centres

Les centres de l'établissement. Exige institution.view. Réponse 200 : { "centres": [Centre] }.

POST /api/institutions/:institutionId/centres

Déclare un centre. Exige partner.manage — ou, pour l'établissement, institution.manage.

{ "name": "Campus de Kotto", "reference": "KOT", "city": "Douala" 
}
ChampTypeObligatoireRègles
namestringouiEspaces resserrés, tronqué à 120 caractères
referencestring ou nullnon64 caractères au plus : lettres, chiffres, point, tiret et soulignement, en commençant par une lettre ou un chiffre
citystringnonTronquée à 120 caractères

Réponse 201 : { "centre": Centre }.

CodeCorpsCause
400nom du site requisname absent ou vide
400référence attendue : lettres, chiffres, point, tiret — 64 caractères au plusreference mal formée
409un centre de l’établissement porte déjà cette référencereference déjà prise

Renommer ou retirer un centre, et nommer ses directeurs, reviennent à l'administration de l'établissement.

Les clés de vos établissements

GET, POST et DELETE sous /api/institutions/:institutionId/keys : mêmes routes, mêmes corps et mêmes réponses que pour l'établissement — voir POST /api/institutions/:institutionId/keys et L'objet Clé. Avec trois différences :

{ "label": "Votre logiciel — emploi du temps", "scopes": ["schedule:read", "schedule:write"] 
}

La clé en clair est rendue dans key.plaintext, cette fois seulement.

POST /api/institutions/:institutionId/entries

Un lien d'entrée dans une salle de l'établissement, à ouvrir dans une iframe. Exige une clé d'éditeur et partner.manage.

{ "room": "ABCD2345", "displayName": "Awa Ngono", "host": false, "ttlMinutes": 120 
}
ChampTypeObligatoireRègles
roomstringouiL'identifiant court de la salle
displayNamestringouiLe nom affiché, 60 caractères au plus. La personne ne peut pas le changer
hostbooleannontrue : la personne entre comme animateur
ttlMinutesintegernonDe 1 à 720 ; 120 par défaut

Réponse 201 :

{
  "entry": {
    "token": "eyJvIjoi….1791000000.Xk2…",
    "url": "https://reunion.exemple.cm/app/?room=ABCD2345&entree=…",
    "expiresAt": "2026-10-14T10:00:00.000Z"
  }

}

À l'entrée, le lien tient lieu de politique d'entrée et de mot de passe. Il ne passe outre ni l'horaire du cours, ni le verrou, ni la salle d'attente, ni une exclusion. La page ne se laisse encadrer que par vos origines enregistrées (Content-Security-Policy: frame-ancestors).

CodeCorpsCause
400nom de la personne requisdisplayName absent ou vide
400host attend vrai ou fauxhost n'est pas un booléen
400durée du lien : de 1 à 720 minutesttlMinutes hors bornes ou pas un entier
404salle inconnueAucune salle de cet identifiant dans l'établissement
409aucune origine d’intégration déclarée : l’exploitant doit d’abord l’enregistrerAucune origine enregistrée pour vous : demandez-le à l'exploitant

L'objet Webhook d'éditeur

ChampTypeDescription
iduuidIdentifiant du webhook, le :webhookId des routes
urlstringL'adresse appelée
eventsstring[]Les événements souscrits
labelstring ou nullSon nom, 120 caractères au plus
createdAtdatetimeSa date de création

GET /api/partner/webhooks

Vos webhooks. Réponse 200 : { "webhooks": [Webhook], "events": [string] }. Le champ events liste tous les événements qui existent.

POST /api/partner/webhooks

{ "url": "https://api.votre-logiciel.cm/meetinghub", "events": ["attendance.closed"], "label": "Production" 
}

Mêmes règles d'adresse et d'événements que pour un webhook d'établissement : voir Webhooks. Le webhook est recopié dans chacun de vos établissements, présents et à venir ; chaque appel porte l'identifiant de l'établissement dans organisationId.

Réponse 201 : { "webhook": Webhook, "notice": "…" }. Le secret de signature est dans webhook.secret, cette fois seulement.

PATCH /api/partner/webhooks/:webhookId

Change url, events ou label. Toutes les copies suivent ; ce qui est propre à un établissement — un webhook coupé après trop d'échecs — reste le sien. Réponse 200 : { "webhook": Webhook }. Un webhook inconnu répond 404, alerte inconnue.

DELETE /api/partner/webhooks/:webhookId

Supprime le webhook et toutes ses copies. Réponse 204. Un webhook inconnu répond 404, alerte inconnue.

GET /api/partner/usage

Ce que chaque établissement a consommé sur un mois calendaire, en UTC.

ParamètreTypeDescription
monthAAAA-MMLe mois ; le mois en cours par défaut. Mal formé : 400, mois attendu au format AAAA-MM

Réponse 200 :

{
  "month": "2026-10",
  "from": "2026-10-01T00:00:00.000Z",
  "to": "2026-11-01T00:00:00.000Z",
  "organisations": [
    {
      "organisationId": "…",
      "name": "Lycée bilingue de Bonamoussadi",
      "status": "active",
      "rooms": 12,
      "connections": 1840,
      "participants": 410,
      "seconds": 2952000,
      "bytes": 61200000000,
      "sessionsHeld": 96
    }
  ]

}
ChampTypeDescription
organisationIduuidL'établissement
roomsintegerLes salles qui ont servi
connectionsintegerLes connexions ; une personne qui se reconnecte en compte plusieurs
participantsintegerLes personnes distinctes, comptes ou invités
secondsintegerLe temps de connexion cumulé
bytesintegerLes octets envoyés et reçus, comptés par les navigateurs
sessionsHeldintegerLes cours tenus

Aucun nom, aucune adresse : ce sont des totaux.

Les anciennes adresses

Les routes /api/partner/… répondent encore, avec une clé d'éditeur seulement, comme alias dépréciés : chaque réponse porte Deprecation: true et un en-tête Link vers la route qui la remplace. Sans clé d'éditeur, elles répondent 401, clé d’éditeur partenaire requise, code auth.required.

Ancienne adresseRoute de /api
GET, POST /api/partner/organisationsGET, POST /api/institutions
GET, POST /api/partner/organisations/:orgId/sitesGET, POST /api/institutions/:institutionId/centres
GET, POST /api/partner/organisations/:orgId/keysGET, POST /api/institutions/:institutionId/keys
DELETE /api/partner/organisations/:orgId/keys/:keyIdDELETE /api/institutions/:institutionId/keys/:keyId
POST /api/partner/organisations/:orgId/entriesPOST /api/institutions/:institutionId/entries
GET, POST /api/partner/webhooksGET, POST /api/partner/webhooks
PATCH, DELETE /api/partner/webhooks/:idPATCH, DELETE /api/partner/webhooks/:webhookId
GET /api/partner/usageGET /api/partner/usage

Les réponses sont celles de /api : GET /api/partner/organisations rend donc institutions, et la liste des centres centres.