Ir ao contido

Guía para desenvolvedores

A API REST de Quire, OAuth, webhooks, o servidor MCP e as extensións.

Ver como Markdown

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/courses

A 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=50

As 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 limit e, a continuación, utiliza o valor next_cursor de page como cursor mentres a lista indique has_more como verdadeiro (exemplo máis abaixo). Non hai desprazamento por posición.
  • Cambios desde unha data: updated_since devolve os cambios posteriores a unha hora determinada. Combínao con include_deleted=true ou consulta /<resource>/deletions para saber que se eliminou.
  • Identificadores externos: a maioría dos recursos acepta un external_id propio 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-Key con POST, PATCH e DELETE. 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 cabeceira Quire-Version, por exemplo Quire-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:

  1. Constrúe a cadea {webhook-id}.{webhook-timestamp}.{raw body} cos bytes exactos recibidos, antes de analizar o JSON.
  2. Calcula HMAC-SHA256 sobre esa cadea coa clave secreta da subscrición e codifícaa en base64.
  3. Compara en tempo constante o resultado con cada valor v1, de webhook-signature. Durante a rotación pode haber dous; calquera coincidencia é válida.
  4. 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.

Navegación

Escribe para buscar…

↑↓ navegar↵ seleccionarEsc pechar