请使用组织的 API 地址和范围受限的凭据。先发送读取请求并检查响应;不要将机密放进源代码管理或文档示例。
Quire 提供一个公共 API:通过 HTTPS 使用 REST,并由 OpenAPI 3.1 文档描述;事件通过签名 webhook 发送,AI 助手可以使用 MCP 服务器。API 参考列出了所有端点和事件。
地址
每个组织都有自己的地址,API 位于该地址下:
https://acme.quirelms.com/api/v1/courses组织由凭据决定。在另一个组织的地址使用某组织的密钥会被拒绝。
任何组织地址下的 /api/v1/openapi.json 都会提供 OpenAPI 文档,因此客户端生成器始终能获取您正在调用的版本。
身份验证
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 注册客户端,然后使用带 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。

请求
- 分页:所有列表都使用游标分页。先传入
limit,再将next_cursor(来自page)作为cursor继续请求;当has_more为 true 时重复此操作(见下例)。不支持 offset。 - 查询变更:
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}}错误
所有错误都使用 RFC 9457 problem 文档:
{"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。
Webhook
可在 /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=验证投递时:
- 根据收到的原始字节(在解析 JSON 前),使用
{webhook-id}.{webhook-timestamp}.{raw body}组成字符串。 - 使用订阅密钥计算其 HMAC-SHA256,并进行 base64 编码。
- 以恒定时间比较结果和
v1,中的webhook-signature值。密钥轮换期间可能同时存在两个值;匹配任意一个即可。 - 如果时间戳与您的时钟相差超过五分钟,则拒绝该请求。
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,使用可流式传输的 HTTP。MCP 客户端从 /.well-known/oauth-protected-resource 发现 OAuth 服务器;用户像使用其他 OAuth 客户端一样登录并授权。工具会按用户本人的权限执行操作,执行破坏性操作前会要求确认。管理员可在 /admin/integrations/mcp 选择可用工具。

套餐与 API
API 权益包含 API 密钥、OAuth 客户端、webhook 和 MCP 服务器;所有标准套餐都包含此权益。不包含该权益的套餐会拒绝创建密钥、客户端或订阅,也会拒绝 REST 写入和 MCP 连接;REST 读取仍可使用,以便导出数据。拒绝响应是 problem 文档,代码为 commerce.plan_entitlement,类别为 precondition。
扩展
Quire 自带的活动类型、区块、选课方式、登录方式、题型、报告、主题和集成都通过同一个扩展注册表声明,自托管安装也可以在其中添加扩展。扩展会在编译时加入:没有运行时插件加载器,托管组织也不能自行添加扩展。管理员可在 /admin/extensions 为组织启用或关闭各个扩展(参见管理员指南)。
编写扩展时,可从 packages/integration/extensions/src/sample.ts 中的示例区块和主题开始。选择扩展点并阅读 points.ts 中的契约,然后声明扩展的标识符、版本、许可证、提供和依赖的内容,以及组织是否可以关闭它。在 Web 应用和 worker 组合的位置注册扩展,确保两者使用一致配置。注册表会在构建时以及每次调用 register 时检查各扩展点的规则;如果扩展集合无效,会列出所有问题并拒绝注册,同时保持注册表不变。扩展自身的测试应确认 extensionContractProblems 对该扩展返回空结果,并验证关闭扩展会改变其影响的功能。