---
title: "Gabay ng developer"
description: "REST API ng Quire, OAuth, mga webhook, MCP server, at mga extension."
image: "https://docs.quirelms.com/og.png"
---

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

# Gabay ng developer

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

Gamitin ang API address ng organisasyon mo at credential na may limitadong scope.
Magsimula sa read request, tingnan ang tugon, at ilayo ang mga secret sa source
control at mga halimbawa sa dokumentasyon.

Iisa ang pampublikong API ng Quire: REST sa HTTPS na inilalarawan ng dokumentong
OpenAPI 3.1, pirmadong webhook para sa mga event, at MCP server para sa mga AI
assistant. Inililista sa [sanggunian ng API](https://docs.quirelms.com/api/) ang bawat endpoint at event.

## Mga address <!--quire:addresses-->

May sariling address ang bawat organisasyon at nasa ilalim nito ang API:

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

Tinutukoy ng credential ang organisasyon. Tatanggihan ang key ng isang organisasyon
kapag ginamit sa address ng iba.

Ipinadadala ang dokumentong OpenAPI sa `/api/v1/openapi.json` sa address ng
anumang organisasyon upang palaging makita ng mga client generator ang tinatawagan
mong bersiyon.

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

Para sa mga script at server-to-server integration ang **API key**. Gumagawa
ang administrador nito sa `/admin/integrations/api-keys`, pumipili ng mga scope,
at minsan lang ito nakikita. Ipadala ito bilang bearer token:

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

Nagsisimula sa `qk_live_` o `qk_test_` ang mga key. Bigyan ng sariling key ang
bawat integration.

Para sa application na kumikilos bilang naka-sign in na tao ang **OAuth 2.1**.
Magrehistro ng client sa `/admin/integrations/oauth-clients`, saka gamitin ang
authorization code flow na may PKCE (`/oauth/authorize`, `/oauth/token`), o
client credentials para sa machine client. Nasa `/.well-known/oauth-authorization-server`
ang discovery. Nililimitahan ng scope ang kayang gawin ng token; hindi nito
lalampasan ang mga pahintulot ng tao.

`resource:read`, `resource:write`, at `resource:delete` ang mga scope, halimbawa
`courses:read` o `enrolments:write`. May apat na may pribilehiyo at ipinapakita
kasama ang babala sa consent screen: `audit:read`, `roles:write`, `tenants:write`,
at `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>

## Mga request <!--quire:requests-->

- **Pagination**: gumagamit ng cursor pagination ang bawat list. Ipadala ang
  `limit`, saka ang `next_cursor` mula sa `page` bilang `cursor` habang true ang
  `has_more` (halimbawa sa ibaba). Walang offset.
- **Mga pagbabago mula noon**: ibinabalik ng `updated_since` ang mga binago
  pagkatapos ng oras. Isabay ang `include_deleted=true`, o basahin ang
  `/<resource>/deletions`, para malaman ang inalis.
- **Mga external identifier**: tinatanggap ng karamihan ng resource ang sarili
  mong `external_id`; binabasa o ini-upsert ito ng `/<resource>/ext:{external_id}`
  kaya hindi kailangang itago ng sync ang mga identifier ng Quire.
- **Idempotency**: ipadala ang `Idempotency-Key` header sa `POST`, `PATCH`, at
  `DELETE`. Ibinabalik ng retry na may kaparehong key ang unang response sa halip
  na ulitin ang trabaho. Kailangan ito ng bulk endpoint.
- **Mga bersiyon**: nasa path ang major version (`/v1`). Pumipili sa loob nito ng
  petsadong revision para sa bawat breaking change gamit ang header na
  `Quire-Version`, halimbawa `Quire-Version: 2026-09-20`. Kapag walang header,
  makukuha mo ang revision na kasalukuyan noong inilabas ang credential.

Isang pahina ng list:

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

## Mga error <!--quire:errors-->

RFC 9457 problem document ang bawat error:

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

Gamitin sa branching ang `code`, na hindi nagbabago; para sa tao ang `detail`,
ligtas itong ipakita at maaari itong magbago. Kapag hindi mo kilala ang code,
pangkatin ayon sa `category`:

| Kategorya | Status | Retry |
| --- | --- | --- |
| `validation` | 422, may detalye ng field sa `errors` | Hindi |
| `authentication` | 401 | Hindi |
| `authorization` | 403 | Hindi |
| `not_found` | 404 | Hindi |
| `conflict` | 409 | Minsan |
| `precondition` | 412 | Hindi |
| `quota` | 402 para sa plan, 413 para sa laki | Hindi |
| `rate_limit` | 429, may `Retry-After` | Oo |
| `upstream` | 502 o 504 | Oo |
| `internal` | 500 | Oo |

Isama ang `request_id` kapag nakikipag-ugnayan sa support.

## Mga webhook <!--quire:webhooks-->

Mag-subscribe sa `/admin/webhooks` o sa API sa `/webhook_subscriptions`.
Piliin ang mga event ayon sa pangalan (`enrolment.created`), area
(`enrolment.*`), o lahat (`*`). Nagpapadala muna ang Quire ng `webhook.ping`;
magsisimula ang subscription kapag sinagot ito ng endpoint mo.

Sumusunod ang mga delivery sa Standard Webhooks specification:

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

Para beripikahin ang delivery:

1. Buuin ang string na `{webhook-id}.{webhook-timestamp}.{raw body}` mula sa
   eksaktong natanggap na bytes bago i-parse bilang JSON.
2. Kuwentahin ang HMAC-SHA256 dito gamit ang subscription secret at i-encode
   bilang base64.
3. Ihambing sa constant time sa bawat value na `v1,` ng
   `webhook-signature`. Maaaring dalawa ang mga ito habang nagpapalit ng secret;
   valid ang alinmang tumugma.
4. Tanggihan ang timestamp na lampas limang minuto ang layo sa oras mo.

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

Gumamit ng `webhook-id` para iwasan ang pagdoble: maaaring dumating nang higit
sa isang beses ang delivery. May identifier at maikling buod ang body; kunin ang
resource para sa kasalukuyan nitong estado. Muling sinusubukan nang may pagitan
ang nabigong delivery nang hanggang 72 oras at maaari rin itong i-replay mula sa
delivery log.

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

Nasa `/mcp` sa address ng organisasyon ang MCP server ng Quire at gumagamit ito
ng streamable HTTP. Nadi-discover ng MCP client ang OAuth server mula sa
`/.well-known/oauth-protected-resource`; mag-sign in at magbigay ng consent ang
tao gaya ng sa alinmang OAuth client. Kumikilos ang mga tool bilang taong iyon,
gamit ang mga pahintulot niya, at humihingi ng kumpirmasyon ang mapanirang tool.
Pinipili ng mga administrador sa `/admin/integrations/mcp` kung aling tool ang
magagamit.

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

## Mga plan at ang API <!--quire:plans-and-the-api-->

Kasama sa API entitlement ng plan ang API key, OAuth client, webhook, at MCP
server; kasama ito sa bawat karaniwang plan. Kapag wala ito sa plan, tatanggihan
ang paggawa ng key, client, o subscription, pati ang REST write at MCP connection;
magpapatuloy ang REST read upang mai-export ang data. Problem document ang
pagtangging may code na `commerce.plan_entitlement` sa kategoryang `precondition`.

## Mga extension <!--quire:extensions-->

Idinedeklara ang sariling activity type, block, enrollment method, sign-in
method, question type, report, theme, at integration ng Quire sa extension
registry na maaaring dagdagan ng self-hosted na installation. Kino-compile ang
mga extension: walang runtime plugin loader at hindi makapagdagdag nito ang
hosted na organisasyon. Ino-on o ino-off ng mga administrador ang bawat extension
para sa organisasyon sa `/admin/extensions` (tingnan ang [gabay ng administrador](/fil/admin/extensions/)).

Para magsulat nito, magsimula sa sample block at theme sa
`packages/integration/extensions/src/sample.ts`. Piliin ang extension point at
basahin ang contract nito sa `points.ts`, saka ideklara ang extension na may ID,
bersiyon, lisensiya, ibinibigay at kailangan nito, at kung maaari itong i-off ng
organisasyon. Irehistro ito sa composition ng web application at worker upang
magkasundo ang dalawa. Sinusuri ng registry ang sariling tuntunin ng bawat point
kapag binubuo at tuwing tatawagin ang `register`; tatanggihan nito ang invalid na
set, ililista ang bawat problema, at pananatilihing hindi nagbabago ang registry.
Dapat tiyakin ng mga test ng extension na walang laman ang `extensionContractProblems`
para rito at binabago ng pag-off ang naaapektuhan nito.

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