公開 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 中自行建立與管理權杖:
- 點選 New token。
- 為它取一個日後認得出來的名稱。
- 選擇到期時間(最長 365 天——沒有「永不到期」)。
- 設定存取原則——只開啟這個權杖真正需要的資源,可選唯讀或可讀寫。預設不授予任何存取權。
- 在允許清單中至少加入一個 IP 位址或 CIDR(必填——參見 IP 允許清單)。表單可以替你填入目前的 IP。
- 檢查後建立。完整權杖只會顯示一次——請立即複製。系統只保存雜湊值,因此無法再次顯示;若不慎遺失,請輪替權杖以取得新的。
之後你可以編輯權杖的存取原則與允許清單,對它進行輪替(發出新的密鑰,同時舊密鑰在短暫的寬限期內仍可使用,方便你無中斷切換),以及撤銷它。每個權杖都會顯示上次使用的時間與來源,以及最近的活動紀錄。
權限範圍
存取控制是粗粒度的,依資源族劃分。權杖帶有一組固定的權限範圍;每個最上層操作都會檢查其中之一。
| 權限範圍 | 授予 |
|---|---|
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 命令列工具會把整套介面包裝成好用的命令。