---
title: "Guide du développeur"
description: "API REST de Quire, OAuth, webhooks, serveur MCP et extensions."
image: "https://docs.quirelms.com/og.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.quirelms.com/fr-CA/llms.txt
> Use this file to discover all available pages before exploring further.

# Guide du développeur

<span id="developer-guide"></span>

Utilisez l’adresse d’API de votre organisation et un justificatif dont la portée est limitée. Commencez par une requête de lecture, vérifiez la réponse et gardez les secrets à l’extérieur du contrôle de version et des exemples de documentation.

Quire offre une API publique : REST sur HTTPS, décrite par un document OpenAPI 3.1, avec des webhooks signés pour les événements et un serveur MCP pour les assistants d’IA. La [référence de l’API](https://docs.quirelms.com/api/) répertorie tous les points de terminaison et événements.

## Adresses <!--quire:addresses-->

Chaque organisation a sa propre adresse, sous laquelle se trouve l’API :

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

Le justificatif détermine l’organisation. Une clé d’une organisation utilisée à l’adresse d’une autre est refusée.

Le document OpenAPI est accessible à `/api/v1/openapi.json` sur l’adresse de chaque organisation; les générateurs de clients voient donc toujours la version que vous appelez.

## Authentification <!--quire:authentication-->

Les **clés d’API** servent aux scripts et aux intégrations serveur à serveur. Un administrateur en crée une à `/admin/integrations/api-keys`, en choisit les portées et ne la voit qu’une seule 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 qui agissent au nom d’une personne connectée. Enregistrez un client à `/admin/integrations/oauth-clients`, puis utilisez le flux de code d’autorisation avec PKCE (`/oauth/authorize`, `/oauth/token`) ou les justificatifs client pour un client machine. La découverte se fait à `/.well-known/oauth-authorization-server`. Une portée limite ce qu’un jeton peut faire; 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 sont privilégiées et accompagnées d’un avertissement sur l’écran de consentement : `audit:read`, `roles:write`, `tenants:write` et `users:delete`.

<figure class="quire-shot" lang="en" dir="ltr"><img src="/screenshots/admin-api-keys.webp" alt="The API keys page with one key, the person it acts as, its scopes and its status, and a form to create another." width="944" height="700" loading="lazy" decoding="async"><figcaption>API keys list who each key acts as and what it may reach.</figcaption></figure>

## Requêtes <!--quire:requests-->

- **Pagination** : chaque liste est paginée par curseur. Transmettez `limit`, puis la valeur `next_cursor` de `page` comme `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 modifications postérieures à une heure donnée. Combinez-le avec `include_deleted=true`, ou lisez `/<resource>/deletions`, pour connaître les éléments supprimés.
- **Identifiants externes** : la plupart des ressources acceptent votre propre `external_id`, et `/<resource>/ext:{external_id}` permet de les lire ou de les créer ou mettre à jour avec cet identifiant; 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 sans répéter l’opération. Les points de terminaison groupés l’exigent.
- **Versions** : la version majeure figure dans le chemin (`/v1`). À l’intérieur de celle-ci, chaque changement incompatible est une révision datée, sélectionnée 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 à la création de votre justificatif.

Exemple de page d’une liste :

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

## Erreurs <!--quire:errors-->

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 traitement sur `code`, qui est stable; `detail` est destiné aux personnes, peut leur être affiché et peut changer. Si vous ne reconnaissez pas un code, classez l’erreur selon `category` :

| Catégorie | État | Nouvelle tentative |
| --- | --- | --- |
| `validation` | 422, avec les détails des champs dans `errors` | No |
| `authentication` | 401 | No |
| `authorization` | 403 | No |
| `not_found` | 404 | No |
| `conflict` | 409 | Sometimes |
| `precondition` | 412 | No |
| `quota` | 402 pour le forfait, 413 pour la taille | No |
| `rate_limit` | 429, avec `Retry-After` | Yes |
| `upstream` | 502 ou 504 | Yes |
| `internal` | 500 | Yes |

Indiquez `request_id` lorsque vous communiquez avec le soutien.

## Webhooks <!--quire:webhooks-->

Abonnez-vous à `/admin/webhooks` ou au moyen de l’API, à `/webhook_subscriptions`. Choisissez les événements par nom (`enrolment.created`), par groupe (`enrolment.*`) ou tous (`*`). Quire envoie d’abord un `webhook.ping`; l’abonnement commence lorsque 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. Construisez la chaîne `{webhook-id}.{webhook-timestamp}.{raw body}` à partir des octets exacts reçus, avant toute analyse JSON.
2. Calculez HMAC-SHA256 sur cette chaîne avec le secret de votre abonnement, puis encodez le résultat en base64.
3. Comparez en temps constant chaque valeur `v1,` de `webhook-signature`. Il peut y en avoir deux pendant la rotation d’un secret; une seule correspondance suffit.
4. Rejetez un horodatage qui s’écarte de plus de cinq minutes de votre horloge.

```
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 sont réessayées avec un délai progressif jusqu’à 72 heures et peuvent être rejouées à partir du journal de livraison.

## MCP <!--quire:mcp-->

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

<figure class="quire-shot" lang="en" dir="ltr"><img src="/screenshots/admin-mcp.webp" alt="The AI assistants page with the server address to give an assistant and a table of the tools it can use." width="944" height="700" loading="lazy" decoding="async"><figcaption>AI assistants (MCP): the server address, and the tools an assistant may call.</figcaption></figure>

## Forfaits et API <!--quire:plans-and-the-api-->

Les clés d’API, clients OAuth, webhooks et serveur MCP relèvent du droit d’accès à l’API du forfait, qui est compris dans tous les forfaits standards. Sans ce droit, 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 continuent afin que les données restent exportables. Le refus est un document de problème dont le code est `commerce.plan_entitlement`, dans la catégorie `precondition`.

## Extensions <!--quire:extensions-->

Les types d’activité, blocs, méthodes d’inscription, méthodes de connexion, types de questions, rapports, thèmes et intégrations propres à Quire sont déclarés par le même registre d’extensions auquel une installation autohébergée peut ajouter des entrées. Les extensions sont intégrées à la compilation : il n’y a pas de chargeur de greffons à l’exécution, et une organisation hébergée ne peut pas en ajouter. Les administrateurs activent ou désactivent chaque extension pour leur organisation à `/admin/extensions` (consultez le [guide de l’administrateur](/fr-CA/admin/extensions/)).

Pour en créer 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, les éléments qu’elle fournit et exige, et l’autorisation ou non pour une organisation de la désactiver. Inscrivez-la à l’endroit où l’application Web et le processus de travail sont assemblés, afin qu’ils soient tous deux d’accord. Le registre vérifie les règles propres à chaque point lors de sa création et à chaque appel de `register`, refuse tout ensemble invalide en nommant chaque problème et reste inchangé en cas de refus. Les tests de l’extension doivent vérifier que `extensionContractProblems` est vide pour celle-ci et que sa désactivation modifie les éléments concernés.

Source: https://docs.quirelms.com/fr-CA/developer/index.mdx
