← 返回 Billbook

遠端記賬 API

最後更新:2026 年 5 月 10 日

透過個人 API token,從 cURL、iOS 捷徑或自動化腳本遠端記一筆帳。Token 是寫入專用:能新增交易、能讀取分類與標籤清單,但無法讀取或刪除任何交易資料。

1. 取得 token

以 admin 身分登入 Billbook,打開設定 → 🔑 遠端記賬 API,點「產生 token」。

明文 token 只會顯示一次,請立即複製保存。資料庫只保留 SHA-256 雜湊,token 一旦遺失只能重新產生(會作廢舊的)。

Token 格式:bb_<userId>_<secret>。所有 API 請求都用 Authorization: Bearer <token> 帶入。

2. POST /api/ingest — 新增一筆交易

請求 body 是一個 JSON 物件,欄位如下:

  • title (string, 必填) — 交易名稱
  • amount (number, 必填) — 金額,必須為正數
  • type (string, 選填,預設 expense) — expense / income / prepaid_expense / pending_income
  • category (string, 選填) — 分類名稱
  • note (string, 選填) — 備註
  • created_at (string, 選填) — ISO 8601 時間,省略則為現在
curl -X POST https://billbook.me/api/ingest \
  -H "Authorization: Bearer bb_<userId>_<secret>" \
  -H "Content-Type: application/json" \
  -d '{"title":"Coffee","amount":120,"type":"expense","category":"Food"}'

# response: 201
{ "id": "...", "created_at": "..." }

3. GET /api/ingest/categories — 取分類清單

回傳 admin 帳號設定的分類名稱清單,順序與儀表板下拉選單一致。回應只有名稱字串,不含 id 或交易資料。

curl https://billbook.me/api/ingest/categories \
  -H "Authorization: Bearer bb_<userId>_<secret>"

# response: 200
{ "categories": ["Food", "Rent", "..."] }

4. GET /api/ingest/tags — 取最近用過的標籤

回傳最近更新的標籤前綴(#XXX 那種),預設 20 個,可用 ?limit= 調整(上限 100)。

tag_prefixes 表還沒建立,回傳空陣列而非錯誤。

curl "https://billbook.me/api/ingest/tags?limit=20" \
  -H "Authorization: Bearer bb_<userId>_<secret>"

# response: 200
{ "tags": ["#management-fee", "#travel", "..."] }

5. 錯誤碼

所有錯誤都是 JSON:{ "error": "訊息" }

  • 401 — 缺少授權、token 格式錯誤、token 已撤銷或不符
  • 402 — 訂閱已到期,需續訂才能寫入
  • 405 — Method 不支援(例如對 /api/ingest 發 GET)
  • 501 — 伺服器尚未設定 SUPABASE_SERVICE_ROLE_KEY
  • 500 — 其他內部錯誤

6. 安全與限制

設計上只能寫入呼叫者自己組織的交易,無法跨 org 或讀取既有資料:

  • user_id 永遠是 token 擁有者本人,無法偽造
  • org_id 永遠是擁有者的 org,無法跨組織寫入
  • token 只會發給 admin 角色(manager / staff 收到 403)
  • 回應不洩漏其他資料列,只回 { id, created_at }
  • 撤銷後立即失效,可在設定中隨時旋轉

7. iOS 捷徑範例

建立一個「取得 URL 內容」動作,URL 設為 https://billbook.me/api/ingest,方法 POST,標頭加 Authorization: Bearer bb_...Content-Type: application/json,請求內文用 JSON:{"title":"咖啡","amount":120,"type":"expense"}。把 titleamount 換成從捷徑輸入或詢問的變數即可。

本文件僅作為快速參考,實際行為以後端程式碼為準。