---
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/bg/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 сървър за AI
асистенти. [Справочникът за 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` на адреса на организацията, през
потоков 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 се декларират чрез същия регистър на разширенията,
към който може да добави self-hosted инсталация. Разширенията са компилирани в продукта:
няма динамично зареждане на приставки по време на изпълнение и хоствана организация не може да добавя такива.
Администраторите включват и изключват разширенията за своята организация на
`/admin/extensions` (вижте [ръководството за администратора](/bg/admin/extensions/)).

За да създадете разширение, започнете от примерния блок и тема в
`packages/integration/extensions/src/sample.ts`. Изберете точката за разширение и
прочетете договора ѝ в `points.ts`, след това декларирайте разширението с идентификатор, версия,
лиценз, предоставяните и изискваните възможности и дали организацията може да го изключи.
Регистрирайте го там, където се съставят уеб приложението и работникът, така че и двата
да са съгласувани. Регистърът проверява собствените правила на всяка точка при създаването му и всеки път,
когато извикате `register`, отхвърля невалиден набор с изброени всички проблеми и оставя регистъра непроменен. Тестовете на самото разширение трябва да проверят,
че `extensionContractProblems` е празен за него и че изключването му променя
засегнатите от него възможности.

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