---
title: "راهنمای توسعه‌دهندگان"
description: "REST API کوایر، OAuth، وب‌هوک‌ها، سرور MCP و افزونه‌ها."
image: "https://docs.quirelms.com/og.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.quirelms.com/fa/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/) همهٔ endpointها و رویدادها را فهرست می‌کند.

## نشانی‌ها <!--quire:addresses-->

هر سازمان نشانی خودش را دارد و API زیر همان نشانی است:

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

اعتبارنامه سازمان را تعیین می‌کند. استفاده از کلید یک سازمان در نشانی سازمان دیگر رد می‌شود.

سند OpenAPI در نشانی هر سازمان از `/api/v1/openapi.json` ارائه می‌شود، پس مولدهای کارخواه همیشه نسخه‌ای را می‌بینند که فراخوانی می‌کنید.

## احراز هویت <!--quire:authentication-->

**کلیدهای API** برای اسکریپت‌ها و یکپارچه‌سازی‌های سروربه‌سرورند. مدیر در `/admin/integrations/api-keys` کلیدی می‌سازد، دامنه‌هایش را انتخاب می‌کند و فقط یک‌بار می‌بیندش. آن را به‌صورت bearer token بفرستید:

```
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` کارخواهی ثبت کنید و سپس از جریان authorization code همراه PKCE (`/oauth/authorize`، `/oauth/token`) یا اعتبارنامهٔ کارخواه برای کارخواه ماشینی استفاده کنید. کشف در `/.well-known/oauth-authorization-server` است. دامنه، کارهایی را که token می‌تواند انجام دهد محدود می‌کند و هرگز اجازه‌ای فراتر از توان آن شخص نمی‌دهد.

دامنه‌ها `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-->

- **صفحه‌بندی**: همهٔ فهرست‌ها با cursor صفحه‌بندی می‌شوند. `limit` را بفرستید و `next_cursor` از `page` را به‌عنوان `cursor` بفرستید، تا وقتی `has_more` درست است (نمونه در پایین). offset وجود ندارد.
- **تغییرها از زمانی مشخص**: `updated_since` مواردی را برمی‌گرداند که پس از زمان مشخصی تغییر کرده‌اند. آن را با `include_deleted=true` همراه کنید یا `/<resource>/deletions` را بخوانید تا بفهمید چه چیزی برداشته شده است.
- **شناسه‌های بیرونی**: بیشتر منابع `external_id` خودتان را می‌پذیرند و `/<resource>/ext:{external_id}` بر پایهٔ آن می‌خواند یا upsert می‌کند؛ پس برای همگام‌سازی لازم نیست شناسه‌های Quire را ذخیره کنید.
- **تکرارپذیری**: سرآیند `Idempotency-Key` را برای درخواست‌های `POST`، `PATCH` و `DELETE` بفرستید. تکرار درخواست با همان کلید، پاسخ نخست را می‌دهد و کار را دوباره انجام نمی‌دهد. endpointهای گروهی به این کلید نیاز دارند.
- **نسخه‌ها**: نسخهٔ اصلی در مسیر است (`/v1`). درون آن، هر تغییر ناسازگار بازنگری تاریخ‌داری است و با سرآیند `Quire-Version` انتخاب می‌شود؛ برای نمونه `Quire-Version: 2026-09-20`. اگر سرآیند نفرستید، بازنگری هنگام صدور اعتبارنامه را می‌گیرید.

یک صفحه از فهرست:

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

## خطاها <!--quire:errors-->

هر خطا یک problem document به قالب 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` می‌فرستد؛ پس از پاسخ endpoint شما اشتراک آغاز می‌شود.

تحویل‌ها از مشخصات Standard Webhooks پیروی می‌کنند:

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

برای اعتبارسنجی یک تحویل:

1. از بایت‌های دقیق دریافتی و پیش از هرگونه تجزیهٔ JSON، رشتهٔ `{webhook-id}.{webhook-timestamp}.{raw body}` را بسازید.
2. با راز اشتراک HMAC-SHA256 را روی آن محاسبه و نتیجه را به base64 تبدیل کنید.
3. با مقایسهٔ ثابت‌زمان، آن را با هر مقدار `v1,` در `webhook-signature` بسنجید. هنگام چرخش راز ممکن است دو مقدار باشد؛ تطبیق هرکدام معتبر است.
4. timestampای را که بیش از پنج دقیقه با ساعت شما اختلاف دارد رد کنید.

```
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` موارد تکراری را حذف کنید؛ ممکن است یک تحویل بیش از یک‌بار برسد. بدنه شناسه‌ها و خلاصه‌ای کوتاه دارد؛ منبع را بگیرید تا وضعیت کنونی‌اش را بخوانید. تحویل ناموفق تا ۷۲ ساعت با فاصلهٔ فزاینده دوباره فرستاده می‌شود و از گزارش تحویل می‌توان آن را بازپخش کرد.

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

سرور MCP کوایر روی نشانی سازمان در `/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 همچنان کار می‌کند تا داده قابل خروجی گرفتن بماند. ردشدن یک problem document با کد `commerce.plan_entitlement` در دستهٔ `precondition` است.

## افزونه‌ها <!--quire:extensions-->

نوع فعالیت‌ها، بلوک‌ها، روش‌های ثبت‌نام، روش‌های ورود، نوع پرسش، گزارش‌ها، پوسته‌ها و یکپارچه‌سازی‌های خود Quire از راه همان فهرست افزونه‌ای تعریف می‌شوند که نصب خودمیزبان هم می‌تواند به آن بیفزاید. افزونه‌ها در برنامه کامپایل می‌شوند: بارگذار افزونهٔ زمان‌اجرا وجود ندارد و سازمان میزبانی‌شده نمی‌تواند افزونه بیفزاید. مدیران هر افزونه را برای سازمانشان در `/admin/extensions` روشن یا خاموش می‌کنند؛ [راهنمای مدیران](/fa/admin/extensions/) را ببینید.

برای نوشتن افزونه، از بلوک و پوستهٔ نمونه در `packages/integration/extensions/src/sample.ts` آغاز کنید. نقطهٔ افزونه را انتخاب و قرارداد آن را در `points.ts` بخوانید؛ سپس افزونه را با شناسه، نسخه، مجوز، مواردی که فراهم و نیاز دارد و امکان روشن یا خاموش کردنش از سوی سازمان تعریف کنید. آن را در جایی ثبت کنید که برنامهٔ وب و worker با هم ساخته می‌شوند تا هر دو برداشت یکسانی داشته باشند. فهرست هنگام ساخته شدن و هر بار که `register` را فراخوانی می‌کنید قواعد همان نقطه را بررسی می‌کند؛ مجموعه‌ای را که نامعتبر باشد همراه نام همهٔ مشکلات رد می‌کند و در صورت ردشدن، فهرست را بی‌تغییر می‌گذارد. آزمون‌های افزونه باید تأیید کنند که `extensionContractProblems` برای آن خالی است و خاموش کردن افزونه چیزی را که بر آن اثر دارد تغییر می‌دهد.

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