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/coursesLa 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=50Les 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.

Peticions
- Paginació: totes les llistes fan servir paginació amb cursor. Passeu
limiti, després,next_cursordepagecom acursormentrehas_moresigui cert (vegeu l’exemple següent). No hi ha desplaçament per offset. - Canvis des d’una data:
updated_sinceretorna els canvis posteriors a una hora. Combineu-lo ambinclude_deleted=trueo consulteu/<resource>/deletionsper saber què s’ha suprimit. - Identificadors externs: la majoria de recursos accepten el vostre
external_idi/<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-Keya les peticionsPOST,PATCHiDELETE. 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çaleraQuire-Version, per exempleQuire-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:
- Creeu la cadena
{webhook-id}.{webhook-timestamp}.{raw body}a partir dels bytes exactes rebuts, abans d’analitzar el JSON. - Calculeu-ne l’HMAC-SHA256 amb el secret de subscripció i codifiqueu-lo en base64.
- Compareu-lo en temps constant amb cada valor
v1,dewebhook-signature. Durant la rotació del secret n’hi pot haver dos; n’hi ha prou que coincideixi un. - 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.

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.