Ves al contingut

Guia del desenvolupador

L’API REST de Quire, OAuth, webhooks, el servidor MCP i les extensions.

Mostra com a Markdown

Feu servir l’adreça de l’API de la vostra organització i una credencial amb els àmbits necessaris. Comenceu amb una petició de lectura, comproveu-ne la resposta i manteniu els secrets fora del control de versions i dels exemples de documentació.

Quire té una única API pública: REST sobre HTTPS, descrita amb un document OpenAPI 3.1; inclou webhooks signats per als esdeveniments i un servidor MCP per als assistents d’IA. La referència de l’API enumera tots els endpoints i esdeveniments.

Adreces

Cada organització té la seva pròpia adreça, i l’API és a sota:

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

La credencial determina l’organització. Es rebutja una clau d’una organització si s’utilitza amb l’adreça d’una altra.

El document OpenAPI està disponible a /api/v1/openapi.json a l’adreça de qualsevol organització; així, els generadors de clients sempre veuen la versió a la qual feu les crides.

Autenticació

Les claus de l’API són per a scripts i integracions de servidor a servidor. Un administrador en crea una a /admin/integrations/api-keys, en tria els àmbits i només la pot veure una vegada. Envieu-la com a bearer token:

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

Les claus comencen per qk_live_ o qk_test_. Doneu una clau pròpia a cada integració.

OAuth 2.1 és per a aplicacions que actuen en nom d’una persona amb sessió iniciada. Registreu un client a /admin/integrations/oauth-clients i, després, utilitzeu el flux de codi d’autorització amb PKCE (/oauth/authorize, /oauth/token) o les credencials de client per a un client de màquina. La descoberta és a /.well-known/oauth-authorization-server. Un àmbit restringeix les accions del token; mai no li permet fer més del que podria fer la persona.

Els àmbits són resource:read, resource:write i resource:delete, per exemple courses:read o enrolments:write. Quatre són privilegiats i es mostren amb un avís a la pantalla de consentiment: audit:read, roles:write, tenants:write i 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.

Peticions

  • Paginació: totes les llistes fan servir paginació amb cursor. Passeu limit i, després, next_cursor de page com a cursor mentre has_more sigui cert (vegeu l’exemple següent). No hi ha desplaçament per offset.
  • Canvis des d’una data: updated_since retorna els canvis posteriors a una hora. Combineu-lo amb include_deleted=true o consulteu /<resource>/deletions per saber què s’ha suprimit.
  • Identificadors externs: la majoria de recursos accepten el vostre external_id i /<resource>/ext:{external_id} permet consultar-los o actualitzar-los; així, la sincronització no necessita desar identificadors de Quire.
  • Idempotència: envieu una capçalera Idempotency-Key a les peticions POST, PATCH i DELETE. Si repetiu una petició amb la mateixa clau, s’obté la primera resposta i no es repeteix l’acció. Els endpoints massius l’exigeixen.
  • Versions: la versió principal apareix al camí (/v1). Dins d’aquesta, cada canvi incompatible és una revisió amb data, que s’indica amb la capçalera Quire-Version, per exemple Quire-Version: 2026-09-20. Si no envieu la capçalera, obtindreu la revisió vigent quan es va crear la credencial.

Una pàgina d’una llista:

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

Errors

Tots els errors són documents de problema 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..."}

Preneu decisions segons code, que és estable. detail està redactat per a persones, es pot mostrar als usuaris i pot canviar. Si no reconeixeu un codi, utilitzeu-ne la category:

Categoria Estat Reintent
validation 422, amb informació dels camps a errors No
authentication 401 No
authorization 403 No
not_found 404 No
conflict 409 De vegades
precondition 412 No
quota 402 per al pla, 413 per a la mida No
rate_limit 429, amb Retry-After Sí
upstream 502 o 504 Sí
internal 500 Sí

Quan contacteu amb el suport, indiqueu request_id.

Webhooks

Creeu una subscripció a /admin/webhooks o mitjançant l’API a /webhook_subscriptions. Trieu els esdeveniments pel nom (enrolment.created), per àrea (enrolment.*) o tots (*). Quire envia primer un webhook.ping; la subscripció comença quan l’endpoint hi respon.

Els lliuraments segueixen l’especificació Standard Webhooks:

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

Per verificar un lliurament:

  1. Creeu la cadena {webhook-id}.{webhook-timestamp}.{raw body} a partir dels bytes exactes rebuts, abans d’analitzar el JSON.
  2. Calculeu-ne l’HMAC-SHA256 amb el secret de subscripció i codifiqueu-lo en base64.
  3. Compareu-lo en temps constant amb cada valor v1, de webhook-signature. Durant la rotació del secret n’hi pot haver dos; n’hi ha prou que coincideixi un.
  4. Rebutgeu una marca de temps que difereixi més de cinc minuts de l’hora actual.
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);
  });
}

Eviteu duplicats segons webhook-id: un lliurament pot arribar més d’una vegada. El cos conté identificadors i un breu resum; consulteu el recurs per obtenir-ne l’estat actual. Els lliuraments fallits es tornen a intentar amb retards creixents durant un màxim de 72 hores i es poden tornar a enviar des del registre de lliuraments.

MCP

El servidor MCP de Quire és a /mcp de l’adreça de l’organització i utilitza HTTP en mode streamable. Un client MCP descobreix el servidor OAuth a /.well-known/oauth-protected-resource; la persona inicia sessió i dona el consentiment com amb qualsevol client OAuth. Les eines actuen amb els permisos de la persona i demanen confirmació per a les accions destructives. Els administradors trien les eines disponibles a /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.

Plans i API

Les claus d’API, els clients OAuth, els webhooks i el servidor MCP depenen de les funcions d’API incloses al pla, i tots els plans estàndard les inclouen. En un pla que no les inclogui, es rebutja la creació de claus, clients i subscripcions, també les escriptures REST i les connexions MCP; les lectures REST continuen funcionant perquè les dades es puguin exportar. El rebuig és un document de problema amb el codi commerce.plan_entitlement i la categoria precondition.

Extensions

Els tipus d’activitat, blocs, mètodes d’inscripció, mètodes d’inici de sessió, tipus de pregunta, informes, temes i integracions propis de Quire es declaren mitjançant el mateix registre d’extensions que una instal·lació autoallotjada pot ampliar. Les extensions es compilen a l’aplicació: no hi ha cap carregador de complements en temps d’execució, i una organització allotjada no n’hi pot afegir. Els administradors activen o desactiven cadascuna per a la seva organització a /admin/extensions (vegeu la guia de l’administrador).

Per crear-ne una, comenceu pel bloc i el tema d’exemple de packages/integration/extensions/src/sample.ts. Trieu el punt d’extensió i llegiu-ne el contracte a points.ts. Després, declareu l’extensió amb un ID, una versió, una llicència, el que ofereix i el que necessita, i si l’organització la pot desactivar. Registreu-la allà on es combinen l’aplicació web i el worker perquè tots dos hi estiguin d’acord. El registre comprova les regles de cada punt tant en crear-lo com en cridar register; si el conjunt no és vàlid, el rebutja indicant tots els problemes i no el modifica. Les proves de l’extensió han de comprovar que extensionContractProblems no conté cap problema i que desactivar-la modifica els elements afectats.

Navegació

Escriviu per cercar…

↑↓ per navegar↵ per seleccionarEsc per tancar