Passer au contenu

Guide du développeur

L’API REST de Quire, OAuth, les webhooks, le serveur MCP et les extensions.

Afficher en Markdown

Utilisez l’adresse API de votre organisation et des identifiants aux portées limitées. Commencez par une requête de lecture, vérifiez la réponse et gardez les secrets hors du contrôle de version et des exemples de documentation.

Quire propose une API publique : REST sur HTTPS, décrite dans un document OpenAPI 3.1, des webhooks signés pour les événements et un serveur MCP pour les assistants d’IA. La référence de l’API répertorie tous les points de terminaison et événements.

Adresses

Chaque organisation dispose de sa propre adresse, qui héberge l’API :

https://acme.quirelms.com/api/v1/courses

Les identifiants déterminent l’organisation. Une clé utilisée à l’adresse d’une autre organisation est refusée.

Le document OpenAPI est publié à /api/v1/openapi.json sur l’adresse de chaque organisation ; les générateurs de clients consultent donc toujours la version appelée.

Authentification

Les clés API servent aux scripts et aux intégrations de serveur à serveur. Un administrateur en crée une dans /admin/integrations/api-keys, en choisit les portées et ne peut la voir qu’une fois. Envoyez-la comme jeton porteur :

curl -H "Authorization: Bearer qk_live_..." https://acme.quirelms.com/api/v1/users?limit=50

Les clés commencent par qk_live_ ou qk_test_. Attribuez une clé distincte à chaque intégration.

OAuth 2.1 sert aux applications agissant au nom d’une personne connectée. Enregistrez un client dans /admin/integrations/oauth-clients, puis utilisez le flux de code d’autorisation avec PKCE (/oauth/authorize, /oauth/token), ou les identifiants du client pour un client machine. Le document de découverte est publié dans /.well-known/oauth-authorization-server. Une portée restreint les opérations du jeton ; elle ne lui permet jamais d’en faire plus que la personne.

Les portées sont resource:read, resource:write et resource:delete, par exemple courses:read ou enrolments:write. Quatre portées privilégiées sont accompagnées d’un avertissement sur l’écran de consentement : audit:read, roles:write, tenants:write et users:delete.

The API keys page with one key, the person it acts as, its scopes and its status, and a form to create another.
API keys list who each key acts as and what it may reach.

Requêtes

  • Pagination : chaque liste utilise une pagination par curseur. Indiquez limit, puis transmettez next_cursor de page en tant que cursor tant que has_more vaut true (voir l’exemple ci-dessous). Il n’y a pas de décalage.
  • Modifications depuis une date : updated_since renvoie les changements postérieurs à un instant. Associez-le à include_deleted=true, ou consultez /<resource>/deletions, pour connaître les suppressions.
  • Identifiants externes : la plupart des ressources acceptent votre propre external_id et /<resource>/ext:{external_id} permet de lire ou de créer/mettre à jour une ressource à partir de celui-ci ; une synchronisation n’a donc pas besoin de conserver les identifiants Quire.
  • Idempotence : envoyez un en-tête Idempotency-Key avec POST, PATCH et DELETE. Une nouvelle tentative avec la même clé renvoie la première réponse au lieu de répéter l’opération. Les points de terminaison groupés l’exigent.
  • Versions : la version majeure figure dans le chemin (/v1). Elle contient des révisions datées pour chaque modification incompatible, sélectionnées avec l’en-tête Quire-Version, par exemple Quire-Version: 2026-09-20. Sans cet en-tête, vous obtenez la révision en vigueur lors de l’émission de vos identifiants.

Exemple de page d’une liste :

{"data": [...], "page": {"next_cursor": "eyJ2Ijox...", "has_more": true, "limit": 100}}

Erreurs

Chaque erreur est un document de problème RFC 9457 :

{"type": "https://quire.com/errors/enrolment.seat_limit_reached",
 "title": "Seat limit reached", "status": 409,
 "code": "enrolment.seat_limit_reached", "category": "conflict",
 "detail": "The course has no seats left, so this enrolment was not created. ...",
 "request_id": "01JB7XQK4Z..."}

Fondez votre logique sur code, qui est stable ; detail est rédigé pour les personnes, peut leur être affiché et peut changer. Si vous ne connaissez pas un code, utilisez sa category :

Catégorie Statut Nouvelle tentative
validation 422, avec le détail des champs dans errors Non
authentication 401 Non
authorization 403 Non
not_found 404 Non
conflict 409 Parfois
precondition 412 Non
quota 402 pour le forfait, 413 pour la taille Non
rate_limit 429, avec Retry-After Oui
upstream 502 ou 504 Oui
internal 500 Oui

