Appearance
开放 API
Base URL:https://<你的机灵兔部署域名>/api/open
除 POST /auth/token 外,其余接口都需要:
Authorization: Bearer <app access token>限流
每个端点都按 app_key/app_id 维度限流(每分钟):成功响应带 X-RateLimit-Limit / X-RateLimit-Remaining / X-RateLimit-Reset(秒, 滑动窗口下 = 最老一条记录滑出窗口的剩余时间);超限返回 429,带 Retry-After(秒)。建议根据 X-RateLimit-Remaining 自适应退避,而不要盲猜。
| 端点分组 | 限额(次/分钟) |
|---|---|
POST /auth/token | 20 |
GET /org/members、GET /org/users、GET /org/teams…、POST /im/send、POST /kb/search | 60 |
POST /ai/completions、GET /ai/models、GET /usage、POST /db/query、/tools[/{id}]系列 | 30 |
端点速查
| 端点 | 能力 | 一句话 |
|---|---|---|
POST /auth/token | — | app_key/secret 换 2h token |
POST /auth/user | 免登 | authCode 换用户身份 |
GET /usage | 任意 | 本应用自己的积分消耗概况(按天) |
GET /org/members | contacts | 成员列表(分页) |
GET /org/users?user_ids= | contacts | 按 id 批量查成员(≤100 个,逗号分隔,事件回调只有 user_id 时用这个) |
GET /org/teams、GET /org/teams/{id}/members | contacts | 团队树/团队成员 |
POST /im/send | im | 给成员发工作通知(≤100 人/次) |
GET /ai/models | ai | 可用对话模型清单(不必硬编码模型 id) |
POST /ai/completions | ai | 对话补全(支持 stream SSE) |
POST /kb/search | kb | 绑定知识库内检索,命中带 kb_name/doc_id(稳定引用标识) |
GET /db/databases、GET /db/{id}/tables… | db | 绑定库清单/表结构 |
POST /db/query | db | 只读 SELECT(强校验) |
GET/POST/PUT/DELETE /tools[/{id}] | ai_tools 前提 | 工具自管理(免管理员 UI) |
POST /tools/result | 同上 | 异步工具结果回填 |
GET /jsapi/jlt.js | — | JSAPI SDK(公开) |
GET /schema | — | /api/open/* 子集 OpenAPI 3.1(公开,可导入 Postman/Apifox) |
token 的获取与缓存见免登与鉴权。可直接复制运行的完整调用示例 (curl / Node.js / Python)见完整示例;平台主动推送的事件 回调见事件订阅。
POST /auth/token
app_key + app_secret 换 app access token。
| 参数 | 类型 | 约束 |
|---|---|---|
app_key | string | ≤ 64 字符 |
app_secret | string | ≤ 128 字符 |
json
// 请求
{ "app_key": "oak_xxx", "app_secret": "xxx" }
// 响应
{ "access_token": "xxx", "token_type": "Bearer", "expires_in": 7200 }POST /auth/user
免登:一次性 authCode 换当前用户身份。请求/响应详见免登与鉴权。
| 参数 | 类型 | 约束 |
|---|---|---|
auth_code | string | ≤ 128 字符,5 分钟有效、一次性 |
GET /org/members
需要 contacts 能力。分页读取组织成员,按加入时间排序。
| 参数 | 类型 | 约束 |
|---|---|---|
org_id | string | 可选,缺省 = 应用所属组织;传安装方组织需对方已授 contacts,否则 403 |
offset | int | ≥ 0,默认 0 |
limit | int | 1–100,默认 50 |
json
{
"org_id": "org_abc",
"members": [
{ "user_id": "u_1", "role": "owner", "nickname": "张三", "avatar_url": "", "title": "" }
],
"offset": 0,
"limit": 50
}GET /org/teams
需要 contacts 能力。组织架构(团队拉平 + 各自成员数);parent_team_id 为空表示顶层团队,用它可以自行组装出层级树。
GET /org/teams?org_id=json
{
"org_id": "org_abc",
"teams": [
{ "id": "team_1", "name": "研发组", "description": "", "parent_team_id": null, "member_count": 12, "created_at": "…" },
{ "id": "team_2", "name": "前端小组", "description": "", "parent_team_id": "team_1", "member_count": 5, "created_at": "…" }
]
}GET /org/teams/{team_id}/members
需要 contacts 能力。某个团队的成员(含团队角色 admin/member);团队 必须属于目标组织(org_id 缺省 = 应用所属组织),否则 404。
json
{
"team_id": "team_1",
"members": [
{ "user_id": "u_1", "role": "admin", "nickname": "张三", "avatar_url": "", "title": "前端负责人" }
]
}POST /im/send
需要 im 能力。给组织成员发工作通知,由系统通知账号代发,消息会自动带上 【你的应用名】 前缀——你的应用不能冒充某个用户说话。
| 参数 | 类型 | 约束 |
|---|---|---|
user_ids | string[] | 1–100 个,目标必须是该组织成员,否则该项返回失败 |
content | string | 1–2000 字符 |
org_id | string | 可选,缺省 = 应用所属组织;传安装方组织需对方已授 im |
json
// 请求
{ "user_ids": ["u_1", "u_2"], "content": "你有一条新的审批待处理", "org_id": "" }
// 响应(逐目标返回,单个失败不影响其他目标)
{ "results": [{ "user_id": "u_1", "ok": true }, { "user_id": "u_2", "ok": false, "error": "不是该组织成员" }] }GET /ai/models
需要 ai 能力。可用对话模型清单——模型集由平台统一管理,会随时增删, 三方应用不应在自己代码里硬编码模型 id,改为启动时/定期拉一次这个接口渲染选择器。 name 优先取平台管理员配置的显示名,没配置时是网关侧名称。 default 恒为哨兵值 "default"——等于不传 model;不传时实际路由到哪个 具体型号由平台决定,不对外暴露(直接传这个哨兵给 /ai/completions 即可)。
json
{
"default": "default",
"models": [
{ "id": "deepseek-v4-flash", "name": "deepseek-v4-flash", "context_length": null },
{ "id": "glm-5.2", "name": "GLM 5.2", "context_length": null }
]
}POST /ai/completions
需要 ai 能力。非流式对话补全(OpenAI 兼容的消息格式),计费走应用所属组织 的积分钱包(不是调用方所在组织);组织未开通钱包时返回 402。
| 参数 | 类型 | 约束 |
|---|---|---|
messages | array | 1–50 条,每条 role ≤ 16 字符(user/assistant/system…)、content ≤ 32000 字符 |
model | string | 可选;留空 / "auto" / "default" 都用平台默认模型(具体型号不暴露);也可传 GET /ai/models 返回的任意模型 id |
max_tokens | int | 1–8192,默认 8192 |
temperature | number | 可选,0–2 |
stream | boolean | 可选,默认 false;true 时返回 OpenAI 兼容的 SSE 流(text/event-stream) |
json
// 请求
{
"messages": [{ "role": "user", "content": "帮我总结一下这段文字…" }]
}
// 响应
{
"model": "qwen3.7-plus",
"content": "……",
"finish_reason": "stop",
"usage": { "prompt_tokens": 12, "completion_tokens": 88, "total_tokens": 100 }
}推理模型可能把
max_tokens预算大量花在思考上——平台会在正文被截断 (finish_reason: "length")时自动帮你续写(最多 6 次,接回已生成内容继续, 不重复输出),usage是全部续写轮次的加总。你几乎不会在非流式响应里看到 「200 但content是空字符串」这种情况;stream: true时因为字节已经 边生成边转发给你,无法在服务端悄悄重发,若怀疑被截断请检查 SSE 流末尾的finish_reason并按需自行续问。
POST /kb/search
需要 kb 能力,且应用必须已绑定至少一个知识库(在应用设置里配置,只能绑定 配置人自己能访问的知识库)。检索永远限制在绑定白名单内。
| 参数 | 类型 | 约束 |
|---|---|---|
query | string | 1–200 字符 |
kb_id | string | 可选;传则必须已绑定到此应用,否则 403;缺省检索全部绑定的库 |
max_hits | int | 1–50,默认 20 |
json
// 请求
{ "query": "报销流程", "max_hits": 20 }
// 响应
{ "hits": [{ "kb_id": "kb_1", "kb_name": "员工手册", "doc_id": "doc_1", "path": "报销制度.md", "line": 12, "snippet": "……" }] }
path(文件名)可被重命名/AI 改写,不保证稳定;引用展示请以kb_name+doc_id为准。
GET /org/users
需要 contacts 能力。按 user_id 批量查成员详情——事件回调/webhook 处理时往往 只拿到 user_id,逐个翻全量分页成本高,用这个接口一次换回所有详情。
| 参数 | 类型 | 约束 |
|---|---|---|
user_ids | string | 逗号分隔,最多 100 个,自动去重 |
org_id | string | 可选,缺省 = 应用所属组织 |
json
// GET /org/users?user_ids=u_1,u_2,u_gone
{
"org_id": "org_abc",
"members": [
{ "user_id": "u_1", "role": "owner", "nickname": "张三", "avatar_url": "", "title": "" },
{ "user_id": "u_2", "role": "member", "nickname": "李四", "avatar_url": "", "title": "" }
],
"missing": ["u_gone"]
}missing 里的 id 可能是已离开组织的成员(事件可能仍引用其 id),不算错误。
GET /usage
任意 scope 即可调用。本应用自己的积分消耗概况(排障/自展示用)——只能看到 自己应用的消耗,看不到安装方组织内其他成员/应用的数据。数据来自两个 来源相加:本接口 POST /ai/completions 的调用,以及应用页面内嵌 AI(Web 组件 jlt.agent,需要浏览器端 SDK,见 AI 对话能力)产生的 调用——后者扣的是触发它的组织成员自己的额度,只是在流水上打了归属于本应用 的标签,两者相加才是"这个应用一共花了多少"。
| 参数 | 类型 | 约束 |
|---|---|---|
days | int | 1–30,默认 7 |
json
// GET /usage?days=7
{
"days": 7,
"total_quota": 150,
"calls": 2,
"daily": [{ "date": "2026-08-27", "quota": 150, "calls": 2 }]
}total_quota/daily[].quota 是积分(非人民币金额);calls 为对账行数,可 近似当调用次数。
GET /schema
无需鉴权(公开)。返回 /api/open/* 子集的 OpenAPI 3.1 文档,可直接导入 Postman/Apifox 等工具生成请求集。 注意:开放端点未声明 response_model,生成的 schema 里响应体为空属预期—— 请求体/参数约束以本页为准,鉴权方式(Bearer app token)写在每个路径的 description 里。
bash
curl https://<你的部署域名>/api/open/schemaGET /db/databases / GET /db/{db_id}/tables[/{table}]
需要 db 能力。绑定的数据库清单(只含 id/名称/类型,不含连接信息与凭证); 表清单与表结构用于拼查询。
POST /db/query
需要 db 能力,且 db_id 必须已绑定到此应用。在绑定库上执行只读查询, 安全边界与用户侧完全一致:单条 SELECT/WITH、禁写关键字、行数上限、语句 超时——写语句直接被拒,不会到达数据库。
| 参数 | 类型 | 约束 |
|---|---|---|
db_id | string | 必须在绑定白名单内,否则 403 |
sql | string | 1–8000 字符,单条只读 SELECT |
limit | int | 1–1000,默认 100 |
json
// 请求
{ "db_id": "…", "sql": "SELECT status, COUNT(*) FROM orders GROUP BY status", "limit": 100 }
// 响应
{ "ok": true, "columns": ["status", "count"], "rows": [{ "status": "paid", "count": 12 }] }
// 写语句被拒
{ "ok": false, "error": "仅允许 SELECT 查询" }GET/POST/PUT/DELETE /tools[/{tool_id}]
应用自管理自己的 AI 工具(注册/列出/修改/删除,无需管理员 UI)。POST/PUT 的 callback_url 会先做 challenge 验证;字段与给 AI 注册工具 一致(name/description/parameters/callback_url/timeout_sec(5–120)/ wants_context)。前提:应用已勾选 ai_tools 能力。变更限流 30 次/分钟。
POST /tools/result
异步工具模式的结果回填: {call_id, result}——call_id 来自工具回调体,绑定本应用。
GET /jsapi/jlt.js
公开接口,返回 JSAPI SDK 源码,供页面 <script> 引入。可缓存(1 小时)。
限流
进程内限流,超限返回 429,稍后重试即可:
| 接口 | 限额 |
|---|---|
POST /auth/token | 20 次/分钟(按 app_key) |
POST /im/send | 60 次/分钟(按应用) |
GET /ai/models | 30 次/分钟(按应用) |
POST /ai/completions | 30 次/分钟(按应用) |
POST /kb/search | 60 次/分钟(按应用) |
POST /db/query | 30 次/分钟(按应用) |
/tools 变更(POST/PUT/DELETE) | 30 次/分钟(按应用) |
服务器 IP 白名单
应用设置里可配置服务器 IP 白名单(精确 IP 或 CIDR,如 203.0.113.5、 10.0.0.0/8,最多 20 条)。非空时,所有 /api/open/* 调用(含换 token) 只接受这些来源 IP,其余返回 403——即使 app_secret 泄露,别的机器也换不出 token。留空 = 不限制。
填什么地址
填你应用后端服务器的出口 IP(即它访问机灵兔 API 时对外呈现的地址), 不是你办公室/用户的 IP。服务器有多台或出口不固定时用 CIDR 段。
来源 IP 以反向代理记录的真实客户端地址为准(X-Real-IP / 转发链尾跳), 伪造 X-Forwarded-For 首部无法通过白名单。
错误响应
统一形状:
json
{ "detail": "人类可读的错误说明" }| HTTP 状态 | 含义 |
|---|---|
| 400 | 参数校验失败;authCode 无效/已使用/已过期 |
| 401 | app token 缺失/无效/过期;app_key/app_secret 不正确;密钥已轮换;应用已停用或组织已解散 |
| 402 | 组织钱包未开通(AI 能力) |
| 403 | 能力未被授予;目标组织未安装此应用;知识库未绑定到此应用;来源 IP 不在白名单内 |
| 429 | 触发限流 |
| 502 | 上游模型调用失败(AI 能力) |
| 503 | 系统通知账号暂不可用(im/send) |