---
title: "Ontwikkelaarsgids"
description: "Die Quire REST API, OAuth, webhooks, MCP-bediener en uitbreidings."
image: "https://docs.quirelms.com/og.png"
---

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

# Ontwikkelaarsgids

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

Gebruik jou organisasie se API-adres en ’n aanmeldbewys met beperkte omvang. Begin met ’n leesversoek, kontroleer die antwoord en hou geheime buite bronbeheer en dokumentasievoorbeelde.

Quire het een openbare API: REST oor HTTPS, beskryf deur ’n OpenAPI 3.1-dokument, met ondertekende webhooks vir gebeurtenisse en ’n MCP-bediener vir KI-assistente. Die [API-verwysing](https://docs.quirelms.com/api/) lys elke eindpunt en gebeurtenis.

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

Elke organisasie het sy eie adres, en die API is daaronder:

```
https://acme.quirelms.com/api/v1/courses
```

Die aanmeldbewys bepaal die organisasie. ’n Sleutel vir een organisasie wat by ’n ander se adres gebruik word, word geweier.

Die OpenAPI-dokument word by `/api/v1/openapi.json` op enige organisasie se adres bedien, sodat kliëntgenerators altyd die weergawe sien wat jy aanroep.

## Verifikasie <!--quire:authentication-->

**API-sleutels** is vir skrifte en bediener-tot-bediener-integrasies. ’n Administrateur skep een by `/admin/integrations/api-keys`, kies sy omvang en sien dit een keer. Stuur dit as ’n draerteken:

```
curl -H "Authorization: Bearer qk_live_..." https://acme.quirelms.com/api/v1/users?limit=50
```

Sleutels begin met `qk_live_` of `qk_test_`. Gee elke integrasie sy eie sleutel.

**OAuth 2.1** is vir toepassings wat as ’n aangemelde persoon optree. Registreer ’n kliënt by `/admin/integrations/oauth-clients`, en gebruik dan die magtigingskodestroom met PKCE (`/oauth/authorize`, `/oauth/token`), of kliëntbewyse vir ’n masjienkliënt. Ontdekking is by `/.well-known/oauth-authorization-server`. ’n Omvang beperk wat ’n teken kan doen; dit laat dit nooit meer doen as wat die persoon kan nie.

Omvange is `resource:read`, `resource:write` en `resource:delete`, byvoorbeeld `courses:read` of `enrolments:write`. Vier is bevoorreg en word met ’n waarskuwing op die toestemmingskerm gewys: `audit:read`, `roles:write`, `tenants:write` en `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>

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

- **Paginering**: elke lys gebruik wyserpaginering. Stuur `limit`, en dan die `next_cursor` van `page` as `cursor` terwyl `has_more` waar is (voorbeeld hieronder). Daar is geen verskuiwingsnommer nie.
- **Veranderinge sedert**: `updated_since` gee terug wat ná ’n tyd verander het. Kombineer dit met `include_deleted=true`, of lees `/<resource>/deletions`, om uit te vind wat verwyder is.
- **Eksterne identifiseerders**: die meeste hulpbronne aanvaar jou eie `external_id`, en `/<resource>/ext:{external_id}` lees of skryf op grond daarvan, sodat ’n sinkronisering nooit Quire se identifiseerders hoef te stoor nie.
- **Idempotensie**: stuur ’n `Idempotency-Key`-opskrif by `POST`, `PATCH` en `DELETE`. ’n Herhaling met dieselfde sleutel gee die eerste antwoord terug in plaas daarvan om die werk twee keer te doen. Grootmaat-eindpunte vereis dit.
- **Weergawes**: die hoofweergawe is in die pad (`/v1`). Daarbinne is elke verandering wat nie agteruitversoenbaar is nie ’n gedateerde hersiening, gekies deur die `Quire-Version`-opskrif, byvoorbeeld `Quire-Version: 2026-09-20`. Sonder die opskrif kry jy die hersiening wat van krag was toe jou aanmeldbewys uitgereik is.

’n Lysbladsy:

```
{"data": [...], "page": {"next_cursor": "eyJ2Ijox...", "has_more": true, "limit": 100}}
```

## Foute <!--quire:errors-->

Elke fout is ’n RFC 9457-probleemdokument:

```
{"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..."}
```

Tak op grond van `code`, wat stabiel is; `detail` is vir mense geskryf, veilig om aan hulle te wys en kan verander. Wanneer jy ’n kode nie herken nie, groepeer volgens `category`:

| Kategorie | Status | Herprobeer |
| --- | --- | --- |
| `validation` | 422, met veldbesonderhede in `errors` | Nee |
| `authentication` | 401 | Nee |
| `authorization` | 403 | Nee |
| `not_found` | 404 | Nee |
| `conflict` | 409 | Soms |
| `precondition` | 412 | Nee |
| `quota` | 402 vir die plan, 413 vir grootte | Nee |
| `rate_limit` | 429, met `Retry-After` | Ja |
| `upstream` | 502 of 504 | Ja |
| `internal` | 500 | Ja |

Haal `request_id` aan wanneer jy ondersteuning kontak.

## Webhooks <!--quire:webhooks-->

Teken in by `/admin/webhooks`, of deur die API by `/webhook_subscriptions`. Kies gebeurtenisse volgens naam (`enrolment.created`), area (`enrolment.*`) of alles (`*`). Quire stuur eers ’n `webhook.ping`; die intekening begin wanneer jou eindpunt daarop antwoord.

Aflewerings volg die Standard Webhooks-spesifikasie:

```
POST /hooks/quire
webhook-id: 01JB7XQK4Z8FQ2M3N4P5R6S7T8
webhook-timestamp: 1790000000
webhook-signature: v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE=
```

Om ’n aflewering te verifieer:

1. Bou die string `{webhook-id}.{webhook-timestamp}.{raw body}` uit die presiese ontvangde grepe, voordat enige JSON-ontleding plaasvind.
2. Bereken HMAC-SHA256 daaroor met jou intekeninggeheim en kodeer die resultaat as base64.
3. Vergelyk in konstante tyd met elke `v1,`-waarde in `webhook-signature`. Daar kan twee wees tydens ’n geheimrotasie; enige passing is geldig.
4. Verwerp ’n tydstempel wat meer as vyf minute van jou horlosie afwyk.

```
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);
  });
}
```

Verwyder duplikate volgens `webhook-id`: ’n aflewering kan meer as een keer aankom. Die liggaam bevat identifiseerders en ’n kort opsomming; haal die hulpbron op vir sy huidige toestand. Mislukte aflewerings word tot 72 uur lank met terugkeertye probeer, en kan weer vanaf die afleweringslog gespeel word.

## MCP <!--quire:mcp-->

Quire se MCP-bediener is by `/mcp` op die organisasie se adres, oor stroomvervoer-HTTP. ’n MCP-kliënt ontdek die OAuth-bediener deur `/.well-known/oauth-protected-resource`, en die persoon meld aan en gee toestemming soos met enige OAuth-kliënt. Nutsmiddels tree met daardie persoon se toestemmings op; vernietigende nutsmiddels vra bevestiging. Administrateurs kies beskikbare nutsmiddels by `/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>

