---
title: "Guía para desenvolvedores"
description: "A API REST de Quire, OAuth, webhooks, o servidor MCP e as extensións."
image: "https://docs.quirelms.com/og.png"
---

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

# Guía para desenvolvedores

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

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](https://docs.quirelms.com/api/) enumera todos os endpoints e eventos.

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

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 <!--quire:authentication-->

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`.

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

## Peticións <!--quire:requests-->

- **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 <!--quire:errors-->

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 <!--quire: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 <!--quire: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`.

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

## Plans e API <!--quire:plans-and-the-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 <!--quire:extensions-->

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](/gl/admin/extensions/)).

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.

Source: https://docs.quirelms.com/gl/developer/index.mdx
