---
title: "Utviklerveiledning"
description: "Quires REST API, OAuth, webhooks, MCP-tjeneren og utvidelser."
image: "https://docs.quirelms.com/og.png"
---

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

# Utviklerveiledning

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

Bruk organisasjonens API-adresse og en avgrenset legitimasjon. Start med en leseforespørsel, sjekk svaret, og hold hemmeligheter utenfor kildekontroll og dokumentasjonseksempler.

Quire har ett offentlig API: REST over HTTPS, beskrevet av et OpenAPI 3.1-dokument, med signerte webhooks for hendelser og en MCP-tjener for AI-assistenter. [API-referansen](https://docs.quirelms.com/api/) viser alle endepunkter og hendelser.

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

Hver organisasjon har sin egen adresse, og API-et ligger under den:

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

Legitimasjonen avgjør organisasjonen. En nøkkel for én organisasjon brukt på en annens adresse avvises.

OpenAPI-dokumentet tjenes på `/api/v1/openapi.json` på enhver organisasjons adresse, slik at klientgeneratorer alltid ser versjonen du kaller.

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

**API-nøkler** er for skript og tjener-til-tjener-integrasjoner. En administrator oppretter en på `/admin/integrations/api-keys`, velger omfangene dens, og ser den én gang. Send den som et bærertoken:

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

Nøkler begynner med `qk_live_` eller `qk_test_`. Gi hver integrasjon sin egen nøkkel.

**OAuth 2.1** er for applikasjoner som handler som en pålogget person. Registrer en klient på `/admin/integrations/oauth-clients`, og bruk deretter autorisasjonskodeflyten med PKCE (`/oauth/authorize`, `/oauth/token`), eller klientlegitimasjon for en maskinklient. Oppdagelse er på `/.well-known/oauth-authorization-server`. Et omfang innsnevrer hva et token kan gjøre; det lar det aldri gjøre mer enn personen kunne.

Omfang er `resource:read`, `resource:write` og `resource:delete`, for eksempel `courses:read` eller `enrolments:write`. Fire er privilegerte og vises med en advarsel på samtykkeskjermen: `audit:read`, `roles:write`, `tenants:write` og `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>

## Forespørsler <!--quire:requests-->

- **Paginering**: alle lister er markørpaginerte. Send `limit`, deretter `next_cursor` fra `page` som `cursor` mens `has_more` er sann (eksempel nedenfor). Det finnes ingen forskyvning.
- **Endringer siden**: `updated_since` returnerer det som er endret etter et tidspunkt. Kombiner det med `include_deleted=true`, eller les `/<resource>/deletions`, for å lære hva som ble fjernet.
- **Eksterne identifikatorer**: de fleste ressurser godtar din egen `external_id`, og `/<resource>/ext:{external_id}` leser eller upserter etter den, slik at en synkronisering aldri trenger å lagre Quires identifikatorer.
- **Idempotens**: send en `Idempotency-Key`-header på `POST`, `PATCH` og `DELETE`. Et nytt forsøk med samme nøkkel returnerer det første svaret i stedet for å gjøre arbeidet to ganger. Bulkendepunkter krever det.
- **Versjoner**: hovedversjonen står i stien (`/v1`). Innen den er hver brytende endring en datert revisjon, valgt med `Quire-Version`-headeren, for eksempel `Quire-Version: 2026-09-20`. Uten headeren får du revisjonen som var gjeldende da legitimasjonen din ble utstedt.

En side av en liste:

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

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

Hver feil er et RFC 9457-problemdokument:

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

Forgren på `code`, som er stabil; `detail` er skrevet for mennesker, trygg å vise dem, og kan endres. Når du ikke gjenkjenner en kode, grupper etter `category`:

| Kategori | Status | Prøv igjen |
| --- | --- | --- |
| `validation` | 422, med feltdetaljer i `errors` | Nei |
| `authentication` | 401 | Nei |
| `authorization` | 403 | Nei |
| `not_found` | 404 | Nei |
| `conflict` | 409 | Noen ganger |
| `precondition` | 412 | Nei |
| `quota` | 402 for planen, 413 for størrelse | Nei |
| `rate_limit` | 429, med `Retry-After` | Ja |
| `upstream` | 502 eller 504 | Ja |
| `internal` | 500 | Ja |

Oppgi `request_id` når du kontakter brukerstøtte.

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

Abonner på `/admin/webhooks`, eller gjennom API-et på `/webhook_subscriptions`. Velg hendelsene etter navn (`enrolment.created`), etter område (`enrolment.*`) eller alle (`*`). Quire sender først en `webhook.ping`; abonnementet starter når endepunktet ditt svarer på den.

Leveringer følger Standard Webhooks-spesifikasjonen:

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

For å verifisere en levering:

1. Bygg strengen `{webhook-id}.{webhook-timestamp}.{raw body}` fra nøyaktig de mottatte bytene, før enhver JSON-tolkning.
2. Beregn HMAC-SHA256 over den med abonnementshemmeligheten din, og base64 den.
3. Sammenlign med hver `v1,`-verdi i `webhook-signature` i konstant tid. Det kan være to under en hemmelighetsrotering; begge som samsvarer er gyldige.
4. Avvis et tidsstempel mer enn fem minutter fra klokken din.

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

Dedupliser på `webhook-id`: en levering kan komme mer enn én gang. Kroppen bærer identifikatorer og et kort sammendrag; hent ressursen for dens gjeldende tilstand. Mislykkede leveringer prøves på nytt med nedtrapping i opptil 72 timer, og kan spilles av på nytt fra leveringsloggen.

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

Quires MCP-tjener er på `/mcp` på organisasjonens adresse, over strømmbar HTTP. En MCP-klient oppdager OAuth-tjeneren fra `/.well-known/oauth-protected-resource`, og personen logger på og samtykker som med enhver OAuth-klient. Verktøy handler som den personen, med tillatelsene deres, og destruktive verktøy ber om bekreftelse. Administratorer velger hvilke verktøy som er tilgjengelige på `/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>

## Planer og API-et <!--quire:plans-and-the-api-->

API-nøkler, OAuth-klienter, webhooks og MCP-tjeneren tilhører planens API-rettighet, og alle standardplaner inkluderer den. På en plan uten den avvises oppretting av nøkkel, klient eller abonnement, REST-skriving og MCP-tilkoblinger avvises, og REST-lesing fortsetter å virke slik at dataene forblir eksporterbare. Avvisningen er et problemdokument med koden `commerce.plan_entitlement`, i `precondition`-kategorien.

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

Quires egne aktivitetstyper, blokker, påmeldingsmetoder, påloggingsmetoder, spørsmålstyper, rapporter, temaer og integrasjoner erklæres gjennom samme utvidelsesregister som en selvdrevet installasjon kan legge til. Utvidelser kompileres inn: det finnes ingen kjøretidspluginlaster, og en driftet organisasjon kan ikke legge til en. Administratorer slår hver utvidelse på eller av for organisasjonen sin på `/admin/extensions` (se [administratorveiledningen](/nb/admin/extensions/)).

For å skrive en, start fra eksempelblokken og -temaet i `packages/integration/extensions/src/sample.ts`. Velg utvidelsespunktet og les kontrakten dens i `points.ts`, og erklær deretter utvidelsen med en id, en versjon, en lisens, hva den tilbyr og krever, og om en organisasjon kan slå den av. Registrer den der webapplikasjonen og arbeideren settes sammen, slik at begge er enige. Registeret sjekker hvert punkts egne regler når det bygges og hver gang du kaller `register`, avviser et sett som ville vært ugyldig med hvert problem navngitt, og lar registeret være uendret når det gjør det. Utvidelsens egne tester bør hevde at `extensionContractProblems` er tom for den og at å slå den av endrer det den påvirker.

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