Utiliza o enderezo da API da túa organización e unha credencial cos ámbitos necesarios. Comeza cunha petición de lectura, comproba a resposta e mantén os segredos fóra do control de código fonte e dos exemplos da documentación.
Quire ten unha API pública: REST sobre HTTPS, descrita cun documento OpenAPI 3.1, ademais de webhooks asinados para os eventos e un servidor MCP para asistentes de IA. A referencia da API enumera todos os endpoints e eventos.
Enderezos
Cada organización ten o seu propio enderezo e a API está dispoñible nel:
https://acme.quirelms.com/api/v1/coursesA credencial determina a organización. Rexéitase o uso no enderezo doutra organización dunha clave creada para unha organización.
O documento OpenAPI está dispoñible en /api/v1/openapi.json no enderezo de calquera organización, para que os xeradores de clientes vexan sempre a versión á que estás chamando.
Autenticación
As claves da API utilízanse en scripts e integracións de servidor a servidor. Unha persoa administradora crea a clave en /admin/integrations/api-keys, escolle os ámbitos e só pode vela unha vez. Envíase como token bearer:
curl -H "Authorization: Bearer qk_live_..." https://acme.quirelms.com/api/v1/users?limit=50As claves comezan por qk_live_ ou qk_test_. Crea unha clave propia para cada integración.
OAuth 2.1 utilízase en aplicacións que actúan en nome dunha persoa coa sesión iniciada. Rexistra un cliente en /admin/integrations/oauth-clients e, a continuación, utiliza o fluxo de código de autorización con PKCE (/oauth/authorize, /oauth/token) ou as credenciais de cliente para un cliente automático. A información de descubrimento está en /.well-known/oauth-authorization-server. Un ámbito restrinxe as operacións dun token; nunca lle permite facer máis do que pode facer a persoa.
Os ámbitos son resource:read, resource:write e resource:delete, por exemplo courses:read ou enrolments:write. Hai catro ámbitos privilexiados que aparecen cun aviso na pantalla de consentimento: audit:read, roles:write, tenants:write e users:delete.
Peticións
- Paxinación: todas as listas utilizan cursores. Envía
limite, a continuación, utiliza o valornext_cursordepagecomocursormentres a lista indiquehas_morecomo verdadeiro (exemplo máis abaixo). Non hai desprazamento por posición. - Cambios desde unha data:
updated_sincedevolve os cambios posteriores a unha hora determinada. Combínao coninclude_deleted=trueou consulta/<resource>/deletionspara saber que se eliminou. - Identificadores externos: a maioría dos recursos acepta un
external_idpropio e/<resource>/ext:{external_id}permite ler ou actualizar mediante ese identificador, polo que non é necesario gardar os identificadores de Quire ao sincronizar. - Idempotencia: envía unha cabeceira
Idempotency-KeyconPOST,PATCHeDELETE. Se repetes unha petición coa mesma clave, recibes a primeira resposta e a operación non se realiza por duplicado. É obrigatoria nos endpoints masivos. - Versións: a versión principal está no camiño (
/v1). Dentro dela, cada cambio incompatible corresponde a unha revisión cunha data que se escolle coa cabeceiraQuire-Version, por exemploQuire-Version: 2026-09-20. Se omites a cabeceira, recibes a revisión vixente cando se emitiu a credencial.
Unha páxina dunha lista:
{"data": [...], "page": {"next_cursor": "eyJ2Ijox...", "has_more": true, "limit": 100}}Erros
Todos os erros utilizan o formato de documento de problemas 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..."}Emprega code para distinguir os erros, xa que é estable; detail está redactado para persoas, é seguro para mostrar e pode cambiar. Se non recoñeces un código, clasifícao segundo category:
| Categoría | Estado | Reintento |
|---|---|---|
validation |
422, con detalles dos campos en errors |
Non |
authentication |
401 | Non |
authorization |
403 | Non |
not_found |
404 | Non |
conflict |
409 | Ás veces |
precondition |
412 | Non |
quota |
402 para o plan, 413 para o tamaño | Non |
rate_limit |
429, con Retry-After |
Si |
upstream |
502 ou 504 | Si |
internal |
500 | Si |
Cita request_id cando contactes co servizo de asistencia.
Webhooks
Crea unha subscrición en /admin/webhooks ou mediante a API en /webhook_subscriptions. Escolle os eventos polo nome (enrolment.created), por área (enrolment.*) ou todos (*). Primeiro, Quire envía un webhook.ping; a subscrición comeza cando o teu endpoint responde.
As entregas cumpren a especificación Standard Webhooks:
POST /hooks/quire
webhook-id: 01JB7XQK4Z8FQ2M3N4P5R6S7T8
webhook-timestamp: 1790000000
webhook-signature: v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE=Para verificar unha entrega:
- Constrúe a cadea
{webhook-id}.{webhook-timestamp}.{raw body}cos bytes exactos recibidos, antes de analizar o JSON. - Calcula HMAC-SHA256 sobre esa cadea coa clave secreta da subscrición e codifícaa en base64.
- Compara en tempo constante o resultado con cada valor
v1,dewebhook-signature. Durante a rotación pode haber dous; calquera coincidencia é válida. - Rexeita as marcas de tempo que difiran máis de cinco minutos do teu reloxo.
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);
});
}Evita duplicados mediante webhook-id: unha entrega pode chegar varias veces. O corpo inclúe identificadores e un breve resumo; consulta o recurso para obter o seu estado actual. As entregas fallidas repítense con intervalos crecientes durante un máximo de 72 horas e pódense reenviar desde o rexistro de entregas.
MCP
O servidor MCP de Quire está en /mcp no enderezo da organización e utiliza HTTP transmisible. Un cliente MCP descubre o servidor OAuth en /.well-known/oauth-protected-resource; a persoa inicia sesión e dá o seu consentimento como con calquera cliente OAuth. As ferramentas actúan cos permisos desa persoa e as ferramentas destrutivas piden confirmación. As persoas administradoras escollen as ferramentas dispoñibles en /admin/integrations/mcp.
Plans e API
As claves da API, os clientes OAuth, os webhooks e o servidor MCP forman parte da prestación da API incluída no plan; todos os plans estándar a inclúen. Se un plan non ofrece esta prestación, rexeítanse a creación dunha clave, cliente ou subscrición, as escrituras REST e as conexións MCP; as lecturas REST seguen funcionando para que se poidan exportar os datos. O rexeitamento é un documento de problemas co código commerce.plan_entitlement, da categoría precondition.
Extensións
Os tipos de actividade, bloques, métodos de inscrición, métodos de inicio de sesión, tipos de preguntas, informes, temas e integracións propios de Quire decláranse no mesmo rexistro de extensións ao que pode engadir extensións unha instalación autoaloxada. As extensións compílanse dentro da aplicación: non hai un cargador de complementos durante a execución e as organizacións aloxadas non poden engadir extensións propias. As persoas administradoras activan ou desactivan cada extensión na organización en /admin/extensions (consulta a guía de administración).
Para crear unha, comeza co bloque e o tema de exemplo en packages/integration/extensions/src/sample.ts. Escolle o punto de extensión e consulta o seu contrato en points.ts; a continuación, declara a extensión cun identificador, unha versión, unha licenza, o que ofrece e o que require, e indica se unha organización a pode desactivar. Rexístraa no lugar onde se compoñen a aplicación web e o traballador, para que ambos coincidan. Ao construírse e cada vez que se chama register, o rexistro comproba as regras propias de cada punto, rexeita unha configuración non válida enumerando todos os problemas e mantén intacto o rexistro. As probas propias da extensión deben comprobar que extensionContractProblems non contén ningún problema e que desactivala cambia o comportamento que afecta.