---
title: "Guia del desenvolupador"
description: "L’API REST de Quire, OAuth, webhooks, el servidor MCP i les extensions."
image: "https://docs.quirelms.com/og.png"
---

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

# Guia del desenvolupador

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

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](https://docs.quirelms.com/api/) enumera tots els
endpoints i esdeveniments.

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

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

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

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

## Peticions <!--quire:requests-->

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

<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 i API <!--quire:plans-and-the-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 <!--quire: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](/ca/admin/extensions/)).

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.

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