跳到主要内容

公共 API

帮助台只提供一个公共 API:一个 GraphQL 端点。凭个人访问令牌(Personal Access Token,PAT),schema 中的每个操作都可以在浏览器之外调用。

本页就是契约——什么是稳定的、如何进行身份验证、权限范围授予了什么,以及错误采用何种形式。hdmx 命令行工具构建在其之上,而 API 版本管理说明了这套接口如何演进。

端点​

POST https://<your-host>/backend/<subdomain>/api/<version>/graphql
  • <subdomain> 标识你的账户(与你登录时使用的标识相同)。
  • <version> 是形如 2026-07 的日期版本 —— 参见 API 版本管理。你也可以省略版本段,直接调用 …/backend/<subdomain>/graphql;此时请求由受支持的最旧版本处理,并且每个响应都会告诉你是哪个版本作出的应答。

身份验证​

以 Bearer 凭据的形式发送个人访问令牌:

Authorization: Bearer hdmx_<random>

PAT 生命周期较长(但必须设置有效期),带有权限范围,受 IP 限制,并且可以吊销。它绑定到单个账户:向另一个账户的子域出示令牌会被以 HTTP 401 拒绝。

创建令牌​

在客服端应用的 Settings → API tokens 中自行创建和管理令牌:

  1. 点击 New token。
  2. 为它取一个日后能认出来的名称。
  3. 选择有效期(最长 365 天——没有“永不过期”)。
  4. 设置访问策略——只打开该令牌真正需要的资源,可选只读或读写。默认不授予任何访问权限。
  5. 向允许列表中至少添加一个 IP 地址或 CIDR(必填——参见 IP 允许列表)。表单可以替你填入当前 IP。
  6. 确认并创建。完整令牌只会显示一次——请立即复制。系统只保存哈希值,因此无法再次显示;如果丢失,请轮换令牌以获取新的。

之后你可以编辑令牌的访问策略和允许列表,对其进行轮换(签发新密钥,同时旧密钥在短暂的宽限期内继续可用,便于无停机切换),以及吊销它。每个令牌都会显示上次使用的时间和来源,以及最近的活动日志。

权限范围​

访问控制是粗粒度的,按资源族划分。令牌携带一组固定的权限范围;每个顶层操作都会检查其中之一。

权限范围授予
tickets:read读取工单、消息、草稿、历史记录、附件、报表
tickets:write创建 / 更新 / 删除工单,发布消息,上传附件。隐含 tickets:read
chat:read读取聊天、会话、消息、会话记录
chat:write发送客服消息,加入 / 离开 / 关闭 / 重新打开会话。隐含 chat:read
customers:read读取客户记录
customers:write创建 / 更新 / 合并客户记录。隐含 customers:read
settings:read读取账户设置(部门、状态、优先级、邮箱——不含密钥信息)

邮箱凭据字段(IMAP/SMTP 的用户名、密码和主机)无论权限范围如何都绝不会返回给令牌——这些密钥属于你的邮件服务商,始终处于公共 API 触及不到的地方。

错误分类​

GraphQL 响应使用 errors[].extensions.code:

代码含义HTTP
SCOPE_DENIED令牌缺少所需的权限范围。extensions.valid_values 会列出可满足该操作的权限范围200
RATE_LIMITED该令牌的请求额度已用尽。extensions.retryAfter 为距离重置的秒数,Retry-After 响应头也携带同一数值429
INVALID_API_TOKEN令牌不存在、格式错误或因其他原因不可用200

已吊销的令牌、过期的令牌、跨账户不匹配以及 IP 允许列表拒绝,都会在查询执行之前被拒绝,并以不带 GraphQL 主体的 HTTP 401 返回。请把令牌请求上的 401 理解为“该令牌对此请求已不再有效——请检查它的有效期、权限范围和 IP 允许列表”。

速率限制​

每个带令牌的请求都会返回如下响应头:

X-RateLimit-Limit: 120
X-RateLimit-Remaining: 96
X-RateLimit-Reset: 1715692800

默认额度为每个令牌每分钟 120 次请求。无论读写,每次请求都消耗 1 次额度。超出后返回 HTTP 429,带 Retry-After 响应头以及 extensions.code = "RATE_LIMITED";行为良好的客户端会退避到重置时刻。

IP 允许列表​

每个自助创建的令牌必须至少包含一个 IP 或 CIDR——不存在“任意 IP”的令牌。每个请求的来源 IP 都会与该令牌的列表比对;不匹配会以 HTTP 401 和 extensions.sub_code = "ip_not_allowed" 被拒绝。

  • IPv4、IPv6 和 CIDR 网段均可接受。单台主机请使用 /32(IPv4)或 /128(IPv6)。
  • 网段在保存时会经过校验和规范化。
  • 允许列表在创建后仍可编辑——编辑不会改变密钥。

请从稳定的出口使用令牌:CI runner、定时任务、固定的办公室 NAT,或自有服务器所在的已知 IP 段。泄露的令牌在其允许列表之外的任何地方都毫无用处。

令牌活动​

令牌发出的每个已验证请求都会被记录:时间、操作名称、来源 IP、结果(成功、错误、触发限流、权限范围被拒、已吊销或已过期)以及往返延迟。当令牌行为异常时,这就是应当查看的线索。

版本管理与弃用​

API 采用 YYYY-MM 日期版本。在 URL 中固定一个版本,它至少在 12 个月内保持稳定;在你所用的内容消失之前,弃用会通过带内方式提前告知。完整策略参见 API 版本管理。

探索 schema​

Schema 是自描述的:对带版本的端点使用标准 GraphQL 内省即可生成类型并浏览整个接口。交互式 GraphQL Playground 位于 …/backend/<subdomain>/playground。

curl 快速上手​

以下示例假定主机为 helpdesk.example.com、子域为 acme、版本为 2026-07,且令牌保存在 $TOKEN 中。

读取当前用户(任意权限范围)​

curl -sS https://helpdesk.example.com/backend/acme/api/2026-07/graphql \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"query":"{ currentUser { id email firstname lastname } }"}'

列出近期工单(tickets:read)​

curl -sS https://helpdesk.example.com/backend/acme/api/2026-07/graphql \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "query ($first: Int!) {
ticketList(first: $first) {
edges { node { code subject status { name } updatedAt } }
}
}",
"variables": { "first": 10 }
}'

发布一条公开回复(tickets:write)​

curl -sS https://helpdesk.example.com/backend/acme/api/2026-07/graphql \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation ($input: SaveTicketInput!) {
saveTicket(input: $input) {
ticket { code }
error { code message }
}
}",
"variables": {
"input": {
"id": "TICKET-UUID-HERE",
"message": "Thanks — fixing this now.",
"messageType": "PUBLIC"
}
}
}'

日常使用时,hdmx 命令行工具会把整套接口封装成好用的命令。