Indiquez request_id lorsque vous contactez l’assistance.

Webhooks

Créez un abonnement dans /admin/webhooks ou via l’API à /webhook_subscriptions. Choisissez les événements par nom (enrolment.created), par domaine (enrolment.*) ou tous (*). Quire envoie d’abord un événement webhook.ping ; l’abonnement démarre quand votre point de terminaison y répond.

Les livraisons suivent la spécification Standard Webhooks :

POST /hooks/quire
webhook-id: 01JB7XQK4Z8FQ2M3N4P5R6S7T8
webhook-timestamp: 1790000000
webhook-signature: v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE=

Pour vérifier une livraison :

  1. À partir des octets exacts reçus, avant tout décodage JSON, construisez la chaîne {webhook-id}.{webhook-timestamp}.{raw body}.
  2. Calculez son HMAC-SHA256 avec le secret de votre abonnement, puis encodez-le en base64.
  3. Comparez en temps constant le résultat à chaque valeur v1, de webhook-signature. Il peut y en avoir deux pendant la rotation d’un secret ; une seule correspondance suffit.
  4. Rejetez tout horodatage qui diffère de votre horloge de plus de cinq minutes.
import { createHmac, timingSafeEqual } from 'node:crypto';

function verify(secret, id, timestamp, rawBody, header) {
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
  const expected = createHmac('sha256', Buffer.from(secret.replace(/^whsec_/, ''), 'base64'))
    .update(`${id}.${timestamp}.${rawBody}`).digest();
  return header.split(' ').some((part) => {
    const [version, value] = part.split(',');
    const given = Buffer.from(value ?? '', 'base64');
    return version === 'v1' && given.length === expected.length && timingSafeEqual(given, expected);
  });
}

Éliminez les doublons à l’aide de webhook-id : une livraison peut arriver plusieurs fois. Le corps contient des identifiants et un bref résumé ; récupérez la ressource pour connaître son état actuel. Les livraisons échouées font l’objet de nouvelles tentatives avec temporisation pendant un maximum de 72 heures ; vous pouvez également les rejouer depuis le journal de distribution.

MCP

Le serveur MCP de Quire se trouve à /mcp sur l’adresse de l’organisation, et utilise HTTP en flux. Un client MCP découvre le serveur OAuth dans /.well-known/oauth-protected-resource ; la personne se connecte et donne son consentement comme avec tout client OAuth. Les outils agissent selon les autorisations de cette personne, et les outils destructifs demandent confirmation. Les administrateurs choisissent les outils disponibles dans /admin/integrations/mcp.

The AI assistants page with the server address to give an assistant and a table of the tools it can use.
AI assistants (MCP): the server address, and the tools an assistant may call.

Forfaits et API

Les clés API, clients OAuth, webhooks et le serveur MCP relèvent de l’option API du forfait, incluse dans chaque forfait standard. Dans un forfait qui ne l’inclut pas, la création d’une clé, d’un client ou d’un abonnement est refusée, les écritures REST et les connexions MCP sont refusées, mais les lectures REST restent possibles afin que les données puissent être exportées. Le refus est un document de problème avec le code commerce.plan_entitlement, dans la catégorie precondition.

Extensions

Les types d’activité, blocs, méthodes d’inscription, modes de connexion, types de question, rapports, thèmes et intégrations de Quire sont déclarés dans le même registre d’extensions que peut enrichir une installation auto-hébergée. Les extensions sont intégrées à la compilation : aucun chargeur de modules n’est disponible à l’exécution, et une organisation utilisant Quire hébergé ne peut pas en ajouter. Les administrateurs activent ou désactivent chaque extension pour leur organisation dans /admin/extensions (consultez le guide de l’administrateur).

Pour en écrire une, partez du bloc et du thème d’exemple dans packages/integration/extensions/src/sample.ts. Choisissez le point d’extension et lisez son contrat dans points.ts, puis déclarez l’extension avec un identifiant, une version, une licence, ses éléments fournis et requis, et l’autorisation ou non pour une organisation de la désactiver. Enregistrez-la à l’endroit où l’application Web et le worker sont assemblés afin qu’ils partagent la même configuration. À la construction et à chaque appel à register, le registre vérifie les règles propres à chaque point d’extension, refuse en nommant tous les problèmes un ensemble invalide et conserve le registre inchangé. Les tests de l’extension doivent vérifier que extensionContractProblems ne renvoie aucun problème et que la désactivation modifie les éléments concernés.

Navigation

Saisissez votre recherche…

↑↓ naviguer↵ sélectionnerÉchap fermer