Verwenden Sie die API-Adresse Ihrer Organisation und Zugangsdaten mit eingeschränktem Berechtigungsumfang. Beginnen Sie mit einer Leseanfrage, prüfen Sie die Antwort und halten Sie Secrets aus der Versionsverwaltung und aus Dokumentationsbeispielen heraus.
Quire hat eine öffentliche API: REST über HTTPS, beschrieben durch ein OpenAPI-3.1-Dokument, signierte Webhooks für Ereignisse und einen MCP-Server für KI-Assistenten. Die API-Referenz führt alle Endpunkte und Ereignisse auf.
Adressen
Jede Organisation hat eine eigene Adresse, und die API befindet sich darunter:
https://acme.quirelms.com/api/v1/coursesDie Zugangsdaten bestimmen die Organisation. Ein Schlüssel für eine Organisation wird an der Adresse einer anderen abgewiesen.
Das OpenAPI-Dokument wird unter /api/v1/openapi.json an der Adresse jeder Organisation bereitgestellt. So sehen Client-Generatoren immer die Version, die Sie aufrufen.
Authentifizierung
API-Schlüssel sind für Skripte und Server-zu-Server-Integrationen gedacht. Ein Administrator erstellt einen unter /admin/integrations/api-keys, wählt dessen Berechtigungsbereiche aus und sieht ihn nur einmal. Senden Sie ihn als Bearer-Token:
curl -H "Authorization: Bearer qk_live_..." https://acme.quirelms.com/api/v1/users?limit=50Schlüssel beginnen mit qk_live_ oder qk_test_. Verwenden Sie für jede Integration einen eigenen Schlüssel.
OAuth 2.1 ist für Anwendungen gedacht, die im Namen einer angemeldeten Person handeln. Registrieren Sie einen Client unter /admin/integrations/oauth-clients und verwenden Sie dann den Authorization-Code-Flow mit PKCE (/oauth/authorize, /oauth/token) oder Client Credentials für einen Maschinen-Client. Die Discovery-Adresse lautet /.well-known/oauth-authorization-server. Ein Scope schränkt ein, was ein Token darf; er kann niemals mehr Rechte verleihen, als die Person selbst hat.
Scopes sind resource:read, resource:write und resource:delete, zum Beispiel courses:read oder enrolments:write. Vier Scopes haben besondere Rechte und werden auf dem Zustimmungsbildschirm mit einer Warnung angezeigt: audit:read, roles:write, tenants:write und users:delete.
Anfragen
- Seitennavigation: Jede Liste ist cursor-paginiert. Übergeben Sie
limitund anschließendnext_cursorauspagealscursor, solangehas_moreden Wert true hat (siehe Beispiel unten). Einen Offset gibt es nicht. - Änderungen seit einem Zeitpunkt:
updated_sincegibt zurück, was sich nach einem Zeitpunkt geändert hat. Kombinieren Sie es mitinclude_deleted=trueoder lesen Sie/<resource>/deletions, um zu erfahren, was entfernt wurde. - Externe Kennungen: Die meisten Ressourcen akzeptieren Ihre eigene
external_id. Über/<resource>/ext:{external_id}lassen sich Datensätze anhand dieser Kennung abrufen oder per Upsert aktualisieren. Eine Synchronisierung muss daher keine Quire-Kennungen speichern. - Idempotenz: Senden Sie einen
Idempotency-Key-Header beiPOST,PATCHundDELETE. Ein erneuter Versuch mit demselben Schlüssel gibt die erste Antwort zurück, statt die Arbeit doppelt auszuführen. Für Bulk-Endpunkte ist dieser Header erforderlich. - Versionen: Die Hauptversion steht im Pfad (
/v1). Innerhalb davon wird jede inkompatible Änderung durch eine datierte Revision abgebildet, die über den HeaderQuire-Versionausgewählt wird, zum BeispielQuire-Version: 2026-09-20. Ohne Header erhalten Sie die Revision, die bei Ausstellung Ihrer Zugangsdaten aktuell war.
Eine Seite einer Liste:
{"data": [...], "page": {"next_cursor": "eyJ2Ijox...", "has_more": true, "limit": 100}}Fehler
Jeder Fehler ist ein RFC-9457-Problem-Dokument:
{"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..."}Verzweigen Sie anhand von code, denn dieser Wert bleibt stabil. detail ist für Menschen formuliert, kann ihnen gefahrlos angezeigt werden und sich ändern. Wenn Ihnen ein Code unbekannt ist, orientieren Sie sich an category:
| Kategorie | Status | Erneuter Versuch |
|---|---|---|
validation |
422, mit Felddetails in errors |
Nein |
authentication |
401 | Nein |
authorization |
403 | Nein |
not_found |
404 | Nein |
conflict |
409 | Manchmal |
precondition |
412 | Nein |
quota |
402 für den Tarif, 413 für die Größe | Nein |
rate_limit |
429, mit Retry-After |
Ja |
upstream |
502 oder 504 | Ja |
internal |
500 | Ja |
Nennen Sie request_id, wenn Sie den Support kontaktieren.
Webhooks
Richten Sie ein Abonnement unter /admin/webhooks oder über die API unter /webhook_subscriptions ein. Wählen Sie Ereignisse nach Namen (enrolment.created), einen Bereich (enrolment.*) oder alle Ereignisse (*) aus. Quire sendet zuerst ein webhook.ping; das Abonnement beginnt, sobald Ihr Endpunkt darauf antwortet.
Zustellungen entsprechen der Standard-Webhooks-Spezifikation:
POST /hooks/quire
webhook-id: 01JB7XQK4Z8FQ2M3N4P5R6S7T8
webhook-timestamp: 1790000000
webhook-signature: v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE=So verifizieren Sie eine Zustellung:
- Bauen Sie aus den genau empfangenen Bytes und vor jedem JSON-Parsing die Zeichenfolge
{webhook-id}.{webhook-timestamp}.{raw body}. - Berechnen Sie darüber mit dem Abonnement-Secret HMAC-SHA256 und kodieren Sie das Ergebnis mit Base64.
- Vergleichen Sie jeden
v1,-Wert inwebhook-signaturein konstanter Zeit. Während einer Secret-Rotation können zwei Werte vorhanden sein; eine Übereinstimmung reicht aus. - Lehnen Sie einen Zeitstempel ab, der mehr als fünf Minuten von Ihrer Uhr abweicht.
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);
});
}Deduplizieren Sie anhand von webhook-id: Eine Zustellung kann mehrfach eintreffen. Der Body enthält Kennungen und eine kurze Zusammenfassung; rufen Sie den Datensatz ab, um seinen aktuellen Zustand zu erhalten. Fehlgeschlagene Zustellungen werden bis zu 72 Stunden lang mit zunehmenden Abständen erneut versucht und können im Zustellungsprotokoll erneut abgespielt werden.
MCP
Der MCP-Server von Quire ist unter /mcp an der Organisationsadresse über streamable HTTP erreichbar. Ein MCP-Client ermittelt den OAuth-Server über /.well-known/oauth-protected-resource; die Person meldet sich an und stimmt wie bei jedem OAuth-Client zu. Werkzeuge handeln mit den Berechtigungen dieser Person, und destruktive Werkzeuge verlangen eine Bestätigung. Administratoren legen unter /admin/integrations/mcp fest, welche Werkzeuge verfügbar sind.
Tarife und die API
API-Schlüssel, OAuth-Clients, Webhooks und der MCP-Server gehören zum API-Leistungsumfang des Tarifs, den alle Standardtarife enthalten. In einem Tarif ohne diesen Leistungsumfang wird das Erstellen von Schlüsseln, Clients und Abonnements sowie das Schreiben über REST und der Verbindungsaufbau über MCP abgelehnt. REST-Lesezugriffe funktionieren weiterhin, damit die Daten exportiert werden können. Die Ablehnung ist ein Problem-Dokument mit dem Code commerce.plan_entitlement und der Kategorie precondition.
Erweiterungen
Die von Quire bereitgestellten Aktivitätstypen, Blöcke, Einschreibungsmethoden, Anmeldemethoden, Fragetypen, Berichte, Themes und Integrationen werden über dieselbe Erweiterungsregistrierung deklariert, zu der eine selbst gehostete Installation weitere Einträge hinzufügen kann. Erweiterungen werden einkompiliert: Es gibt keinen Plugin-Loader zur Laufzeit, und eine gehostete Organisation kann keine Erweiterung hinzufügen. Administratoren schalten Erweiterungen für ihre Organisation unter /admin/extensions ein oder aus (siehe Administratorhandbuch).
Beginnen Sie beim Schreiben einer Erweiterung mit dem Beispiel-Block und dem Beispiel-Theme unter packages/integration/extensions/src/sample.ts. Wählen Sie den Erweiterungspunkt und lesen Sie dessen Vertrag in points.ts. Deklarieren Sie die Erweiterung anschließend mit ID, Version, Lizenz, bereitgestellten und benötigten Funktionen sowie der Angabe, ob eine Organisation sie ausschalten darf. Registrieren Sie sie dort, wo Webanwendung und Worker zusammengesetzt werden, damit beide dieselbe Konfiguration verwenden. Beim Aufbau und bei jedem Aufruf von register prüft die Registrierung die Regeln des jeweiligen Erweiterungspunkts. Ein ungültiger Satz wird mit Angabe jedes Problems abgewiesen; die Registrierung bleibt dabei unverändert. In den Tests der Erweiterung sollte extensionContractProblems für sie leer sein und geprüft werden, ob das Ausschalten verändert, was sie beeinflusst.