---
title: "Водич за програмери"
description: "REST API на Quire, OAuth, веб-куки, MCP-серверот и екстензии."
image: "https://docs.quirelms.com/og.png"
---

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

# Водич за програмери

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

Користете ја API-адресата на вашата организација и потврда со опсег. Започнете со барање за читање, проверете го одговорот и држете ги тајните надвор од контролата на изворниот код и од примерите во документацијата.

Quire има едно јавно API: REST преку HTTPS, опишано во OpenAPI 3.1-документ, со потпишани веб-куки за настани и MCP-сервер за асистенти со вештачка интелигенција. [Референцата за API](https://docs.quirelms.com/api/) ги наведува сите точки на влез и сите настани.

## Адреси <!--quire:addresses-->

Секоја организација има своја адреса, а API-то се наоѓа под неа:

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

Потврдата одлучува за која организација се работи. Клуч за една организација употребен на адресата на друга е одбиен.

OpenAPI-документот се служи на `/api/v1/openapi.json` на адресата на било која организација, така што генераторите на клиенти секогаш ја гледаат верзијата што ја повикувате.

## Проверка на идентитет <!--quire:authentication-->

**API-клучевите** се за скрипти и интеграции од сервер до сервер. Администраторот создава еден на `/admin/integrations/api-keys`, ги избира неговите опсези и го гледа еднаш. Испратете го како bearer-токен:

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

Клучевите започнуваат со `qk_live_` или `qk_test_`. Дајте му на секоја интеграција нејзин сопствен клуч.

**OAuth 2.1** е за апликации што дејствуваат во име на најавено лице. Регистрирајте клиент на `/admin/integrations/oauth-clients`, а потоа користете го текот на кодот за овластување со PKCE (`/oauth/authorize`, `/oauth/token`) или клиентски потврди за машински клиент. Откривањето е на `/.well-known/oauth-authorization-server`. Опсегот го стеснува она што токенот може да го прави; никогаш не му дозволува повеќе од тоа што лицето може.

Опсезите се `resource:read`, `resource:write` и `resource:delete`, на пример `courses:read` или `enrolments:write`. Четири се привилегирани и се прикажуваат со предупредување на екранот за согласност: `audit:read`, `roles:write`, `tenants:write` и `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>

## Барања <!--quire:requests-->

- **Пагинација**: секој список е пагиниран со курсор. Поставете `limit`, потоа `next_cursor` од `page` како `cursor` додека `has_more` е true (примерот подолу). Нема отстапување.
- **Промени од**: `updated_since` го враќа она што се променило по одреден временски момент. Поврзете го со `include_deleted=true` или читајте го `/<resource>/deletions` за да дознаете што било отстрането.
- **Надворешни идентификатори**: повеќето ресурси го прифаќаат вашиот сопствен `external_id`, а `/<resource>/ext:{external_id}` чита или утврдува запис по него, така што синхронизацијата никогаш не мора да ги чува идентификаторите на Quire.
- **Идемпотентност**: испратете заглавие `Idempotency-Key` на `POST`, `PATCH` и `DELETE`. Повторниот обид со истиот клуч го враќа првиот одговор наместо да ја врши работата двапати. Масовните точки на влез го бараат тоа.
- **Верзии**: главната верзија е во патеката (`/v1`). Внатре во неа, секоја нарушувачка промена е датирана ревизија, избрана со заглавието `Quire-Version`, на пример `Quire-Version: 2026-09-20`. Без заглавието ја добивате ревизијата што била актуелна кога била издадена вашата потврда.

Страница од список:

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

## Грешки <!--quire:errors-->

Секоја грешка е проблем-документ според 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..."}
```

Разликувајте според `code`, кој е стабилен; `detail` е напишан за луѓе, безбеден за да им се прикаже и може да се менува. Кога не препознавате код, групирајте според `category`:

| Категорија | Статус | Обид повторно |
| --- | --- | --- |
| `validation` | 422, со детали за полето во `errors` | Не |
| `authentication` | 401 | Не |
| `authorization` | 403 | Не |
| `not_found` | 404 | Не |
| `conflict` | 409 | Понекогаш |
| `precondition` | 412 | Не |
| `quota` | 402 за планот, 413 за големина | Не |
| `rate_limit` | 429, со `Retry-After` | Да |
| `upstream` | 502 или 504 | Да |
| `internal` | 500 | Да |

Наведете го `request_id` кога ќе контактирате со поддршката.

## Веб-куки <!--quire:webhooks-->

Претплатете се на `/admin/webhooks` или преку API-то на `/webhook_subscriptions`. Изберете ги настаните по име (`enrolment.created`), по област (`enrolment.*`) или сите (`*`). Quire прво испраќа `webhook.ping`; претплатата започнува откако вашата точка на влез ќе му одговори.

Испораките следат спецификација Standard Webhooks:

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

За да проверите испорака:

1. Изградете ја низата `{webhook-id}.{webhook-timestamp}.{raw body}` од точно примениите бајти, пред било какво JSON-парсирање.
2. Пресметајте HMAC-SHA256 врз неа со тајната на вашата претплата и отпечатете ја во base64.
3. Спорете со секоја вредност `v1,` во `webhook-signature` во константно време. Може да има две за време на ротација на тајната; соодветноста на било која од нив е важечка.
4. Одбивајте временска ознака повеќе од пет минути од вашиот часовник.

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

Дедуплицирајте по `webhook-id`: една испорака може да пристигне повеќе од еднаш. Телото носи идентификатори и краток резиме; повикајте го ресурсот за неговата тековна состојба. Неуспешните испораки се обидуваат повторно со експоненцијално повлекување до 72 часа и може да се репродуцираат од дневникот за испорака.

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

MCP-серверот на Quire е на `/mcp` на адресата на организацијата, преку streamable HTTP. MCP-клиентот го открива OAuth-серверот од `/.well-known/oauth-protected-resource`, а лицето се најавува и дава согласност како со секој OAuth-клиент. Алатките дејствуваат во тоа лице, со неговите дозволи, а разорните алатки бараат потврда. Администраторите избираат кои алатки се достапни на `/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>

## Планови и API <!--quire:plans-and-the-api-->

API-клучевите, OAuth-клиентите, веб-куките и MCP-серверот припаѓаат на API-правото на планот и секој стандарден план го вклучува. На план без него, создавањето клуч, клиент или претплата е одбиено, REST-записите и MCP-поврзувањата се одбиени, а REST-читањата продолжуваат да работат за податоците да останат извозливи. Одбивањето е проблем-документ со кодот `commerce.plan_entitlement`, во категоријата `precondition`.

## Екстензии <!--quire:extensions-->

Сопствените видови активности, блокови, методи за запишување, методи за најавување, видови прашања, извештаи, теми и интеграции на Quire се декларирани низ истото регистар за екстензии на кое и самодржена инсталација може да додаде. Екстензиите се компајлирани: нема товарач на приклучоци во извршувањето, и хостирана организација не може да додаде еден. Администраторите вклучуваат или исклучуваат секоја екстензија за нивната организација на `/admin/extensions` (видете го [водичот за администратори](/mk/admin/extensions/)).

За да напишете една, започнете од примерочниот блок и тема во `packages/integration/extensions/src/sample.ts`. Изберете ја точката на продолжување и прочитајте го нејзиниот договор во `points.ts`, а потоа декларирајте ја екстензијата со идентификатор, верзија, лиценца, тоа што ја обезбедува и бара, и дали организацијата може да ја исклучи. Регистрирајте ја каде што се составуваат веб-апликацијата и работникот, за да се согласат двајцата. Регистарот ги проверува сопствените правила на секоја точка кога се гради и секогаш кога ќе повикате `register`, одбива збир што би бил неважечки со наведување на секој проблем и го остава регистарот непроменет кога тоа го прави. Сопствените тестови на екстензијата треба да тврдат дека `extensionContractProblems` е празен за неа и дека нејзиното исклучување го менува она на што влијае.

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