## Planne en die API <!--quire:plans-and-the-api-->

API-sleutels, OAuth-kliënte, webhooks en die MCP-bediener val onder die plan se API-regte, en elke standaardplan sluit dit in. Op ’n plan daarsonder word die skep van ’n sleutel, kliënt of intekening geweier; REST-skrywings en MCP-verbindings word geweier; REST-leesaksies bly werk sodat data uitvoerbaar bly. Die weiering is ’n probleemdokument met kode `commerce.plan_entitlement` in die kategorie `precondition`.

## Uitbreidings <!--quire:extensions-->

Quire se eie aktiwiteitsoorte, blokke, inskrywingsmetodes, aanmeldmetodes, vraagsoorte, verslae, temas en integrasies word verklaar deur dieselfde uitbreidingsregister waaraan ’n selfgehuisveste installasie kan byvoeg. Uitbreidings word saamgestel: daar is geen inprop-laaier tydens looptyd nie en ’n gehuisveste organisasie kan nie een byvoeg nie. Administrateurs skakel elke uitbreiding vir hul organisasie aan of af by `/admin/extensions` (sien die [administrateursgids](/af/admin/extensions/)).

Om een te skryf, begin met die voorbeeldblok en -tema in `packages/integration/extensions/src/sample.ts`. Kies die uitbreidingspunt en lees die kontrak in `points.ts`; verklaar dan die uitbreiding met ’n ID, weergawe, lisensie, wat dit verskaf en vereis, en of ’n organisasie dit mag afskakel. Registreer dit waar die webtoepassing en werker saamgestel word, sodat albei ooreenstem. Die register kontroleer elke punt se eie reëls wanneer dit gebou word en elke keer wat jy `register` aanroep; dit weier ’n ongeldige stel, benoem elke probleem en laat die register onveranderd. Die uitbreiding se eie toetse behoort te bevestig dat `extensionContractProblems` daarvoor leeg is en dat die afskakeling daarvan verander wat dit beïnvloed.

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