cairn

API 參考

進階套組

292 個端點,依領域分類。每個標出 HTTP method、路徑、 所需權限與模組閘。按 ⌘K 搜尋。

開始使用

API 掛在你的租戶網域之下(base URL https://<your-tenant-domain>/api/v1)——打哪個網域就操作哪個租戶。 REST 語意、JSON 進出。

每個請求帶 Authorization: Bearer …。token 由 CLI 的 OAuth device flow 核發,權限沿用你帳號的角色——API 不會給你後台沒有的能力。

所有端點回傳同一個外殼:成功 { "ok": true, "data": … }、失敗 { "ok": false, "error": { "code", "message" } }(錯誤碼一覽見下方 錯誤碼)。部分端點掛方案模組閘,未啟用回 403 module_disabled

機器可讀規格:openapi.json(OpenAPI 3.1,含參數型別與回應欄位)、llms-full.txt(全文件單檔)。

第一個請求
curl https://your-tenant.example.com/api/v1/orders \
  -H "Authorization: Bearer $CAIRN_TOKEN"

{ "ok": true,
  "data": { "rows": [ … ], "total": 42, "page": 1 } }

錯誤碼

HTTPcode意義
401unauthorized未帶 / 無效 bearer token
403forbidden通過認證但無此權限
403module_disabled租戶未啟用該方案模組
404not_found資源不存在或不在你的 owner-scope 內
409conflict狀態機 / 業務規則衝突
409invariant金流不變式違反
422validation輸入驗證失敗(附 issues[])
500internal伺服器內部錯誤(細節不外洩)
失敗回應
{ "ok": false,
  "error": {
    "code": "validation",
    "message": "…",
    "issues": [ … ]      // 422 才有
  } }

/departures

設定梯次分配模式

PATCH/api/v1/departures/{depId}/allocation-mode
lottery.manage模組:lottery

參數

depId路徑
string· min 1

梯次 ID

mode必填
enum
fcfslottery

分配模式:fcfs(先到先得)或 lottery(抽籤)

回應欄位 · data

ok
boolean

更新成功旗標,恆為 true。

departureId
string

被更新的梯次 id。

mode
"fcfs" | "lottery"

更新後的佔位模式:fcfs 先到先得/lottery 抽籤。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/departures/<depId>/allocation-mode \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "fcfs"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "departureId": "…",
    "mode": "fcfs"
  }
}

登錄梯次成本

POST/api/v1/departures/{depId}/costs
departure_cost.create

參數

depId路徑
string· min 1

梯次 ID

category必填
string· min 1

成本科目類別,決定歸入哪個分類帳

vendorName選填
string

供應商/受款對象名稱

description選填
string

成本說明備註

amountTwd必填
integer

成本金額(台幣,整數)

回應欄位 · data

ok
boolean

建立成功旗標,恆為 true。

id
string

新建立的梯次成本列 id。

請求
curl -X POST https://your-tenant.example.com/api/v1/departures/<depId>/costs \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "category": "<category>",
    "amountTwd": 0
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "id": "…"
  }
}
PATCH/api/v1/departures/{depId}/costs/{costId}
departure_cost.manage

參數

costId路徑
string· min 1

成本列 ID

category必填
string· min 1

成本科目類別,決定歸入哪個分類帳

vendorName選填
string

供應商/受款對象名稱

description選填
string

成本說明備註

amountTwd必填
integer

成本金額(台幣,整數)

回應欄位 · data

ok
boolean

更新成功旗標,恆為 true。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/departures/{depId}/costs/<costId> \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "category": "<category>",
    "amountTwd": 0
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}
DELETE/api/v1/departures/{depId}/costs/{costId}
departure_cost.manage

參數

costId路徑
string· min 1

成本列 ID

回應欄位 · data

ok
boolean

刪除成功旗標,恆為 true。

請求
curl -X DELETE https://your-tenant.example.com/api/v1/departures/{depId}/costs/<costId> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

該梯次財務摘要

GET/api/v1/departures/{depId}/finance-summary
departure.update

參數

depId路徑
string· min 1

梯次 ID

回應欄位 · data

header
object

梯次表頭(團號/行程名/出發日等基本資訊)。

id
string

梯次 id(dep_ 前綴)。

tripTitle
string

所屬行程標題。

tripSlug
string

所屬行程網址 slug。

departureDate
string

出發日(ISO 'YYYY-MM-DD')。

returnDate
string

回程日(ISO 'YYYY-MM-DD')。

finance
object

應收/已收金額彙整(TWD)。

receivableTwd
number

梯次應收:tour 訂單 order_charge_lines 聚合(排除已取消單)。

collectedTwd
number

實收:tour 訂單 payment_transactions(direction='in')。

cashReturnedTwd
number

客戶現金退回(refund/chargeback/reversal)。

outstandingTwd
number

待收 = 應收 − (實收 − 退回),floor 0。

costTwd
number

成本:departure_costs 真實額(房費另計,見成本登記簿)。

costBilledTwd
number

已轉請款成本。

costUnbilledTwd
number

未轉請款成本。

anomalyOrderCount
number

異常單數:overpaid / partially_refunded / refund pending 的 tour 訂單。

cost
object

成本彙整(各類直接成本合計,TWD)。

totalTwd
number

內帳真實成本合計(TWD 整數,各成本列金額加總)。

billedTwd
number

已轉請款的成本合計(TWD 整數)。

unbilledTwd
number

尚未轉請款的成本合計(TWD 整數)。

declarableTwd
number

外帳可申報金額合計(TWD 整數,各列憑證金額加總)。

nonDeclarableTwd
number

無憑證的不可申報成本合計(TWD 整數,逐列取 金額−憑證 的正值,不可跨列抵減)。

count
number

成本列筆數。

請求
curl -X GET https://your-tenant.example.com/api/v1/departures/<depId>/finance-summary \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "header": {
      "id": "…",
      "tripTitle": "…",
      "tripSlug": "…",
      "departureDate": "…",
      "returnDate": "…"
    },
    "finance": {
      "receivableTwd": 0,
      "collectedTwd": 0,
      "cashReturnedTwd": 0,
      "outstandingTwd": 0,
      "costTwd": 0,
      "costBilledTwd": 0,
      "costUnbilledTwd": 0,
      "anomalyOrderCount": 0
    },
    "cost": {
      "totalTwd": 0,
      "billedTwd": 0,
      "unbilledTwd": 0,
      "declarableTwd": 0,
      "nonDeclarableTwd": 0,
      "count": 0
    }
  }
}

該梯次抽籤訂單清單

GET/api/v1/departures/{depId}/lottery-orders
order.read

參數

depId路徑
string· min 1

梯次 ID

回應欄位 · data[]

orderId
string

訂單 id。

orderNumber
string

訂單編號。

customerName
string

訂購人姓名。

partySize
number

佔位人數。

lotteryState
"applied" | "won" | "lost"

抽籤狀態:applied 已應募/won 中籤/lost 未中籤。

backupChoiceCount
number

客人自選的有序備案筆數(order_backup_choices;0 = 無備案)。

collectedTwd
number

已收現金(payment_transactions direction='in');抽籤未中安置時的訂金結轉基準。

failoverFromOrderId
string | null

落腳譜系:本單若是由某主單 force-place / cascade 落腳而成立的備案單,指向原主單 id。 null = 本單即主單(非備案落腳單)。供線控從備案列回溯主單。

awaitingPlacement
boolean

true when lottery_state='lost' and still active (not cancelled). Means backup cascade exhausted — awaiting manual placement or explicit cancel.

請求
curl -X GET https://your-tenant.example.com/api/v1/departures/<depId>/lottery-orders \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "orderId": "…",
      "orderNumber": "…",
      "customerName": "…",
      "partySize": 0,
      "lotteryState": "applied",
      "backupChoiceCount": 0,
      "collectedTwd": 0,
      "failoverFromOrderId": "…",
      "awaitingPlacement": true
    }
  ]
}

該梯次旅客名單

GET/api/v1/departures/{depId}/manifest
order.read

參數

depId路徑
string· min 1

梯次 ID

回應欄位 · data[]

orderId
string

所屬訂單 id。

orderNumber
string

所屬訂單編號。

travelerName
string

旅客姓名。

phone
string

聯絡電話。

email
string

聯絡 Email。

isPrimary
boolean

是否為該訂單的主要聯絡人(訂購人)。

gender
"male" | "female" | "other" | null

性別(明文 enum-like):'male'|'female'|'other'|null(未填)。

birthDate
string | null

生日 ISO `YYYY-MM-DD`;null = 未填。

diet
string | null

飲食需求(葷素)明文;null = 未填。

medicalNotes
string | null

醫療 / 過敏 / 病史備註明文;null = 未填。

specialNeeds
string | null

「飲食 · 特殊需求」欄的合併顯示字串(diet + medical_notes,以 ` · ` 併接)。 結構化欄落地後改吃 diet / medical_notes(不再湊 roommate_pref —— 分房需求回歸分房面板)。 兩者皆空 → null。

emergencyContactName
string | null

緊急聯絡人姓名;null = 未填。

emergencyContactPhone
string | null

緊急聯絡人電話;null = 未填。

consentPending
boolean

該訂單是否仍缺最新版 PDPA 同意書(per-order,同訂單所有旅客共享此旗標)。 true = 未簽 / 只簽過舊版;與 dashboard KPI、催簽 badge 同一述詞。

orderStatus
string

Single display status (派生自三軸,與 deriveOrderDisplayStatus 同 precedence)。

amount
number

該訂單應收金額(TWD;自 order_charge_lines 派生)。

請求
curl -X GET https://your-tenant.example.com/api/v1/departures/<depId>/manifest \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "orderId": "…",
      "orderNumber": "…",
      "travelerName": "…",
      "phone": "…",
      "email": "…",
      "isPrimary": true,
      "gender": "male",
      "birthDate": "…",
      "diet": "…",
      "medicalNotes": "…",
      "specialNeeds": "…",
      "emergencyContactName": "…",
      "emergencyContactPhone": "…",
      "consentPending": true,
      "orderStatus": "…",
      "amount": 0
    }
  ]
}

成本轉請款:以選定的未轉成本列建立一張

POST/api/v1/departures/{depId}/payables
payable.create

參數

depId路徑
string· min 1

梯次 ID

costIds必填
array· min 1

要轉成請款單的成本列 ID 清單,至少一筆

payeeType必填
enum
supplierguidestaff_commissionother

受款人類型:supplier(供應商)/ guide(領隊)/ staff_commission(員工佣金)/ other(其他)

payeeName必填
string· min 1

受款人姓名/戶名(必填)

payeeBankAccount選填
string

受款人銀行帳號

payeeBankName選填
string

受款人銀行名稱

payeeTaxId選填
string

受款人統一編號/稅籍編號

submitImmediately選填
boolean

設為 true 時建立後立即送出核簽,否則僅存為草稿

回應欄位 · data

ok
boolean

轉請款成功旗標,恆為 true。

payableId
string

新建立的出款單(payable)id。

payableNumber
string

出款單編號。

請求
curl -X POST https://your-tenant.example.com/api/v1/departures/<depId>/payables \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "costIds": [],
    "payeeType": "supplier",
    "payeeName": "<payeeName>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "payableId": "…",
    "payableNumber": "…"
  }
}

新增餐食紀錄

POST/api/v1/departures/{depId}/prep/catering
departure_prep.manage

參數

depId路徑
string· min 1

梯次 ID

supplier選填
string

餐食供應商名稱

mealPlan選填
string

餐食安排說明(如餐數、菜色)

headcountNote選填
string

人數備註(如素食、特殊餐需求)

status選填
string

餐食安排狀態,預設 pending

回應欄位 · data

ok
boolean

建立成功旗標,恆為 true。

id
string

新建立的餐食紀錄 id。

請求
curl -X POST https://your-tenant.example.com/api/v1/departures/<depId>/prep/catering \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "id": "…"
  }
}

更新餐食紀錄

PATCH/api/v1/departures/{depId}/prep/catering/{id}
departure_prep.manage

參數

depId路徑
string· min 1

梯次 ID

id路徑
string· min 1

餐食紀錄 ID

supplier選填
string

餐食供應商名稱

mealPlan選填
string

餐食安排說明(如餐數、菜色)

headcountNote選填
string

人數備註(如素食、特殊餐需求)

status選填
string

餐食安排狀態

回應欄位 · data

ok
boolean

更新成功旗標,恆為 true。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/departures/<depId>/prep/catering/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

刪除餐食紀錄

DELETE/api/v1/departures/{depId}/prep/catering/{id}
departure_prep.manage

參數

depId路徑
string· min 1

梯次 ID

id路徑
string· min 1

餐食紀錄 ID

回應欄位 · data

ok
boolean

刪除成功旗標,恆為 true。

請求
curl -X DELETE https://your-tenant.example.com/api/v1/departures/<depId>/prep/catering/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

設定行前總檢查某項勾選狀態

POST/api/v1/departures/{depId}/prep/checklist
departure_prep.manage

參數

depId路徑
string· min 1

梯次 ID

itemKey必填
string· min 1

行前檢查項目的代碼

checked必填
boolean

該檢查項目是否已完成勾選

回應欄位 · data

ok
boolean

設定成功旗標,恆為 true。

id
string

行前檢查項紀錄 id。

請求
curl -X POST https://your-tenant.example.com/api/v1/departures/<depId>/prep/checklist \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "itemKey": "<itemKey>",
    "checked": true
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "id": "…"
  }
}

設定梯次期限警戒

POST/api/v1/departures/{depId}/prep/deadlines
departure_prep.manage模組:climbing

參數

depId路徑
string· min 1

梯次 ID

permitApply選填
string

入山申請截止日(ISO 日期);傳空字串或省略則清除此期限

permitDownload選填
string

入山證下載截止日(ISO 日期);傳空字串或省略則清除此期限

climbingInsurance選填
string

登山險送保截止日(ISO 日期);傳空字串或省略則清除此期限

liabilityInsurance選填
string

旅責險送保截止日(ISO 日期);傳空字串或省略則清除此期限

回應欄位 · data

permitApply
string | null

入山申請截止日(ISO 日期;null = 未設 / 已清除)。

permitDownload
string | null

入山證下載截止日(ISO 日期;null = 未設 / 已清除)。

climbingInsurance
string | null

登山險送保截止日(ISO 日期;null = 未設 / 已清除)。

liabilityInsurance
string | null

旅責險送保截止日(ISO 日期;null = 未設 / 已清除)。

ok
boolean

設定成功旗標,恆為 true。

departureId
string

被設定期限的梯次 id。

請求
curl -X POST https://your-tenant.example.com/api/v1/departures/<depId>/prep/deadlines \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "permitApply": "…",
    "permitDownload": "…",
    "climbingInsurance": "…",
    "liabilityInsurance": "…",
    "ok": true,
    "departureId": "…"
  }
}

upsert 一種證件追蹤狀態

POST/api/v1/departures/{depId}/prep/documents
departure_prep.manage

參數

depId路徑
string· min 1

梯次 ID

docType必填
string· min 1

證件/文件種類代碼(如入山申請、保險名冊)

applyStatus選填
enum
todoapplyingapproved

申辦狀態:todo(待辦)/ applying(申請中)/ approved(已核准)

fileReady選填
boolean

文件檔案是否已備妥

uploadedToCloud選填
boolean

文件是否已上傳雲端

fileUri選填
string

文件檔案連結;給 null 清空

note選填
string

備註;給 null 清空

回應欄位 · data

ok
boolean

upsert 成功旗標,恆為 true。

id
string

證件追蹤紀錄 id。

請求
curl -X POST https://your-tenant.example.com/api/v1/departures/<depId>/prep/documents \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "docType": "<docType>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "id": "…"
  }
}

upsert 某裝備品項的需求數

POST/api/v1/departures/{depId}/prep/equipment-needs
departure_prep.manage

參數

depId路徑
string· min 1

梯次 ID

equipmentItemId必填
string· min 1

裝備品項 ID

quantity必填
integer

該品項的需求數量

note選填
string

需求備註;給 null 清空

回應欄位 · data

ok
boolean

upsert 成功旗標,恆為 true。

id
string

裝備需求紀錄 id。

請求
curl -X POST https://your-tenant.example.com/api/v1/departures/<depId>/prep/equipment-needs \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "equipmentItemId": "<equipmentItemId>",
    "quantity": 0
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "id": "…"
  }
}

刪除裝備需求列

DELETE/api/v1/departures/{depId}/prep/equipment-needs/{id}
departure_prep.manage

參數

depId路徑
string· min 1

梯次 ID

id路徑
string· min 1

裝備需求列 ID

回應欄位 · data

ok
boolean

刪除成功旗標,恆為 true。

請求
curl -X DELETE https://your-tenant.example.com/api/v1/departures/<depId>/prep/equipment-needs/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

指派 / 重派領隊到梯次

POST/api/v1/departures/{depId}/prep/guides
departure_prep.manage

參數

depId路徑
string· min 1

梯次 ID

guideId必填
string· min 1

領隊 ID

role必填
enum
leaderassistant

指派角色:leader(領隊)或 assistant(隨隊/助理)

status選填
enum
tentativeconfirmed

指派狀態:tentative(暫定)或 confirmed(已確認)

回應欄位 · data

ok
boolean

指派成功旗標,恆為 true。

id
string

領隊指派紀錄 id。

請求
curl -X POST https://your-tenant.example.com/api/v1/departures/<depId>/prep/guides \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "guideId": "<guideId>",
    "role": "leader"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "id": "…"
  }
}

新增投保紀錄

POST/api/v1/departures/{depId}/prep/insurance
departure_prep.manage

參數

depId路徑
string· min 1

梯次 ID

kind必填
string· min 1

保險種類(如登山險、旅責險)

insurer選填
string

保險公司名稱

policyNo選填
string

保單號碼

status選填
string

投保狀態,預設 pending

note選填
string

備註;給 null 清空

回應欄位 · data

ok
boolean

建立成功旗標,恆為 true。

id
string

新建立的投保紀錄 id。

請求
curl -X POST https://your-tenant.example.com/api/v1/departures/<depId>/prep/insurance \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "<kind>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "id": "…"
  }
}

更新投保紀錄

PATCH/api/v1/departures/{depId}/prep/insurance/{id}
departure_prep.manage

參數

depId路徑
string· min 1

梯次 ID

id路徑
string· min 1

投保紀錄 ID

insurer選填
string

保險公司名稱

policyNo選填
string

保單號碼

status選填
string

投保狀態

note選填
string

備註;給 null 清空

回應欄位 · data

ok
boolean

更新成功旗標,恆為 true。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/departures/<depId>/prep/insurance/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

刪除投保紀錄

DELETE/api/v1/departures/{depId}/prep/insurance/{id}
departure_prep.manage

參數

depId路徑
string· min 1

梯次 ID

id路徑
string· min 1

投保紀錄 ID

回應欄位 · data

ok
boolean

刪除成功旗標,恆為 true。

請求
curl -X DELETE https://your-tenant.example.com/api/v1/departures/<depId>/prep/insurance/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

從裝備需求開租借單

POST/api/v1/departures/{depId}/prep/rentals
departure_prep.manage

參數

depId路徑
string· min 1

梯次 ID

orderId必填
string· min 1

要掛這筆租借費用的訂單 ID

renterName選填
string

租借人姓名;給 null 清空

lines必填
array

租借品項明細(品項 + 數量),數量需大於 0 才計入

回應欄位 · data

ok
boolean

開單成功旗標,恆為 true。

rentalId
string

新開立的裝備租借單 id。

請求
curl -X POST https://your-tenant.example.com/api/v1/departures/<depId>/prep/rentals \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "orderId": "<orderId>",
    "lines": []
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "rentalId": "…"
  }
}

新增派車紀錄

POST/api/v1/departures/{depId}/prep/transport
departure_prep.manage

參數

depId路徑
string· min 1

梯次 ID

description選填
string

派車說明(如路線、接送地點)

driverName選填
string

司機姓名

vehicleInfo選填
string

車輛資訊(如車型、車牌)

fareNote選填
string

車資備註

status選填
string

派車狀態,預設 pending

回應欄位 · data

ok
boolean

建立成功旗標,恆為 true。

id
string

新建立的派車紀錄 id。

請求
curl -X POST https://your-tenant.example.com/api/v1/departures/<depId>/prep/transport \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "id": "…"
  }
}

更新派車紀錄

PATCH/api/v1/departures/{depId}/prep/transport/{id}
departure_prep.manage

參數

depId路徑
string· min 1

梯次 ID

id路徑
string· min 1

派車紀錄 ID

description選填
string

派車說明(如路線、接送地點)

driverName選填
string

司機姓名

vehicleInfo選填
string

車輛資訊(如車型、車牌)

fareNote選填
string

車資備註

status選填
string

派車狀態

回應欄位 · data

ok
boolean

更新成功旗標,恆為 true。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/departures/<depId>/prep/transport/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

刪除派車紀錄

DELETE/api/v1/departures/{depId}/prep/transport/{id}
departure_prep.manage

參數

depId路徑
string· min 1

梯次 ID

id路徑
string· min 1

派車紀錄 ID

回應欄位 · data

ok
boolean

刪除成功旗標,恆為 true。

請求
curl -X DELETE https://your-tenant.example.com/api/v1/departures/<depId>/prep/transport/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

分房表匯出資料列

GET/api/v1/departures/{depId}/rooming-export
departure.update

參數

depId路徑
string· min 1

梯次 ID

回應欄位 · data[]

fullName
string

旅客姓名。

gender
string

性別(中文標籤:男/女/其他)。

roomLabel
string

房號/房間標籤(未排房為「未分房」)。

bedInfo
string

床位資訊(房型中文標籤 + 床位)。

roommates
string

同房其他旅客姓名(依房號分組派生)。

specialRequest
string

特殊需求(房友偏好等自由文字)。

contactSummary
string

聯絡摘要(電話已遮罩,只露末 3 碼)。

請求
curl -X GET https://your-tenant.example.com/api/v1/departures/<depId>/rooming-export \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "fullName": "…",
      "gender": "…",
      "roomLabel": "…",
      "bedInfo": "…",
      "roommates": "…",
      "specialRequest": "…",
      "contactSummary": "…"
    }
  ]
}

該梯次分房檢視

GET/api/v1/departures/{depId}/rooms
departure.update

參數

depId路徑
string· min 1

梯次 ID

回應欄位 · data

departure
object

梯次表頭(id/起訖日/行程名/容量等)。

id
string

梯次 id(dep_ 前綴)。

departureDate
string

出發日(ISO 'YYYY-MM-DD')。

returnDate
string

回程日(ISO 'YYYY-MM-DD')。

tripTitle
string

所屬行程標題。

tripSlug
string

所屬行程網址 slug。

capacity
number

名額上限(人數)。

bookedCount
number

已成團佔用名額(人數)。

rooms
object[]

此梯次的所有房間(含入住旅客)。

id
string

房間 id。

roomLabel
string

房號/房間標籤。

roomType
string

房型(如 single 單人/double 雙人/dorm 通舖)。

bedCount
number

床位數。

bedConfig
string | null

床位配置說明(可空)。

accommodationName
string | null

住宿名稱(梯次配套派生房才有;可空)。

accommodationDate
string | null

住宿日期(YYYY-MM-DD;可空)。

baseCostTwd
number

房間底價成本(TWD)。

upgradeFeeTwd
number

房型升等補款(TWD)。

notes
string | null

備註(可空)。

departureLodgingId
string | null

null = 手動建立的房;non-null = 梯次配套自動派生房的來源 ID。

assignedTravelers
object[]

已入住此房的旅客。

unassignedTravelers
object[]

尚未分房的旅客清單。

id
string

旅客 id。

fullName
string

旅客姓名。

orderId
string

所屬訂單 id。

orderNumber
string

所屬訂單編號。

isPrimary
boolean

是否為該訂單的主要聯絡人(訂購人)。

gender
string | null

性別:'male'|'female'|'other'|null。

birthDate選填
string | undefined

出生日期(YYYY-MM-DD;可空)。

roomPreference
string | null

下單登記的房型偏好(auto-pair 起點提示)。

roommatePref
string | null

指定房友 id / 特殊需求自由文字。

stats
object

分房統計彙總(總人數/已分房數/房間數/升等補款合計)。

totalTravelers
number

此梯次旅客總人數。

assignedCount
number

已分配房間的旅客數。

roomCount
number

房間數。

totalUpgradeFee
number

升等補款合計(TWD 整數)。

請求
curl -X GET https://your-tenant.example.com/api/v1/departures/<depId>/rooms \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "departure": {
      "id": "…",
      "departureDate": "…",
      "returnDate": "…",
      "tripTitle": "…",
      "tripSlug": "…",
      "capacity": 0,
      "bookedCount": 0
    },
    "rooms": [
      {
        "id": "…",
        "roomLabel": "…",
        "roomType": "…",
        "bedCount": 0,
        "bedConfig": "…",
        "accommodationName": "…",
        "accommodationDate": "…",
        "baseCostTwd": 0,
        "upgradeFeeTwd": 0,
        "notes": "…",
        "departureLodgingId": "…",
        "assignedTravelers": []
      }
    ],
    "unassignedTravelers": [
      {
        "id": "…",
        "fullName": "…",
        "orderId": "…",
        "orderNumber": "…",
        "isPrimary": true,
        "gender": "…",
        "birthDate": "…",
        "roomPreference": "…",
        "roommatePref": "…"
      }
    ],
    "stats": {
      "totalTravelers": 0,
      "assignedCount": 0,
      "roomCount": 0,
      "totalUpgradeFee": 0
    }
  }
}

建立一間梯次房間

POST/api/v1/departures/{depId}/rooms
departure.update

參數

depId路徑
string· min 1

梯次 ID

roomLabel必填
string· min 1

房間代號/標籤(如 101、A 房)

roomType必填
string· min 1

房型(如 雙人房、四人房)

bedCount必填
integer

床位數,必須大於 0

bedConfig選填
string

床型配置說明(如 2 大床、1 大 2 小)

accommodationName選填
string

住宿地點/旅宿名稱

accommodationDate選填
string

入住日期(ISO 日期字串)

baseCostTwd選填
integer

房間基本成本(台幣),預設 0

upgradeFeeTwd選填
integer

房型升等補款金額(台幣),預設 0

notes選填
string

房間備註

回應欄位 · data

ok
boolean

建立成功旗標,恆為 true。

id
string

新建立的房間 id。

請求
curl -X POST https://your-tenant.example.com/api/v1/departures/<depId>/rooms \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "roomLabel": "<roomLabel>",
    "roomType": "<roomType>",
    "bedCount": 0
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "id": "…"
  }
}

編輯房間

PATCH/api/v1/departures/{depId}/rooms/{roomId}
departure.update

參數

roomId路徑
string· min 1

房間 ID

roomLabel選填
string

房間代號/標籤;未給則不變

roomType選填
string

房型;未給則不變

bedCount選填
integer

床位數;未給則不變

bedConfig選填
string

床型配置說明;給 null 清空、未給則不變

accommodationName選填
string

住宿地點名稱;給 null 清空、未給則不變

accommodationDate選填
string

入住日期(ISO 字串);給 null 清空、未給則不變

baseCostTwd選填
integer

房間基本成本(台幣);未給則不變

upgradeFeeTwd選填
integer

房型升等補款金額(台幣);未給則不變

notes選填
string

房間備註;給 null 清空、未給則不變

回應欄位 · data

ok
boolean

更新成功旗標,恆為 true。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/departures/{depId}/rooms/<roomId> \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

刪除房間

DELETE/api/v1/departures/{depId}/rooms/{roomId}
departure.update

參數

roomId路徑
string· min 1

房間 ID

回應欄位 · data

ok
boolean

刪除成功旗標,恆為 true。

請求
curl -X DELETE https://your-tenant.example.com/api/v1/departures/{depId}/rooms/<roomId> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

線控確認 auto-pair 建議分組:

POST/api/v1/departures/{depId}/rooms/auto-pair-apply
departure.update

參數

depId路徑
string· min 1

梯次 ID

travelerIds必填
array· min 1

要編入同一房的旅客 ID 清單,至少一人

roomType選填
string· min 1

建立房間的房型,預設 shared(合住)

回應欄位 · data

ok
boolean

套用成功旗標,恆為 true。

roomId
string

建議分組寫入後所在的房間 id。

travelerIds
string[]

被排入該房的旅客 id 清單。

請求
curl -X POST https://your-tenant.example.com/api/v1/departures/<depId>/rooms/auto-pair-apply \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "travelerIds": []
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "roomId": "…",
    "travelerIds": [
      "…"
    ]
  }
}

對某梯次「尚未排房」的旅客

GET/api/v1/departures/{depId}/rooms/auto-pair-preview
departure.update

參數

depId路徑
string· min 1

梯次 ID

回應欄位 · data

suggestion
object

auto-pair 引擎產出的分房建議(未寫入,供線控確認)。

groups
object[]

建議的分房組合(每組一間房,含旅客與需確認註記)。

unmatched
object[]

無法安全自動配對、待人工處理的旅客。

names
object

travelerId → 顯示名(建議分組渲染用)。

請求
curl -X GET https://your-tenant.example.com/api/v1/departures/<depId>/rooms/auto-pair-preview \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "suggestion": {
      "groups": [],
      "unmatched": []
    },
    "names": "…"
  }
}

該梯次套用的成本範本列

GET/api/v1/departures/{depId}/template-costs
departure.update

參數

depId路徑
string· min 1

梯次 ID

回應欄位 · data[]

id
string

梯次成本列 ID。

category
string

成本分類(如 交通 / 餐費 / 保險)。

vendorName
string | null

供應商 / 廠商名(可空)。

description
string | null

摘要說明(可空)。

amountTwd
number

內帳成本金額(TWD;數量 × 單價派生)。

invoiceAmountTwd
number

報帳/發票金額(TWD;is_declarable=true 時同步 amount,否則 0)。

isDeclarable
boolean

是否有合法憑證可報帳(開發票)。

quantityMode
QuantityMode | null

數量模式:fixed 固定值 / headcount 依人頭公式(ceil(Σ人頭 / 組距))。

headcountComponents
HeadcountComponent[] | null

headcount 模式選定的人頭 component(passenger / leader / assistant / driver);fixed 為 null。

groupDivisor
number | null

headcount 模式的組距(每 N 人一組,ceil 進位);null = 直接加總。

quantity
number | null

實際套用的數量(依 quantityMode 派生)。

unitPriceTwd
number | null

內帳單價(TWD;外幣列可為 null)。

currency
string

幣別('TWD' = 台幣列)。

unitPriceForeign
number | null

外幣單價;TWD 列 null。

foreignAmount
number | null

外幣金額快照 = unit_price_foreign × quantity;TWD 列 null。

internalRate
string | null

內帳匯率快照(numeric 字串);TWD 列 null。

externalRate
string | null

外帳匯率快照(numeric 字串);TWD 列 null。

isManualOverride
boolean

是否為線控手動改寫(true 時重算會跳過此列,不覆蓋手改值)。

payableId
string | null

已轉請款 → 鎖定(不可手改 / 重算)。

請求
curl -X GET https://your-tenant.example.com/api/v1/departures/<depId>/template-costs \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "category": "…",
      "vendorName": "…",
      "description": "…",
      "amountTwd": 0,
      "invoiceAmountTwd": 0,
      "isDeclarable": true,
      "quantityMode": null,
      "headcountComponents": null,
      "groupDivisor": 0,
      "quantity": 0,
      "unitPriceTwd": 0,
      "currency": "…",
      "unitPriceForeign": 0,
      "foreignAmount": 0,
      "internalRate": "…",
      "externalRate": "…",
      "isManualOverride": true,
      "payableId": "…"
    }
  ]
}

重設為範本算法

POST/api/v1/departures/{depId}/template-costs/{id}/clear-override
departure_cost.manage

參數

id路徑
string· min 1

範本成本列 ID

回應欄位 · data

ok
boolean

清除手改鎖並重算成功旗標,恆為 true。

請求
curl -X POST https://your-tenant.example.com/api/v1/departures/{depId}/template-costs/<id>/clear-override \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

線控手改某範本成本列

POST/api/v1/departures/{depId}/template-costs/{id}/override
departure_cost.manage

參數

id路徑
string· min 1

範本成本列 ID

amountTwd必填
integer

手動指定的成本金額(台幣),設定後停止自動重算

回應欄位 · data

ok
boolean

手改金額成功旗標,恆為 true。

請求
curl -X POST https://your-tenant.example.com/api/v1/departures/{depId}/template-costs/<id>/override \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "amountTwd": 0
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

套用行程綁定範本到本梯次

POST/api/v1/departures/{depId}/template-costs/apply
departure_cost.create

參數

depId路徑
string· min 1

梯次 ID

回應欄位 · data

ok
boolean

套用成功旗標,恆為 true。

inserted
number

本次新補插入的範本成本行數(冪等,已存在的不重複插)。

請求
curl -X POST https://your-tenant.example.com/api/v1/departures/<depId>/template-costs/apply \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "inserted": 0
  }
}

該梯次各訂單旅客資料完整度

GET/api/v1/departures/{depId}/validation-summary
order.read

參數

depId路徑
string· min 1

梯次 ID

回應欄位 · data[]

orderId
string

訂單 id。

orderNumber
string

訂單編號。

errorCount
number

該訂單的 error(必補缺漏)項目數。

warningCount
number

該訂單的 warning(建議補齊)項目數。

incompleteTravelerCount
number

至少有一項 error 或 warning 的旅客數(資料待補人數)。

errorTravelerCount
number

含 error 的旅客數(出團前置紅標用)。

請求
curl -X GET https://your-tenant.example.com/api/v1/departures/<depId>/validation-summary \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "orderId": "…",
      "orderNumber": "…",
      "errorCount": 0,
      "warningCount": 0,
      "incompleteTravelerCount": 0,
      "errorTravelerCount": 0
    }
  ]
}

團控主列表:以出發日為主軸、彙整 order/付款/同意書

GET/api/v1/departures/control
order.read

參數

range選填
enum
future_60this_monthnext_month

時間視窗:future_60(未來 60 天)/ this_month(本月)/ next_month(下個月),預設不限

trip選填
string

行程 ID,只看該行程的梯次

status選填
string

梯次狀態篩選(如 open / closed)

attention選填
boolean

設為 true 時只回傳付款或同意書有異常、需要關注的梯次

回應欄位 · data[]

id
string

梯次 id。

tripId
string

所屬行程 id。

tripTitle
string

行程名稱。

tripSlug
string

行程公開頁網址代稱(slug)。

groupCode
string | null

團號(可空)。

departureDate
string

出發日(YYYY-MM-DD)。

returnDate
string

回程日(YYYY-MM-DD)。

capacity
number

團位容量(總名額)。

bookedCount
number

已佔位人數。

status
string

梯次狀態(如 open 開放/closed 關閉)。

allocationMode
"fcfs" | "lottery"

佔位模式:fcfs 先到先得/lottery 抽籤。

leaderNames
string[]

已排領隊姓名(confirmed + tentative 皆列;空 = 未指派)。

assistantNames
string[]

已排協作 / 助教姓名(空 = 未指派協作)。

priceTwd
number

定價(TWD)。

agencyPriceTwd
number | null

同業/旅行社報價(TWD;未設為 null)。

promoActive
boolean

是否有進行中的促銷價。

promoPriceTwd
number | null

促銷價(TWD;無促銷為 null)。

promoAgencyPriceTwd
number | null

同業促銷價(TWD;無促銷為 null)。

daysUntilDeparture
number

距出發天數(負值表示已出發)。

travelerCount
number

旅客總人數(未取消訂單的 party_size 加總)。

paidCount
number

已付款人數(party_size 加總)。

pendingCount
number

未結清人數(未付/部分付/已付訂金;不含取消)。

cancelledCount
number

已取消人數(僅供參考,不計入總數)。

ordersWithoutConsent
number

尚未簽署同意書(PDPA)的訂單數。

codedRevenueTwd
number

有折扣訂單的應收營收合計(TWD;排除取消/退款)。

discountTotalTwd
number

折扣金額合計(TWD)。

profitShareTotalTwd
number

利潤分潤金額合計(TWD)。

請求
curl -X GET https://your-tenant.example.com/api/v1/departures/control \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "tripId": "…",
      "tripTitle": "…",
      "tripSlug": "…",
      "groupCode": "…",
      "departureDate": "…",
      "returnDate": "…",
      "capacity": 0,
      "bookedCount": 0,
      "status": "…",
      "allocationMode": "fcfs",
      "leaderNames": [
        "…"
      ],
      "assistantNames": [
        "…"
      ],
      "priceTwd": 0,
      "agencyPriceTwd": 0,
      "promoActive": true,
      "promoPriceTwd": 0,
      "promoAgencyPriceTwd": 0,
      "daysUntilDeparture": 0,
      "travelerCount": 0,
      "paidCount": 0,
      "pendingCount": 0,
      "cancelledCount": 0,
      "ordersWithoutConsent": 0,
      "codedRevenueTwd": 0,
      "discountTotalTwd": 0,
      "profitShareTotalTwd": 0
    }
  ]
}

多梯次的分房進度統計

GET/api/v1/departures/room-stats
order.read

參數

ids必填
string· min 1

要查詢的梯次 ID 清單,以逗號分隔(例:a,b,c)

請求
curl -X GET "https://your-tenant.example.com/api/v1/departures/room-stats?ids=<ids>" \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {}
}

/discount-codes

list all discount codes

GET/api/v1/discount-codes
discount.read

回應欄位 · data[]

id
string

折扣碼 id(disc_ 前綴)。

code
string

折扣碼字串(客戶結帳輸入用,租戶內唯一)。

label
string

折扣碼顯示名稱(後台辨識用)。

discountType
DiscountType

折扣型別:fixed 定額折抵 / percentage 比例折抵。

discountValue
number

折扣值:fixed 為 TWD 整數,percentage 為百分比數字。

profitShareType
ProfitShareType | null

分潤型別:fixed 定額 / percentage 比例;null = 無分潤。

profitShareValue
number | null

分潤值:fixed 為 TWD 整數,percentage 為百分比;null = 無分潤。

profitSharePayee
string | null

分潤受款對象(如合作夥伴名稱);null = 無。

isActive
boolean

是否啟用(停用後不可再兌換)。

validFrom
Date | null

生效起始時間;null = 無下限。

validUntil
Date | null

生效截止時間;null = 無上限。

maxRedemptions
number | null

總兌換次數上限;null = 不限。

redemptionCount
number

已兌換次數(不含已取消訂單)。

minOrderTwd
number | null

最低訂單金額門檻(TWD 整數);null = 無門檻。

appliesToAll
boolean

是否適用所有行程(true = 全站,false = 僅限 tripIds 名單)。

maxRedemptionsPerCustomer
number | null

每位客戶兌換次數上限;null = 不限。

allowedPriceChannels
string[] | null

限用的價格通路清單(如 direct / agency);null = 不限。

allowedCustomerTypes
string[] | null

限用的客戶類型清單;null = 不限。

stackable
boolean

是否可與其他折扣疊加使用。

notes
string | null

內部備註;null = 無。

createdAt
Date

建立時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/discount-codes \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "code": "…",
      "label": "…",
      "discountType": "…",
      "discountValue": 0,
      "profitShareType": null,
      "profitShareValue": 0,
      "profitSharePayee": "…",
      "isActive": true,
      "validFrom": null,
      "validUntil": null,
      "maxRedemptions": 0,
      "redemptionCount": 0,
      "minOrderTwd": 0,
      "appliesToAll": true,
      "maxRedemptionsPerCustomer": 0,
      "allowedPriceChannels": "…",
      "allowedCustomerTypes": "…",
      "stackable": true,
      "notes": "…",
      "createdAt": "2026-06-30T08:00:00.000Z"
    }
  ]
}

create a discount code

POST/api/v1/discount-codes
discount.manage

參數

code必填
string· max 64 · min 1

折扣碼字串(前台結帳輸入,不分大小寫須唯一)

label必填
string· max 200 · min 1

折扣碼顯示名稱(後台與報表辨識用)

discountType必填
enum
fixedpercentage

折抵方式:fixed 固定金額(TWD)或 percentage 百分比

discountValue必填
integer

折抵數值;fixed 為折抵金額(TWD),percentage 為百分比(1–100)

profitShareType選填
enum
fixedpercentage

分潤方式:fixed 固定金額或 percentage 百分比;null 為不分潤

profitShareValue選填
integer

分潤數值;搭配 profitShareType,percentage 須 1–100,null 為不分潤

profitSharePayee選填
string· max 200

分潤對象名稱(如合作推廣者),供出款對帳辨識

isActive選填
boolean

是否啟用;停用後前台無法套用

validFrom選填
string

生效起日(YYYY-MM-DD);留空為不限起日

validUntil選填
string

生效迄日(YYYY-MM-DD);留空為不限迄日

maxRedemptions選填
integer

全碼可使用總次數上限;null 為不限

minOrderTwd選填
integer

最低訂單金額門檻(TWD),未達門檻不可套用;null 為不限

appliesToAll選填
boolean

是否適用全部行程;true 時忽略 tripIds

tripIds選填
array

指定可套用的行程 id 清單(appliesToAll=false 時生效)

maxRedemptionsPerCustomer選填
integer

每位客戶可使用次數上限;null 為不限

allowedPriceChannels選填
array

可套用的價格渠道(direct 直客 / agency 同業 / promo 優惠);空陣列為不限

allowedCustomerTypes選填
array

可套用的客戶類型(direct 直客 / agency_contact 同業聯絡人);空陣列為不限

stackable選填
boolean

是否可與其他折扣碼疊加使用

notes選填
string· max 2000

內部備註(不對外顯示)

回應欄位 · data

id
string

新建立折扣碼的 id(disc_ 前綴)。

請求
curl -X POST https://your-tenant.example.com/api/v1/discount-codes \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "<code>",
    "label": "<label>",
    "discountType": "fixed",
    "discountValue": 0
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…"
  }
}

full discount code detail

GET/api/v1/discount-codes/{id}
discount.read

參數

id路徑
string· min 1

折扣碼 id(路徑參數)

回應欄位 · data

id
string

折扣碼 id(disc_ 前綴)。

code
string

折扣碼字串(客戶結帳輸入用,租戶內唯一)。

label
string

折扣碼顯示名稱(後台辨識用)。

discountType
DiscountType

折扣型別:fixed 定額折抵 / percentage 比例折抵。

discountValue
number

折扣值:fixed 為 TWD 整數,percentage 為百分比數字。

profitShareType
ProfitShareType | null

分潤型別:fixed 定額 / percentage 比例;null = 無分潤。

profitShareValue
number | null

分潤值:fixed 為 TWD 整數,percentage 為百分比;null = 無分潤。

profitSharePayee
string | null

分潤受款對象(如合作夥伴名稱);null = 無。

isActive
boolean

是否啟用(停用後不可再兌換)。

validFrom
Date | null

生效起始時間;null = 無下限。

validUntil
Date | null

生效截止時間;null = 無上限。

maxRedemptions
number | null

總兌換次數上限;null = 不限。

redemptionCount
number

已兌換次數(不含已取消訂單)。

minOrderTwd
number | null

最低訂單金額門檻(TWD 整數);null = 無門檻。

appliesToAll
boolean

是否適用所有行程(true = 全站,false = 僅限 tripIds 名單)。

maxRedemptionsPerCustomer
number | null

每位客戶兌換次數上限;null = 不限。

allowedPriceChannels
string[] | null

限用的價格通路清單(如 direct / agency);null = 不限。

allowedCustomerTypes
string[] | null

限用的客戶類型清單;null = 不限。

stackable
boolean

是否可與其他折扣疊加使用。

notes
string | null

內部備註;null = 無。

createdAt
Date

建立時間。

tripIds
string[]

限定適用的行程 id 清單(appliesToAll=false 時生效)。

redemptions
object[]

逐筆兌換紀錄。

orderId
string

兌換該折扣碼的訂單 id(ord_ 前綴)。

orderNumber
string

訂單編號(人類可讀流水號)。

codeSnapshot
string

兌換當下的折扣碼字串快照。

originalTotalTwd
number

套用折扣前的原始應收總額(TWD 整數)。

discountTwd
number

本次折抵金額(TWD 整數)。

profitShareTwd
number

本次分潤金額(TWD 整數)。

orderStatus
string

訂單當前狀態。

createdAt
Date

兌換(下單)時間。

totalDiscountTwd
number

累計折抵金額合計(TWD 整數)。

totalProfitShareTwd
number

累計分潤金額合計(TWD 整數)。

totalPaidTwd
number

兌換訂單累計已收金額合計(TWD 整數)。

請求
curl -X GET https://your-tenant.example.com/api/v1/discount-codes/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "id": "…",
    "code": "…",
    "label": "…",
    "discountType": "…",
    "discountValue": 0,
    "profitShareType": null,
    "profitShareValue": 0,
    "profitSharePayee": "…",
    "isActive": true,
    "validFrom": null,
    "validUntil": null,
    "maxRedemptions": 0,
    "redemptionCount": 0,
    "minOrderTwd": 0,
    "appliesToAll": true,
    "maxRedemptionsPerCustomer": 0,
    "allowedPriceChannels": "…",
    "allowedCustomerTypes": "…",
    "stackable": true,
    "notes": "…",
    "createdAt": "2026-06-30T08:00:00.000Z",
    "tripIds": [
      "…"
    ],
    "redemptions": [
      {
        "orderId": "…",
        "orderNumber": "…",
        "codeSnapshot": "…",
        "originalTotalTwd": 0,
        "discountTwd": 0,
        "profitShareTwd": 0,
        "orderStatus": "…",
        "createdAt": "2026-06-30T08:00:00.000Z"
      }
    ],
    "totalDiscountTwd": 0,
    "totalProfitShareTwd": 0,
    "totalPaidTwd": 0
  }
}

update a discount code

PATCH/api/v1/discount-codes/{id}
discount.manage

參數

id路徑
string· min 1

折扣碼 id(路徑參數)

code必填
string· max 64 · min 1

折扣碼字串(前台結帳輸入,不分大小寫須唯一)

label必填
string· max 200 · min 1

折扣碼顯示名稱(後台與報表辨識用)

discountType必填
enum
fixedpercentage

折抵方式:fixed 固定金額(TWD)或 percentage 百分比

discountValue必填
integer

折抵數值;fixed 為折抵金額(TWD),percentage 為百分比(1–100)

profitShareType選填
enum
fixedpercentage

分潤方式:fixed 固定金額或 percentage 百分比;null 為不分潤

profitShareValue選填
integer

分潤數值;搭配 profitShareType,percentage 須 1–100,null 為不分潤

profitSharePayee選填
string· max 200

分潤對象名稱(如合作推廣者),供出款對帳辨識

isActive選填
boolean

是否啟用;停用後前台無法套用

validFrom選填
string

生效起日(YYYY-MM-DD);留空為不限起日

validUntil選填
string

生效迄日(YYYY-MM-DD);留空為不限迄日

maxRedemptions選填
integer

全碼可使用總次數上限;null 為不限

minOrderTwd選填
integer

最低訂單金額門檻(TWD),未達門檻不可套用;null 為不限

appliesToAll選填
boolean

是否適用全部行程;true 時忽略 tripIds

tripIds選填
array

指定可套用的行程 id 清單(appliesToAll=false 時生效)

maxRedemptionsPerCustomer選填
integer

每位客戶可使用次數上限;null 為不限

allowedPriceChannels選填
array

可套用的價格渠道(direct 直客 / agency 同業 / promo 優惠);空陣列為不限

allowedCustomerTypes選填
array

可套用的客戶類型(direct 直客 / agency_contact 同業聯絡人);空陣列為不限

stackable選填
boolean

是否可與其他折扣碼疊加使用

notes選填
string· max 2000

內部備註(不對外顯示)

回應欄位 · data

ok
boolean

操作成功旗標,恆為 true。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/discount-codes/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "<code>",
    "label": "<label>",
    "discountType": "fixed",
    "discountValue": 0
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

redemption/profit-share report for

GET/api/v1/discount-codes/{id}/redemptions
discount.read

參數

id路徑
string· min 1

折扣碼 id(路徑參數)

回應欄位 · data

id
string

折扣碼 id(disc_ 前綴)。

code
string

折扣碼字串。

label
string

折扣碼顯示名稱。

redemptionCount
number

已兌換次數(不含已取消訂單)。

totalDiscountTwd
number

累計折抵金額合計(TWD 整數)。

totalProfitShareTwd
number

累計分潤金額合計(TWD 整數)。

totalPaidTwd
number

兌換訂單累計已收金額合計(TWD 整數)。

redemptions
object[]

逐筆兌換紀錄。

orderId
string

兌換該折扣碼的訂單 id(ord_ 前綴)。

orderNumber
string

訂單編號(人類可讀流水號)。

codeSnapshot
string

兌換當下的折扣碼字串快照。

originalTotalTwd
number

套用折扣前的原始應收總額(TWD 整數)。

discountTwd
number

本次折抵金額(TWD 整數)。

profitShareTwd
number

本次分潤金額(TWD 整數)。

orderStatus
string

訂單當前狀態。

createdAt
Date

兌換(下單)時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/discount-codes/<id>/redemptions \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "id": "…",
    "code": "…",
    "label": "…",
    "redemptionCount": 0,
    "totalDiscountTwd": 0,
    "totalProfitShareTwd": 0,
    "totalPaidTwd": 0,
    "redemptions": [
      {
        "orderId": "…",
        "orderNumber": "…",
        "codeSnapshot": "…",
        "originalTotalTwd": 0,
        "discountTwd": 0,
        "profitShareTwd": 0,
        "orderStatus": "…",
        "createdAt": "2026-06-30T08:00:00.000Z"
      }
    ]
  }
}

activate / deactivate a discount

POST/api/v1/discount-codes/{id}/set-active
discount.manage

參數

id路徑
string· min 1

折扣碼 id(路徑參數)

isActive必填
boolean

目標啟用狀態:true 啟用、false 停用

回應欄位 · data

ok
boolean

操作成功旗標,恆為 true。

請求
curl -X POST https://your-tenant.example.com/api/v1/discount-codes/<id>/set-active \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "isActive": true
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

read-only checkout preview of a code's

GET/api/v1/discount-codes/preview
discount.read

參數

code必填
string· min 1

欲試算的折扣碼字串

kind必填
enum
tourlodging

產品種類:tour 行程或 lodging 住宿

tripId選填
string

行程 id(kind=tour 時必填)

total必填
integer

試算用原始金額(TWD,未折扣前)

priceChannel選填
string

價格渠道(direct / agency / promo),用於折扣碼資格判定

customerType選填
string

客戶類型(direct / agency_contact),用於折扣碼資格判定

userId選填
string

客戶 user id,用於每客戶使用次數限制判定

請求
curl -X GET "https://your-tenant.example.com/api/v1/discount-codes/preview?code=<code>&kind=<kind>&total=<total>" \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": "…"
}

/group-codes

航空碼對照表

GET/api/v1/group-codes/airlines
group_code.manage

參數

activeOnly選填
enum
truefalse10

傳 true 或 1 時只列出啟用中的航空碼

回應欄位 · data[]

code
string

航空公司代碼(團號組成,通常大寫縮寫,如 EG)。

name
string

航空公司名稱。

isActive
boolean

是否啟用(停用後不可再指派給新梯次)。

displayOrder
number

顯示排序(由小到大)。

usedCount
number

被多少梯次引用。

請求
curl -X GET https://your-tenant.example.com/api/v1/group-codes/airlines \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "code": "…",
      "name": "…",
      "isActive": true,
      "displayOrder": 0,
      "usedCount": 0
    }
  ]
}
POST/api/v1/group-codes/airlines
group_code.manage

參數

code必填
string

對照表碼,2–3 碼大寫英數(自動轉大寫)

name必填
string· max 100 · min 1

碼的顯示名稱(如地區或航空公司全名)

isActive選填
boolean

是否啟用(停用後不再供新團號選用)

displayOrder選填
integer· max 9999 · min 0

排序權重,數字越小越前面

回應欄位 · data

ok
boolean

操作成功旗標,恆為 true。

code
string

新增或更新的航空公司代碼。

請求
curl -X POST https://your-tenant.example.com/api/v1/group-codes/airlines \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "<code>",
    "name": "<name>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "code": "…"
  }
}
PATCH/api/v1/group-codes/airlines
group_code.manage

參數

code必填
string

要更新的對照表碼(不可變更碼本身)

name必填
string· max 100 · min 1

碼的顯示名稱(如地區或航空公司全名)

isActive選填
boolean

是否啟用(停用後不再供新團號選用)

displayOrder選填
integer· max 9999 · min 0

排序權重,數字越小越前面

回應欄位 · data

ok
boolean

操作成功旗標,恆為 true。

code
string

新增或更新的航空公司代碼。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/group-codes/airlines \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "<code>",
    "name": "<name>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "code": "…"
  }
}

前綴團號反查多梯次

GET/api/v1/group-codes/departures
group_code.manage

參數

prefix必填
string· min 1

團號前綴,反查同地區同航空的所有梯次(如 26EGTK)

回應欄位 · data[]

id
string

梯次 id(dep_ 前綴)。

tripId
string

所屬行程 id(trip_ 前綴)。

tripTitle
string

所屬行程標題。

tripSlug
string

所屬行程網址 slug。

departureDate
string

出發日(ISO 'YYYY-MM-DD')。

groupCode
string

完整團號。

regionCode
string | null

地區代碼;null = 未設。

airlineCode
string | null

航空公司代碼;null = 國內團或未設。

請求
curl -X GET "https://your-tenant.example.com/api/v1/group-codes/departures?prefix=<prefix>" \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "tripId": "…",
      "tripTitle": "…",
      "tripSlug": "…",
      "departureDate": "…",
      "groupCode": "…",
      "regionCode": "…",
      "airlineCode": "…"
    }
  ]
}

精確團號反查單一梯次

GET/api/v1/group-codes/departures/{id}
group_code.manage

參數

id路徑
string· min 1

完整團號,反查單一梯次(大小寫不敏感)

回應欄位 · data

id
string

梯次 id(dep_ 前綴)。

tripId
string

所屬行程 id(trip_ 前綴)。

tripTitle
string

所屬行程標題。

tripSlug
string

所屬行程網址 slug。

departureDate
string

出發日(ISO 'YYYY-MM-DD')。

groupCode
string

完整團號。

regionCode
string | null

地區代碼;null = 未設。

airlineCode
string | null

航空公司代碼;null = 國內團或未設。

請求
curl -X GET https://your-tenant.example.com/api/v1/group-codes/departures/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "id": "…",
    "tripId": "…",
    "tripTitle": "…",
    "tripSlug": "…",
    "departureDate": "…",
    "groupCode": "…",
    "regionCode": "…",
    "airlineCode": "…"
  }
}

地區碼對照表

GET/api/v1/group-codes/regions
group_code.manage

參數

activeOnly選填
enum
truefalse10

傳 true 或 1 時只列出啟用中的地區碼

回應欄位 · data[]

code
string

地區代碼(團號組成,通常大寫縮寫,如 YS)。

name
string

地區名稱(如「玉山」)。

isActive
boolean

是否啟用(停用後不可再指派給新梯次)。

displayOrder
number

顯示排序(由小到大)。

usedCount
number

被多少梯次引用 —— UI 鎖頭 / 「使用中 N」。

請求
curl -X GET https://your-tenant.example.com/api/v1/group-codes/regions \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "code": "…",
      "name": "…",
      "isActive": true,
      "displayOrder": 0,
      "usedCount": 0
    }
  ]
}
POST/api/v1/group-codes/regions
group_code.manage

參數

code必填
string

對照表碼,2–3 碼大寫英數(自動轉大寫)

name必填
string· max 100 · min 1

碼的顯示名稱(如地區或航空公司全名)

isActive選填
boolean

是否啟用(停用後不再供新團號選用)

displayOrder選填
integer· max 9999 · min 0

排序權重,數字越小越前面

回應欄位 · data

ok
boolean

操作成功旗標,恆為 true。

code
string

新增或更新的地區代碼。

請求
curl -X POST https://your-tenant.example.com/api/v1/group-codes/regions \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "<code>",
    "name": "<name>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "code": "…"
  }
}
PATCH/api/v1/group-codes/regions
group_code.manage

參數

code必填
string

要更新的對照表碼(不可變更碼本身)

name必填
string· max 100 · min 1

碼的顯示名稱(如地區或航空公司全名)

isActive選填
boolean

是否啟用(停用後不再供新團號選用)

displayOrder選填
integer· max 9999 · min 0

排序權重,數字越小越前面

回應欄位 · data

ok
boolean

操作成功旗標,恆為 true。

code
string

新增或更新的地區代碼。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/group-codes/regions \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "<code>",
    "name": "<name>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "code": "…"
  }
}

/holidays

per-tenant national-holiday / makeup-workday table

GET/api/v1/holidays
public_holiday.read

參數

year選填
integer· max 9999 · min 1000

篩選的西元年份(1000..9999);省略則回傳所有年份

回應欄位 · data

rows
object[]

假日列(依日期排序)。

date
string

日期(ISO 'YYYY-MM-DD')。

name
string

名稱(如「國慶日」「補班」)。

isWorkday
boolean

是否為補班日(true = 該日照常上班,false = 放假)。

請求
curl -X GET https://your-tenant.example.com/api/v1/holidays \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "rows": [
      {
        "date": "…",
        "name": "…",
        "isWorkday": true
      }
    ]
  }
}

upsert / delete a single per-tenant

PUT/api/v1/holidays/{date}
public_holiday.manage

參數

date路徑
string· min 1

假日 / 補班日的日期(YYYY-MM-DD,路徑參數),作為該筆紀錄的自然鍵

name必填
string· max 100 · min 1

假日 / 補班日名稱(如「春節」「補行上班」)

isWorkday選填
boolean

是否為補班日:true 表示原假日改上班、false 表示國定假日;影響行前作業工作日倒數

回應欄位 · data

ok
boolean

操作成功旗標,恆為 true。

請求
curl -X PUT https://your-tenant.example.com/api/v1/holidays/<date> \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "<name>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}
DELETE/api/v1/holidays/{date}
public_holiday.manage

參數

date路徑
string· min 1

要刪除的假日 / 補班日日期(YYYY-MM-DD,路徑參數)

回應欄位 · data

ok
boolean

操作成功旗標,恆為 true。

請求
curl -X DELETE https://your-tenant.example.com/api/v1/holidays/<date> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

holiday / makeup-workday counts for a

GET/api/v1/holidays/stats
public_holiday.read

參數

year必填
integer· max 9999 · min 1000

要統計的西元年份(1000..9999,必填)

回應欄位 · data

holidayCount
number

該年度放假日數。

makeupCount
number

該年度補班日數。

請求
curl -X GET "https://your-tenant.example.com/api/v1/holidays/stats?year=<year>" \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "holidayCount": 0,
    "makeupCount": 0
  }
}

/images

list/search the trip image gallery

GET/api/v1/images
image.read

參數

tripId選填
string

行程 ID 篩選,僅回傳掛在該行程的圖片

q選填
string

關鍵字,模糊比對行程標題、slug、圖說或網址

page選填
integer

分頁頁碼,從 1 起算,預設第 1 頁

pageSize選填
integer· max 200

每頁筆數,上限 200,預設由後端決定

回應欄位 · data

rows
object[]

當頁圖片列。

id
string

圖片資源 id(timg_ 前綴)。

tripId
string

所屬行程 id(trip_ 前綴)。

tripTitle
string

所屬行程標題。

tripSlug
string

所屬行程網址 slug。

url
string

圖片公開 URL。

caption
string | null

圖說文字;null = 無。

displayOrder
number

在行程相簿中的排序(由小到大)。

createdAt
Date

上傳建立時間。

total
number

符合條件的總筆數(跨頁)。

page
number

目前頁碼(1 起算)。

pageSize
number

每頁筆數。

請求
curl -X GET https://your-tenant.example.com/api/v1/images \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "rows": [
      {
        "id": "…",
        "tripId": "…",
        "tripTitle": "…",
        "tripSlug": "…",
        "url": "…",
        "caption": "…",
        "displayOrder": 0,
        "createdAt": "2026-06-30T08:00:00.000Z"
      }
    ],
    "total": 0,
    "page": 0,
    "pageSize": 0
  }
}
POST/api/v1/images
image.manage

參數

tripId必填
string· min 1

要掛上此圖片的行程 ID

url必填
string· max 2000

圖片網址(http 或 https),以引用方式掛載,非檔案上傳

caption選填
string· max 500

圖片說明文字,選填

displayOrder選填
integer· max 9999 · min 0

排序權重,數字越小越前面,預設 0

回應欄位 · data

id
string

新建立圖片的 id(timg_ 前綴)。

請求
curl -X POST https://your-tenant.example.com/api/v1/images \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "tripId": "<tripId>",
    "url": "<url>"
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…"
  }
}

remove a trip image

DELETE/api/v1/images/{id}
image.manage

參數

id路徑
string· min 1

欲刪除的行程圖片 ID

回應欄位 · data

ok
boolean

操作成功旗標,恆為 true。

請求
curl -X DELETE https://your-tenant.example.com/api/v1/images/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

the trip picker for attaching images: draft +

GET/api/v1/images/trips
image.read

回應欄位 · data[]

id
string

行程 id(trip_ 前綴)。

title
string

行程標題。

請求
curl -X GET https://your-tenant.example.com/api/v1/images/trips \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "title": "…"
    }
  ]
}

/lodging

list staff-side direct lodging bookings

GET/api/v1/lodging/bookings
lodging.read

參數

status選填
string

依訂單狀態篩選(省略則回全部)

q選填
string

自由文字關鍵字(訂房人、旅宿等)

回應欄位 · data[]

orderId
string

訂單 id(ord_ 前綴)。

orderNumber
string

訂單編號(人類可讀流水號)。

status
string

顯示狀態(派生自三軸,沿用舊欄名供 UI badge / canCancel 相容)。

bookingState
string

訂位軸狀態(如 confirmed / cancelled)。

paymentState
string

付款軸狀態(如 unpaid / partial / paid)。

refundState
string

退款軸狀態。

totalTwd
number

應收總額(TWD 整數,訂單各應收明細加總)。

createdAt
Date

訂單建立時間。

bookerName
string

訂購人姓名。

bookerEmail
string

訂購人 email。

propertyId
string

住宿館 id(prop_ 前綴)。

propertyName
string

住宿館名稱。

roomTypeId
string

房型 id(rt_ 前綴)。

roomTypeName
string

房型名稱。

checkIn
string

入住日(ISO 'YYYY-MM-DD')。

checkOut
string

退房日(ISO 'YYYY-MM-DD')。

units
number

訂購房間數。

guestCount
number

入住總人數。

請求
curl -X GET https://your-tenant.example.com/api/v1/lodging/bookings \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "orderId": "…",
      "orderNumber": "…",
      "status": "…",
      "bookingState": "…",
      "paymentState": "…",
      "refundState": "…",
      "totalTwd": 0,
      "createdAt": "2026-06-30T08:00:00.000Z",
      "bookerName": "…",
      "bookerEmail": "…",
      "propertyId": "…",
      "propertyName": "…",
      "roomTypeId": "…",
      "roomTypeName": "…",
      "checkIn": "…",
      "checkOut": "…",
      "units": 0,
      "guestCount": 0
    }
  ]
}
POST/api/v1/lodging/bookings
order.create模組:lodging

參數

propertyId必填
string· min 1

旅宿物件 ID

roomTypeId必填
string· min 1

房型 ID(須屬於該旅宿物件)

checkIn必填
string· min 1

入住日(YYYY-MM-DD,含此晚)

checkOut必填
string· min 1

退房日(YYYY-MM-DD,不含此晚,須晚於入住日)

units必填
integer

預訂單元數(房數或床位數,1-50)

guestCount必填
integer

入住人數(1-100,不得超過房型總容納人數)

bookerEmail必填
string· min 1

訂房人 Email(須為已註冊會員)

paymentMethod必填
enum
cashatmmanual

付款方式:cash 現金/atm 轉帳/manual 其他人工

receivingAccountId選填
string

收款帳戶 ID(搭配付款方式記帳,可省略)

notes選填
string

代訂備註

回應欄位 · data

orderId
string

新建立住宿訂單的 id(ord_ 前綴)。

請求
curl -X POST https://your-tenant.example.com/api/v1/lodging/bookings \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "propertyId": "<propertyId>",
    "roomTypeId": "<roomTypeId>",
    "checkIn": "<checkIn>",
    "checkOut": "<checkOut>",
    "units": 0,
    "guestCount": 0,
    "bookerEmail": "<bookerEmail>",
    "paymentMethod": "cash"
  }'
回應
{
  "ok": true,
  "data": {
    "orderId": "…"
  }
}

single lodging booking detail.

GET/api/v1/lodging/bookings/{orderId}
lodging.read

參數

orderId路徑
string· min 1

旅宿訂單 ID

回應欄位 · data

orderId
string

訂單 id(ord_ 前綴)。

orderNumber
string

訂單編號(人類可讀流水號)。

status
string

顯示狀態(派生自三軸,沿用舊欄名供 UI badge / canCancel 相容)。

bookingState
string

訂位軸狀態(如 confirmed / cancelled)。

paymentState
string

付款軸狀態(如 unpaid / partial / paid)。

refundState
string

退款軸狀態。

totalTwd
number

應收總額(TWD 整數,訂單各應收明細加總)。

createdAt
Date

訂單建立時間。

bookerName
string

訂購人姓名。

bookerEmail
string

訂購人 email。

propertyId
string

住宿館 id(prop_ 前綴)。

propertyName
string

住宿館名稱。

roomTypeId
string

房型 id(rt_ 前綴)。

roomTypeName
string

房型名稱。

checkIn
string

入住日(ISO 'YYYY-MM-DD')。

checkOut
string

退房日(ISO 'YYYY-MM-DD')。

units
number

訂購房間數。

guestCount
number

入住總人數。

請求
curl -X GET https://your-tenant.example.com/api/v1/lodging/bookings/<orderId> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "orderId": "…",
    "orderNumber": "…",
    "status": "…",
    "bookingState": "…",
    "paymentState": "…",
    "refundState": "…",
    "totalTwd": 0,
    "createdAt": "2026-06-30T08:00:00.000Z",
    "bookerName": "…",
    "bookerEmail": "…",
    "propertyId": "…",
    "propertyName": "…",
    "roomTypeId": "…",
    "roomTypeName": "…",
    "checkIn": "…",
    "checkOut": "…",
    "units": 0,
    "guestCount": 0
  }
}

cancel a direct lodging

POST/api/v1/lodging/bookings/{orderId}/cancel
order.update

參數

orderId路徑
string· min 1

旅宿訂單 ID

回應欄位 · data

ok
boolean

操作成功旗標,恆為 true。

請求
curl -X POST https://your-tenant.example.com/api/v1/lodging/bookings/<orderId>/cancel \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

delete a gallery

DELETE/api/v1/lodging/images/{id}
lodging.manage模組:lodging

參數

id路徑
string· min 1

圖片 ID

kind必填
enum
propertyroom-type

圖片所屬相簿:property 旅宿相簿/room-type 房型相簿

回應欄位 · data

ok
boolean

操作成功旗標,恆為 true。

請求
curl -X DELETE "https://your-tenant.example.com/api/v1/lodging/images/<id>?kind=<kind>" \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

list tenant lodging properties

GET/api/v1/lodging/properties
lodging.read

回應欄位 · data[]

id
object

住宿館 id(prop_ 前綴)。

length
number

Returns the length of a String object.

slug
string

網址 slug(公開站路徑,租戶內唯一)。

name
string

住宿館名稱。

kind
string

類型:hotel 旅館 / camp 營地。

isOverseas
boolean

是否為海外住宿。

location
string | null

地點描述;null = 未設。

description
string | null

簡介文字;null = 未設。

contentMdx
string | null

內文(MDX 原始碼);null = 未設。

facilities
unknown

設施清單(JSON);null = 未設。

coverImageUrl
string | null

封面圖 URL;null = 未設。

usageHint
string

用途:direct 散客直訂 / package 梯次配套 / both 兩者皆可。

checkInTime
string | null

入住時間文字(如「15:00」);null = 未設。

checkOutTime
string | null

退房時間文字(如「11:00」);null = 未設。

checkInInfo
string | null

入住須知;null = 未設。

houseRules
string | null

館內規範;null = 未設。

cancellationPolicy
string | null

取消政策;null = 未設。

addressRegion
string | null

地址:縣市/區域;null = 未設。

addressLocality
string | null

地址:鄉鎮/地區;null = 未設。

streetAddress
string | null

街道地址;null = 未設。

postalCode
string | null

郵遞區號;null = 未設。

latitude
number | null

緯度;null = 未設。

longitude
number | null

經度;null = 未設。

phone
string | null

聯絡電話;null = 未設。

petsAllowed
boolean | null

是否允許攜帶寵物;null = 未設。

smokingAllowed
boolean | null

是否允許吸菸;null = 未設。

status
string

狀態:active 啟用 / inactive 停用。

seoTitle
string | null

SEO 標題覆寫;null = 沿用內容欄。

seoDescription
string | null

SEO 描述;null = 未設。

ogImageUrl
string | null

Open Graph 分享圖 URL;null = 未設。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/lodging/properties \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": {
        "length": 0
      },
      "slug": "…",
      "name": "…",
      "kind": "…",
      "isOverseas": true,
      "location": "…",
      "description": "…",
      "contentMdx": "…",
      "facilities": "…",
      "coverImageUrl": "…",
      "usageHint": "…",
      "checkInTime": "…",
      "checkOutTime": "…",
      "checkInInfo": "…",
      "houseRules": "…",
      "cancellationPolicy": "…",
      "addressRegion": "…",
      "addressLocality": "…",
      "streetAddress": "…",
      "postalCode": "…",
      "latitude": 0,
      "longitude": 0,
      "phone": "…",
      "petsAllowed": true,
      "smokingAllowed": true,
      "status": "…",
      "seoTitle": "…",
      "seoDescription": "…",
      "ogImageUrl": "…",
      "createdAt": "2026-06-30T08:00:00.000Z",
      "updatedAt": "2026-06-30T08:00:00.000Z"
    }
  ]
}

create a property

POST/api/v1/lodging/properties
lodging.manage模組:lodging

參數

slug必填
string· 格式限定

旅宿代稱(小寫英數與連字號,2-63 字,租戶內唯一,用於網址)

name必填
string· max 200 · min 1

旅宿名稱(對外顯示)

kind選填
enum
camphotel

旅宿類型:camp 營地/hotel 旅館,預設 hotel

isOverseas選填
boolean

是否為海外旅宿,預設否

location選填
string· max 200

所在地點概述(如縣市、區域)

description選填
string· max 2000

旅宿介紹文字

usageHint選填
enum
directpackageboth

銷售用途:direct 僅直接訂房/package 僅併入套裝行程/both 兩者皆可,預設 both

回應欄位 · data

id
string

新建立住宿館的 id(prop_ 前綴)。

請求
curl -X POST https://your-tenant.example.com/api/v1/lodging/properties \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "slug": "<slug>",
    "name": "<name>"
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…"
  }
}

single lodging property

GET/api/v1/lodging/properties/{id}
lodging.read

參數

id路徑
string· min 1

旅宿物件 ID

回應欄位 · data

id
object

住宿館 id(prop_ 前綴)。

length
number

Returns the length of a String object.

slug
string

網址 slug(公開站路徑,租戶內唯一)。

name
string

住宿館名稱。

kind
string

類型:hotel 旅館 / camp 營地。

isOverseas
boolean

是否為海外住宿。

location
string | null

地點描述;null = 未設。

description
string | null

簡介文字;null = 未設。

contentMdx
string | null

內文(MDX 原始碼);null = 未設。

facilities
unknown

設施清單(JSON);null = 未設。

coverImageUrl
string | null

封面圖 URL;null = 未設。

usageHint
string

用途:direct 散客直訂 / package 梯次配套 / both 兩者皆可。

checkInTime
string | null

入住時間文字(如「15:00」);null = 未設。

checkOutTime
string | null

退房時間文字(如「11:00」);null = 未設。

checkInInfo
string | null

入住須知;null = 未設。

houseRules
string | null

館內規範;null = 未設。

cancellationPolicy
string | null

取消政策;null = 未設。

addressRegion
string | null

地址:縣市/區域;null = 未設。

addressLocality
string | null

地址:鄉鎮/地區;null = 未設。

streetAddress
string | null

街道地址;null = 未設。

postalCode
string | null

郵遞區號;null = 未設。

latitude
number | null

緯度;null = 未設。

longitude
number | null

經度;null = 未設。

phone
string | null

聯絡電話;null = 未設。

petsAllowed
boolean | null

是否允許攜帶寵物;null = 未設。

smokingAllowed
boolean | null

是否允許吸菸;null = 未設。

status
string

狀態:active 啟用 / inactive 停用。

seoTitle
string | null

SEO 標題覆寫;null = 沿用內容欄。

seoDescription
string | null

SEO 描述;null = 未設。

ogImageUrl
string | null

Open Graph 分享圖 URL;null = 未設。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/lodging/properties/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "id": {
      "length": 0
    },
    "slug": "…",
    "name": "…",
    "kind": "…",
    "isOverseas": true,
    "location": "…",
    "description": "…",
    "contentMdx": "…",
    "facilities": "…",
    "coverImageUrl": "…",
    "usageHint": "…",
    "checkInTime": "…",
    "checkOutTime": "…",
    "checkInInfo": "…",
    "houseRules": "…",
    "cancellationPolicy": "…",
    "addressRegion": "…",
    "addressLocality": "…",
    "streetAddress": "…",
    "postalCode": "…",
    "latitude": 0,
    "longitude": 0,
    "phone": "…",
    "petsAllowed": true,
    "smokingAllowed": true,
    "status": "…",
    "seoTitle": "…",
    "seoDescription": "…",
    "ogImageUrl": "…",
    "createdAt": "2026-06-30T08:00:00.000Z",
    "updatedAt": "2026-06-30T08:00:00.000Z"
  }
}

update a property

PATCH/api/v1/lodging/properties/{id}
lodging.manage模組:lodging

參數

id路徑
string· min 1

旅宿物件 ID

name選填
string· max 200 · min 1

旅宿名稱(對外顯示)

location選填
string· max 200

所在地點概述(如縣市、區域)

description選填
string· max 2000

旅宿介紹文字

usageHint選填
enum
directpackageboth

銷售用途:direct 僅直接訂房/package 僅併入套裝行程/both 兩者皆可

checkInTime選填
string· max 10

入住時間(如 15:00)

checkOutTime選填
string· max 10

退房時間(如 11:00)

checkInInfo選填
string· max 2000

入住須知與報到說明

houseRules選填
string· max 2000

住宿規範

cancellationPolicy選填
string· max 2000

取消政策說明

addressRegion選填
string· max 50

地址行政區(縣市層級)

addressLocality選填
string· max 50

地址鄉鎮市區

streetAddress選填
string· max 200

街道地址

postalCode選填
string· max 10

郵遞區號

latitude選填
integer· max 90

緯度(-90 至 90)

longitude選填
integer· max 180

經度(-180 至 180)

phone選填
string· max 50

聯絡電話

petsAllowed選填
enum
allowdisallowunset

是否允許攜帶寵物:allow 允許/disallow 不允許/unset 清除設定,省略則不變更

smokingAllowed選填
enum
allowdisallowunset

是否允許吸菸:allow 允許/disallow 不允許/unset 清除設定,省略則不變更

facilities選填
array

設施代碼陣列(須為合法 amenity key;送空陣列代表清空)

seoTitle選填
string

SEO 標題(送空字串代表清空,退回預設)

seoDescription選填
string

SEO 描述(送空字串代表清空,退回預設)

ogImageUrl選填
string

社群分享圖 URL(須為 http/https,送空字串代表清空)

回應欄位 · data

ok
boolean

操作成功旗標,恆為 true。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/lodging/properties/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

archive

POST/api/v1/lodging/properties/{id}/archive
lodging.manage模組:lodging

參數

id路徑
string· min 1

旅宿物件 ID

回應欄位 · data

ok
boolean

操作成功旗標,恆為 true。

請求
curl -X POST https://your-tenant.example.com/api/v1/lodging/properties/<id>/archive \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

property gallery images.

GET/api/v1/lodging/properties/{id}/images
lodging.read模組:lodging

參數

id路徑
string· min 1

旅宿物件 ID

回應欄位 · data[]

id
string

圖片資源 id(pimg_ / rtimg_ 前綴)。

url
string

圖片公開 URL。

caption
string | null

圖說文字;null = 無。

displayOrder
number

相簿中的排序(由小到大)。

請求
curl -X GET https://your-tenant.example.com/api/v1/lodging/properties/<id>/images \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "url": "…",
      "caption": "…",
      "displayOrder": 0
    }
  ]
}

add a property gallery image

POST/api/v1/lodging/properties/{id}/images
lodging.manage模組:lodging

參數

id路徑
string· min 1

旅宿物件 ID

url必填
string· min 1

圖片網址

caption選填
string

圖片說明文字(可省略)

displayOrder選填
integer

在相簿中的排序序號,數字越小越前面,預設 0

回應欄位 · data

id
string

新建立住宿館圖片的 id(pimg_ 前綴)。

請求
curl -X POST https://your-tenant.example.com/api/v1/lodging/properties/<id>/images \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "<url>"
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…"
  }
}

room types for one property

GET/api/v1/lodging/properties/{id}/room-types
lodging.read

參數

id路徑
string· min 1

旅宿物件 ID

回應欄位 · data[]

id
object

房型 id(rt_ 前綴)。

length
number

Returns the length of a String object.

propertyId
object

所屬住宿館 id(prop_ 前綴)。

length
number

Returns the length of a String object.

name
string

房型名稱。

inventoryUnit
string

庫存單位:room 以房計 / bed 以床位計。

unitsTotal
number

總庫存量(房間數或床位數)。

capacityPerUnit
number

每單位可住人數。

basePriceTwd
number

底價(TWD 整數,每晚每單位;可被逐晚覆寫)。

description
string | null

房型描述;null = 未設。

facilities
unknown

設施清單(JSON);null = 未設。

bedConfig
unknown

床型配置(JSON);null = 未設。

floorSizeSqm
number | null

房間坪數(平方公尺);null = 未設。

status
string

狀態:active 啟用 / inactive 停用。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/lodging/properties/<id>/room-types \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": {
        "length": 0
      },
      "propertyId": {
        "length": 0
      },
      "name": "…",
      "inventoryUnit": "…",
      "unitsTotal": 0,
      "capacityPerUnit": 0,
      "basePriceTwd": 0,
      "description": "…",
      "facilities": "…",
      "bedConfig": "…",
      "floorSizeSqm": 0,
      "status": "…",
      "createdAt": "2026-06-30T08:00:00.000Z",
      "updatedAt": "2026-06-30T08:00:00.000Z"
    }
  ]
}

create a room type under this property

POST/api/v1/lodging/properties/{id}/room-types
lodging.manage模組:lodging

參數

id路徑
string· min 1

所屬旅宿物件 ID

name必填
string· max 200 · min 1

房型名稱(如標準雙人房)

inventoryUnit選填
enum
roombed

庫存單位:room 以房計/bed 以床位計,預設 room

unitsTotal必填
integer· max 10000 · min 1

此房型可售總單元數(房數或床位數)

capacityPerUnit選填
integer· max 100 · min 1

每單元可容納人數,預設 1

basePriceTwd必填
integer· max 10000000 · min 0

每晚每單元基準售價(新台幣)

description選填
string· max 2000

房型介紹文字

floorSizeSqm選填
integer

房間坪數(平方公尺)

bedType選填
string

床型代碼(須為合法 bed type,搭配 bedCount 才生效)

bedCount選填
integer

該床型數量(須大於 0 才生效)

facilities選填
array

房型設施代碼陣列(須為合法 amenity key)

回應欄位 · data

id
string

新建立房型的 id(rt_ 前綴)。

請求
curl -X POST https://your-tenant.example.com/api/v1/lodging/properties/<id>/room-types \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "<name>",
    "unitsTotal": 0,
    "basePriceTwd": 0
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…"
  }
}

single room type

GET/api/v1/lodging/room-types/{id}
lodging.read

參數

id路徑
string· min 1

房型 ID

回應欄位 · data

id
object

房型 id(rt_ 前綴)。

length
number

Returns the length of a String object.

propertyId
object

所屬住宿館 id(prop_ 前綴)。

length
number

Returns the length of a String object.

name
string

房型名稱。

inventoryUnit
string

庫存單位:room 以房計 / bed 以床位計。

unitsTotal
number

總庫存量(房間數或床位數)。

capacityPerUnit
number

每單位可住人數。

basePriceTwd
number

底價(TWD 整數,每晚每單位;可被逐晚覆寫)。

description
string | null

房型描述;null = 未設。

facilities
unknown

設施清單(JSON);null = 未設。

bedConfig
unknown

床型配置(JSON);null = 未設。

floorSizeSqm
number | null

房間坪數(平方公尺);null = 未設。

status
string

狀態:active 啟用 / inactive 停用。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/lodging/room-types/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "id": {
      "length": 0
    },
    "propertyId": {
      "length": 0
    },
    "name": "…",
    "inventoryUnit": "…",
    "unitsTotal": 0,
    "capacityPerUnit": 0,
    "basePriceTwd": 0,
    "description": "…",
    "facilities": "…",
    "bedConfig": "…",
    "floorSizeSqm": 0,
    "status": "…",
    "createdAt": "2026-06-30T08:00:00.000Z",
    "updatedAt": "2026-06-30T08:00:00.000Z"
  }
}

update a room type

PATCH/api/v1/lodging/room-types/{id}
lodging.manage模組:lodging

參數

id路徑
string· min 1

房型 ID

name選填
string· max 200 · min 1

房型名稱(如標準雙人房)

inventoryUnit選填
enum
roombed

庫存單位:room 以房計/bed 以床位計

unitsTotal選填
integer· max 10000 · min 1

此房型可售總單元數(房數或床位數)

capacityPerUnit選填
integer· max 100 · min 1

每單元可容納人數

basePriceTwd選填
integer· max 10000000 · min 0

每晚每單元基準售價(新台幣)

description選填
string· max 2000

房型介紹文字

floorSizeSqm選填
integer

房間坪數(平方公尺)

bedType選填
string

床型代碼(須為合法 bed type,搭配 bedCount 才生效)

bedCount選填
integer

該床型數量(須大於 0 才生效)

facilities選填
array

房型設施代碼陣列(須為合法 amenity key;送空陣列代表清空)

回應欄位 · data

ok
boolean

操作成功旗標,恆為 true。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/lodging/room-types/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

archive

POST/api/v1/lodging/room-types/{id}/archive
lodging.manage模組:lodging

參數

id路徑
string· min 1

房型 ID

回應欄位 · data

ok
boolean

操作成功旗標,恆為 true。

請求
curl -X POST https://your-tenant.example.com/api/v1/lodging/room-types/<id>/archive \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

per-night availability +

GET/api/v1/lodging/room-types/{id}/availability
lodging.read

參數

id路徑
string· min 1

房型 ID

checkIn必填
string· min 1

入住日(YYYY-MM-DD,含此晚)

checkOut必填
string· min 1

退房日(YYYY-MM-DD,不含此晚)

回應欄位 · data

available
number

整段住宿期間可訂房間數(各晚剩餘取最小;任一晚關閉則為 0)。

nights
number

住宿晚數。

totalPriceTwd
number

整段期間房價合計(TWD 整數,逐晚牌價加總)。

perNight
object[]

逐晚可售明細。

night
string

該晚日期(ISO 'YYYY-MM-DD')。

capacity
number

該晚可售容量(房間數;有覆寫則用覆寫值,否則房型總數)。

booked
number

該晚已訂數。

remaining
number

該晚剩餘可訂數(capacity − booked,不小於 0)。

priceTwd
number

該晚房價(TWD 整數;有逐晚覆寫則用覆寫值,否則房型底價)。

status
string

該晚販售狀態:open 開放 / closed 關閉。

請求
curl -X GET "https://your-tenant.example.com/api/v1/lodging/room-types/<id>/availability?checkIn=<checkIn>&checkOut=<checkOut>" \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "available": 0,
    "nights": 0,
    "totalPriceTwd": 0,
    "perNight": [
      {
        "night": "…",
        "capacity": 0,
        "booked": 0,
        "remaining": 0,
        "priceTwd": 0,
        "status": "…"
      }
    ]
  }
}

per-night

GET/api/v1/lodging/room-types/{id}/availability/breakdown
lodging.read

參數

id路徑
string· min 1

房型 ID

from必填
string· min 1

起始日(YYYY-MM-DD,含此晚)

to必填
string· min 1

結束日(YYYY-MM-DD,不含此晚)

回應欄位 · data[]

night
string

該晚日期(ISO 'YYYY-MM-DD')。

directBooked
number

該晚散客直訂的已訂數。

packageBooked
number

該晚梯次配套佔用的已訂數。

請求
curl -X GET "https://your-tenant.example.com/api/v1/lodging/room-types/<id>/availability/breakdown?from=<from>&to=<to>" \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "night": "…",
      "directBooked": 0,
      "packageBooked": 0
    }
  ]
}

room-type gallery images.

GET/api/v1/lodging/room-types/{id}/images
lodging.read模組:lodging

參數

id路徑
string· min 1

房型 ID

回應欄位 · data[]

id
string

圖片資源 id(pimg_ / rtimg_ 前綴)。

url
string

圖片公開 URL。

caption
string | null

圖說文字;null = 無。

displayOrder
number

相簿中的排序(由小到大)。

請求
curl -X GET https://your-tenant.example.com/api/v1/lodging/room-types/<id>/images \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "url": "…",
      "caption": "…",
      "displayOrder": 0
    }
  ]
}

add a room-type gallery image

POST/api/v1/lodging/room-types/{id}/images
lodging.manage模組:lodging

參數

id路徑
string· min 1

房型 ID

url必填
string· min 1

圖片網址

caption選填
string

圖片說明文字(可省略)

displayOrder選填
integer

在相簿中的排序序號,數字越小越前面,預設 0

回應欄位 · data

id
string

新建立房型圖片的 id(rtimg_ 前綴)。

請求
curl -X POST https://your-tenant.example.com/api/v1/lodging/room-types/<id>/images \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "<url>"
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…"
  }
}

batch-override the

POST/api/v1/lodging/room-types/{id}/nights/override
lodging.manage模組:lodging

參數

id路徑
string· min 1

房型 ID

from必填
string

套用起始日(YYYY-MM-DD,含此日)

to必填
string

套用結束日(YYYY-MM-DD,含此日;須不早於起始日)

priceTwd選填
integer· max 10000000 · min 0

覆寫的每晚售價(新台幣),省略則不調整價格

capacity選填
integer· max 10000 · min 1

覆寫的每晚可售單元數,若低於已訂數量會回 409 衝突

status選填
enum
openclosed

每晚開關房狀態:open 開放/closed 封房

回應欄位 · data

ok
boolean

操作成功旗標,恆為 true。

請求
curl -X POST https://your-tenant.example.com/api/v1/lodging/room-types/<id>/nights/override \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "<from>",
    "to": "<to>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

旅宿 dashboard overview

GET/api/v1/lodging/stats
lodging.read

回應欄位 · data

tonightCheckInUnits
number

今晚入住房間數(Asia/Taipei)。

tonightCheckInGuests
number

今晚入住總人數(Asia/Taipei)。

weekOccupancyPct
number

未來 7 晚住房率(已訂 / 可售,0–100)。

next7AvailableUnits
number

未來 7 晚仍可售的房晚數。

pendingPaymentCount
number

待收款訂單筆數。

pendingPaymentTwd
number

待收款金額合計(TWD 整數)。

請求
curl -X GET https://your-tenant.example.com/api/v1/lodging/stats \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "tonightCheckInUnits": 0,
    "tonightCheckInGuests": 0,
    "weekOccupancyPct": 0,
    "next7AvailableUnits": 0,
    "pendingPaymentCount": 0,
    "pendingPaymentTwd": 0
  }
}

/trips

GET/api/v1/trips
trip.read

參數

status選填
string

依行程狀態篩選(draft 草稿/published 上架/archived 封存)

q選填
string

自由文字搜尋(行程標題/代稱/目的地)

groupCode選填
string

依團號篩選,列出含該團號梯次的行程

回應欄位 · data[]

id
string

行程 id(trip_ 前綴)。

slug
string

行程網址 slug。

title
string

行程標題。

destination
string

目的地名稱。

durationDays
number

天數。

priceFromTwd
number

「NT$ X 起」起價(TWD 整數)。

status
TripStatus

上架狀態:draft 草稿 / published 已上架 / archived 封存。

updatedAt
Date

最後更新時間。

isClimbing
boolean

是否登山團(行程層模組旗標)。

isOverseas
boolean

是否海外團(行程層模組旗標)。

activeDepartureCount
number

Count of departures with status='selling'.

nextDepartureDate
string | null

Earliest selling departure_date, ISO date string, or null.

representativeGroupCode
string | null

代表團號(group-code §8.2):最新一筆有團號的梯次;無則 null(UI 顯示 —)。

請求
curl -X GET https://your-tenant.example.com/api/v1/trips \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "slug": "…",
      "title": "…",
      "destination": "…",
      "durationDays": 0,
      "priceFromTwd": 0,
      "status": "…",
      "updatedAt": "2026-06-30T08:00:00.000Z",
      "isClimbing": true,
      "isOverseas": true,
      "activeDepartureCount": 0,
      "nextDepartureDate": "…",
      "representativeGroupCode": "…"
    }
  ]
}

same core op + audit as the back office

POST/api/v1/trips
trip.manage

參數

slug必填
string· 格式限定

行程網址代稱(slug),用於前台路徑與後台識別,只能小寫英數與連字號

title必填
string· max 200 · min 1

行程標題,顯示於前台與訂單

summary選填
string· max 500

行程摘要,前台列表卡片用的一句話簡介

contentMdx選填
string· max 50000

行程詳細內容(MDX 格式),前台行程頁主文

destination必填
string· max 100 · min 1

目的地名稱

durationDays必填
integer· max 60 · min 1

行程天數

priceFromTwd必填
integer· max 10000000 · min 0

起價(新台幣),前台「OOO 元起」顯示用

directPriceTwd選填
integer

直客定價(新台幣),留空(null)則退回起價繼承

agencyPriceTwd選填
integer

同業定價(新台幣),留空(null)則退回直客/起價繼承

depositMode選填
enum
nonefixedpercent

訂金計算方式(none 不收/fixed 固定金額/percent 百分比)

depositAmountTwd選填
integer

訂金固定金額(新台幣),depositMode 為 fixed 時生效

depositPercent選填
integer

訂金百分比(1–100),depositMode 為 percent 時生效

balanceDueDaysBeforeDeparture選填
integer

尾款應繳截止日(出發前幾天)

feeInclusions選填
array· max 30

費用包含項目清單,每項含勾選狀態(ok)與說明文字(text)

isClimbing選填
boolean

是否為登山團(啟用登山相關模組欄位)

isOverseas選填
boolean

是否為海外團

gradeScore選填
integer· max 100 · min 0

登山難度評分(0–100),null 表示未評級

requiresAlpineExperience選填
boolean

是否需具備高山經驗

gradeLabel選填
string· max 50

難度等級標籤文字

confirmGroupMultiple選填
integer· max 1000 · min 1

成團人數倍數(如國內高山團為 7 的倍數),null 表示不限

restrictedQuotaEnabled選填
boolean

是否啟用每人使用次數限制

quotaPerPersonLimit選填
integer· max 1000 · min 1

每人於限制窗內可使用次數上限,null 表示不限

quotaWindow選填
string· max 50

次數限制的計算窗口

waitlistEnabled選填
boolean

是否開放候補

coverImageUrl選填
string· max 500

行程封面圖網址(http/https)

seoTitle選填
string· max 200

SEO 標題,覆寫前台頁面 title

seoDescription選填
string· max 500

SEO 描述,覆寫前台 meta description

ogImageUrl選填
string· max 500

Open Graph 社群分享圖網址(http/https)

status選填
enum

行程狀態(draft 草稿/published 上架/archived 封存)

pnlRegionId選填
string· max 60

損益分區 id(pnl_regions),null 表示未指派、退回系統派生

回應欄位 · data

id
string

新建立行程的 id(trip_ 前綴)。

請求
curl -X POST https://your-tenant.example.com/api/v1/trips \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "slug": "<slug>",
    "title": "<title>",
    "destination": "<destination>",
    "durationDays": 0,
    "priceFromTwd": 0
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…"
  }
}

full admin trip detail

GET/api/v1/trips/{id}
trip.read

參數

id路徑
string· min 1

行程 ID(路徑參數)

回應欄位 · data

id
object

行程 id(trip_ 前綴)。

length
number

Returns the length of a String object.

slug
string

行程網址 slug(公開站路徑)。

title
string

行程標題。

summary
string | null

一句話摘要;null = 未設。

contentMdx
string | null

行程內文(MDX 原始碼);null = 未設。

destination
string

目的地名稱。

durationDays
number

天數。

priceFromTwd
number

「NT$ X 起」起價(TWD 整數)。

coverImageUrl
string | null

封面圖 URL;null = 未設。

status
TripStatus

上架狀態:draft 草稿 / published 已上架 / archived 封存。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

isClimbing
boolean

是否登山團(行程層模組旗標)。

isOverseas
boolean

是否海外團(行程層模組旗標)。

gradeScore
number | null

難度評鑑分數(climbing-screening §3.1);null = 未評級。

requiresAlpineExperience
boolean

是否要求具備高山經驗(報名審核用)。

gradeLabel
string | null

難度標籤(如「B+」);null = 未設。

feeInclusions
{ ok: boolean; text: string; }[] | null

團費包含/不包含(前台費用區唯一來源);null = 未設。

seoTitle
string | null

SEO 標題覆寫;null = 沿用 title。

seoDescription
string | null

SEO 描述;null = 未設。

ogImageUrl
string | null

Open Graph 分享圖 URL;null = 未設。

images
object[]

行程相簿圖片(依 displayOrder 排序)。

id
string

圖片資源 id(timg_ 前綴)。

url
string

圖片公開 URL。

caption
string | null

圖說文字;null = 無。

displayOrder
number

在行程相簿中的排序(由小到大)。

departures
object[]

Active (selling, future) departures only on the public side; all on admin.

id
string

梯次 id(dep_ 前綴)。

tripId
string

所屬行程 id(trip_ 前綴)。

departureDate
string

出發日(ISO 'YYYY-MM-DD')。

returnDate
string

回程日(ISO 'YYYY-MM-DD')。

priceTwd
number

售價(TWD 整數,未稅牌價)。

capacity
number

名額上限(人數)。

bookedCount
number

已成團佔用名額(人數)。

status
DepartureStatus

梯次狀態:selling 販售中 / closed 關閉 / cancelled 取消 / completed 已結團。

notes
string | null

內部備註;null = 無。

allocationMode
"fcfs" | "lottery"

抽籤分配模式(lottery-integration §2.1):fcfs=先到先得 / lottery=抽籤制。

agencyPriceTwd選填
number | null | undefined

同業價(TWD 整數);admin-only,公開站不映射。

depositMode選填
DepositMode | null | undefined

訂金規則模式:none 免訂金 / fixed 定額 / percent 比例;admin-only。

depositAmountTwd選填
number | null | undefined

訂金定額(TWD 整數,depositMode=fixed 時適用);admin-only。

depositPercent選填
number | null | undefined

訂金比例(百分比,depositMode=percent 時適用);admin-only。

groupCode選填
string | null | undefined

團號(group-code §3.3);admin-only,公開站不映射。

regionCode選填
string | null | undefined

地區代碼(團號組成);admin-only。

airlineCode選填
string | null | undefined

航空公司代碼(團號組成);admin-only。

promoActive選填
boolean | undefined

梯次促銷是否啟用(trip-pricing);admin-only。

promoPriceTwd選填
number | null | undefined

促銷覆寫售價(TWD 整數);admin-only。

promoAgencyPriceTwd選填
number | null | undefined

促銷覆寫同業價(TWD 整數);admin-only。

請求
curl -X GET https://your-tenant.example.com/api/v1/trips/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "id": {
      "length": 0
    },
    "slug": "…",
    "title": "…",
    "summary": "…",
    "contentMdx": "…",
    "destination": "…",
    "durationDays": 0,
    "priceFromTwd": 0,
    "coverImageUrl": "…",
    "status": "…",
    "createdAt": "2026-06-30T08:00:00.000Z",
    "updatedAt": "2026-06-30T08:00:00.000Z",
    "isClimbing": true,
    "isOverseas": true,
    "gradeScore": 0,
    "requiresAlpineExperience": true,
    "gradeLabel": "…",
    "feeInclusions": "…",
    "seoTitle": "…",
    "seoDescription": "…",
    "ogImageUrl": "…",
    "images": [
      {
        "id": "…",
        "url": "…",
        "caption": "…",
        "displayOrder": 0
      }
    ],
    "departures": [
      {
        "id": "…",
        "tripId": "…",
        "departureDate": "…",
        "returnDate": "…",
        "priceTwd": 0,
        "capacity": 0,
        "bookedCount": 0,
        "status": "…",
        "notes": "…",
        "allocationMode": "fcfs",
        "agencyPriceTwd": 0,
        "depositMode": null,
        "depositAmountTwd": 0,
        "depositPercent": 0,
        "groupCode": "…",
        "regionCode": "…",
        "airlineCode": "…",
        "promoActive": true,
        "promoPriceTwd": 0,
        "promoAgencyPriceTwd": 0
      }
    ]
  }
}
PATCH/api/v1/trips/{id}
trip.manage

參數

id路徑
string· min 1

行程 ID(路徑參數)

slug必填
string· 格式限定

行程網址代稱(slug),用於前台路徑與後台識別,只能小寫英數與連字號

title必填
string· max 200 · min 1

行程標題,顯示於前台與訂單

summary選填
string· max 500

行程摘要,前台列表卡片用的一句話簡介

contentMdx選填
string· max 50000

行程詳細內容(MDX 格式),前台行程頁主文

destination必填
string· max 100 · min 1

目的地名稱

durationDays必填
integer· max 60 · min 1

行程天數

priceFromTwd必填
integer· max 10000000 · min 0

起價(新台幣),前台「OOO 元起」顯示用

directPriceTwd選填
integer

直客定價(新台幣),留空(null)則退回起價繼承

agencyPriceTwd選填
integer

同業定價(新台幣),留空(null)則退回直客/起價繼承

depositMode選填
enum
nonefixedpercent

訂金計算方式(none 不收/fixed 固定金額/percent 百分比)

depositAmountTwd選填
integer

訂金固定金額(新台幣),depositMode 為 fixed 時生效

depositPercent選填
integer

訂金百分比(1–100),depositMode 為 percent 時生效

balanceDueDaysBeforeDeparture選填
integer

尾款應繳截止日(出發前幾天)

feeInclusions選填
array· max 30

費用包含項目清單,每項含勾選狀態(ok)與說明文字(text)

isClimbing選填
boolean

是否為登山團(啟用登山相關模組欄位)

isOverseas選填
boolean

是否為海外團

gradeScore選填
integer· max 100 · min 0

登山難度評分(0–100),null 表示未評級

requiresAlpineExperience選填
boolean

是否需具備高山經驗

gradeLabel選填
string· max 50

難度等級標籤文字

confirmGroupMultiple選填
integer· max 1000 · min 1

成團人數倍數(如國內高山團為 7 的倍數),null 表示不限

restrictedQuotaEnabled選填
boolean

是否啟用每人使用次數限制

quotaPerPersonLimit選填
integer· max 1000 · min 1

每人於限制窗內可使用次數上限,null 表示不限

quotaWindow選填
string· max 50

次數限制的計算窗口

waitlistEnabled選填
boolean

是否開放候補

coverImageUrl選填
string· max 500

行程封面圖網址(http/https)

seoTitle選填
string· max 200

SEO 標題,覆寫前台頁面 title

seoDescription選填
string· max 500

SEO 描述,覆寫前台 meta description

ogImageUrl選填
string· max 500

Open Graph 社群分享圖網址(http/https)

status選填
enum

行程狀態(draft 草稿/published 上架/archived 封存)

pnlRegionId選填
string· max 60

損益分區 id(pnl_regions),null 表示未指派、退回系統派生

回應欄位 · data

ok
boolean

操作成功旗標,恆為 true。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/trips/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "slug": "<slug>",
    "title": "<title>",
    "destination": "<destination>",
    "durationDays": 0,
    "priceFromTwd": 0
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

bind / unbind a trip's cost templates

PUT/api/v1/trips/{id}/cost-template
cost_template.manage

參數

id路徑
string· min 1

行程 ID(路徑參數)

templateIds選填
array

要綁定的成本範本 ID 陣列(依序疊加);[] 或省略表示解除全部綁定

templateId選填
string· min 1

(向後相容,單一)要綁定的成本範本 ID;null 表示解綁

回應欄位 · data

ok
boolean

操作成功旗標,恆為 true。

請求
curl -X PUT https://your-tenant.example.com/api/v1/trips/<id>/cost-template \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

add a departure to a trip

POST/api/v1/trips/{id}/departures
trip.manage

參數

id路徑
string· min 1

行程 ID(路徑參數),新梯次所屬的行程

departureDate必填
string

出發日期(YYYY-MM-DD)

returnDate必填
string

回程日期(YYYY-MM-DD),須晚於出發日

priceTwd必填
integer· max 10000000 · min 0

梯次直客售價(新台幣)

capacity必填
integer· max 200 · min 1

梯次總名額(座位上限)

agencyPriceTwd選填
integer· max 10000000 · min 0

梯次同業售價(新台幣)

depositMode選填
enum
nonefixedpercent

訂金計算方式(none 不收/fixed 固定金額/percent 百分比)

depositAmountTwd選填
integer· max 10000000 · min 0

訂金固定金額(新台幣),depositMode 為 fixed 時生效

depositPercent選填
integer· max 100 · min 1

訂金百分比(1–100),depositMode 為 percent 時生效

status選填
enum

梯次狀態(selling 銷售中/closed 關閉/cancelled 取消/completed 完成)

regionCode選填
string· 格式限定

團號地區來源碼(2–3 碼大寫英數),用於產生團號,可不指定

airlineCode選填
string· 格式限定

團號航空來源碼(2–3 碼大寫英數),用於產生團號,可不指定

回應欄位 · data

id
string

新建立梯次的 id(dep_ 前綴)。

請求
curl -X POST https://your-tenant.example.com/api/v1/trips/<id>/departures \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "departureDate": "<departureDate>",
    "returnDate": "<returnDate>",
    "priceTwd": 0,
    "capacity": 0
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…"
  }
}

為某梯次預留自家旅宿配套

POST/api/v1/trips/{id}/departures/{depId}/lodging
trip.manage模組:lodging

參數

id路徑
string· min 1

行程 ID(路徑參數),梯次所屬的行程

depId路徑
string· min 1

梯次 ID(路徑參數),要預留旅宿的梯次

propertyId必填
string· min 1

自家旅宿物件 ID

roomTypeId必填
string· min 1

該旅宿的房型 ID

checkIn必填
string· 格式限定

入住日(YYYY-MM-DD)

checkOut必填
string· 格式限定

退房日(YYYY-MM-DD),須晚於入住日

blockUnits必填
integer

整塊預留的房間間數

回應欄位 · data

ok
boolean

操作成功旗標,恆為 true。

請求
curl -X POST https://your-tenant.example.com/api/v1/trips/<id>/departures/<depId>/lodging \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "propertyId": "<propertyId>",
    "roomTypeId": "<roomTypeId>",
    "checkIn": "<checkIn>",
    "checkOut": "<checkOut>",
    "blockUnits": 0
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

釋回某梯次的自家旅宿配套預留

DELETE/api/v1/trips/{id}/lodging/{dlId}
trip.manage模組:lodging

參數

id路徑
string· min 1

行程 ID(路徑參數),預留所屬的行程

dlId路徑
string· min 1

梯次旅宿配套預留 ID(路徑參數),要釋回的預留

回應欄位 · data

ok
boolean

操作成功旗標,恆為 true。

請求
curl -X DELETE https://your-tenant.example.com/api/v1/trips/<id>/lodging/<dlId> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

active cost templates for

GET/api/v1/trips/cost-templates
cost_template.read

參數

status選填
string

成本範本狀態篩選;目前僅回傳啟用中(active)範本

回應欄位 · data[]

id
string

成本範本 id(ct_ 前綴)。

name
string

成本範本名稱。

請求
curl -X GET https://your-tenant.example.com/api/v1/trips/cost-templates \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "name": "…"
    }
  ]
}

group-code lookup over HTTP.

GET/api/v1/trips/departures
trip.read

參數

groupCode選填
string· min 1

完整團號,精確比對單一梯次

groupCodePrefix選填
string· min 1

團號前綴,前綴比對列出多個梯次

請求
curl -X GET https://your-tenant.example.com/api/v1/trips/departures \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": "…"
}

per-row pricing / deposit /

PATCH/api/v1/trips/departures/{departureId}
trip.manage

參數

departureId路徑
string· min 1

梯次 ID(路徑參數)

priceTwd必填
integer· max 10000000 · min 0

梯次直客售價(新台幣)

agencyPriceTwd選填
integer· max 10000000 · min 0

梯次同業售價(新台幣),留空則退回常規定價鏈

depositMode選填
enum
nonefixedpercent

訂金計算方式(none 不收/fixed 固定金額/percent 百分比)

depositAmountTwd選填
integer· max 10000000 · min 0

訂金固定金額(新台幣),depositMode 為 fixed 時生效

depositPercent選填
integer· max 100 · min 1

訂金百分比(1–100),depositMode 為 percent 時生效

promoActive選填
boolean

是否啟用梯次促銷覆寫價

promoPriceTwd選填
integer· max 10000000 · min 1

直客促銷價(新台幣),啟用促銷時必填,null 表示清空

promoAgencyPriceTwd選填
integer· max 10000000 · min 1

同業促銷價(新台幣),null 表示同業退回常規鏈

回應欄位 · data

ok
boolean

操作成功旗標,恆為 true。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/trips/departures/<departureId> \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "priceTwd": 0
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

manual group-code

POST/api/v1/trips/departures/{departureId}/group-code
departure.update

參數

departureId路徑
string· min 1

要覆寫團號的梯次 ID

groupCode必填
string

完整團號,格式為 YY+地區+航空+MMDD+序號(如 26EGTK1010A,自動轉大寫)

回應欄位 · data

ok
boolean

操作成功旗標,恆為 true。

groupCode
string

設定後的團號。

請求
curl -X POST https://your-tenant.example.com/api/v1/trips/departures/<departureId>/group-code \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "groupCode": "<groupCode>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "groupCode": "…"
  }
}

auto

POST/api/v1/trips/departures/{departureId}/group-code/generate
departure.update

參數

departureId路徑
string· min 1

要產生團號的梯次 ID

regionCode必填
string

地區碼,2–3 碼大寫英數(自動轉大寫)

airlineCode選填
string

航空碼(選填),2–3 碼大寫英數;國內團留空省略航空段

departureDate必填
string

出發日期(ISO 格式 YYYY-MM-DD,取 MMDD 組成團號)

回應欄位 · data

groupCode
string

自動產生的團號。

請求
curl -X POST https://your-tenant.example.com/api/v1/trips/departures/<departureId>/group-code/generate \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "regionCode": "<regionCode>",
    "departureDate": "<departureDate>"
  }'
回應
{
  "ok": true,
  "data": {
    "groupCode": "…"
  }
}

change a departure's

POST/api/v1/trips/departures/{departureId}/status
trip.manage

參數

departureId路徑
string· min 1

梯次 ID(路徑參數)

status必填
enum

目標梯次狀態(selling 銷售中/closed 關閉/cancelled 取消/completed 完成)

回應欄位 · data

ok
boolean

操作成功旗標,恆為 true。

請求
curl -X POST https://your-tenant.example.com/api/v1/trips/departures/<departureId>/status \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "<status>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

匯出行程

GET/api/v1/trips/export
trip.read

參數

status選填
string

依行程狀態篩選(draft 草稿/published 上架/archived 封存)

q選填
string

自由文字搜尋(行程標題/代稱/目的地)

groupCode選填
string

依團號篩選,匯出含該團號梯次的行程

回應欄位 · data

rows
object[]

匯出的行程列(套用相同 filter,無分頁)。

id
string

行程 id(trip_ 前綴)。

slug
string

行程網址 slug。

title
string

行程標題。

destination
string

目的地名稱。

durationDays
number

天數。

priceFromTwd
number

「NT$ X 起」起價(TWD 整數)。

status
TripStatus

上架狀態:draft 草稿 / published 已上架 / archived 封存。

updatedAt
Date

最後更新時間。

isClimbing
boolean

是否登山團(行程層模組旗標)。

isOverseas
boolean

是否海外團(行程層模組旗標)。

activeDepartureCount
number

Count of departures with status='selling'.

nextDepartureDate
string | null

Earliest selling departure_date, ISO date string, or null.

representativeGroupCode
string | null

代表團號(group-code §8.2):最新一筆有團號的梯次;無則 null(UI 顯示 —)。

total
number

匯出總筆數。

truncated
boolean

是否因上限被截斷(此端點回全列,恆為 false)。

請求
curl -X GET https://your-tenant.example.com/api/v1/trips/export \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "rows": [
      {
        "id": "…",
        "slug": "…",
        "title": "…",
        "destination": "…",
        "durationDays": 0,
        "priceFromTwd": 0,
        "status": "…",
        "updatedAt": "2026-06-30T08:00:00.000Z",
        "isClimbing": true,
        "isOverseas": true,
        "activeDepartureCount": 0,
        "nextDepartureDate": "…",
        "representativeGroupCode": "…"
      }
    ],
    "total": 0,
    "truncated": true
  }
}

行程批次匯入 commit:上傳檔

POST/api/v1/trips/import
trip.manage

參數

filename必填
string· min 1

上傳檔名,副檔名須為 .xlsx 或 .csv

contentBase64必填
string· min 1

檔案內容的 base64 編碼字串(上限 5 MB)

回應欄位 · data

filename
string

已匯入的檔名。

result
object

匯入結果(建檔筆數與逐列結果)。

importBatchId
string

本次匯入批次 id(imp_ 前綴),供稽核追溯。

createdTripCount
number

新建行程數。

createdDepartureCount
number

新建梯次數。

skippedCount
number

略過列數(重複/無需匯入)。

errorCount
number

失敗列數。

results
object[]

逐列匯入結果。

請求
curl -X POST https://your-tenant.example.com/api/v1/trips/import \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "filename": "<filename>",
    "contentBase64": "<contentBase64>"
  }'
回應
{
  "ok": true,
  "data": {
    "filename": "…",
    "result": {
      "importBatchId": "…",
      "createdTripCount": 0,
      "createdDepartureCount": 0,
      "skippedCount": 0,
      "errorCount": 0,
      "results": []
    }
  }
}

行程批次匯入 dry-run:上傳檔

POST/api/v1/trips/import/validate
trip.manage

參數

filename必填
string· min 1

上傳檔名,副檔名須為 .xlsx 或 .csv

contentBase64必填
string· min 1

檔案內容的 base64 編碼字串(上限 5 MB)

回應欄位 · data

filename
string

已驗證的檔名。

result
object

試算(dry-run)結果(逐列預覽 + 彙總,不寫入)。

rows
object[]

逐列預覽結果。

summary
object

各狀態列數彙總。

fileError
string | null

整檔層級的致命錯誤(如超列上限、空檔、無法解析),非空時 rows 為空。

請求
curl -X POST https://your-tenant.example.com/api/v1/trips/import/validate \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "filename": "<filename>",
    "contentBase64": "<contentBase64>"
  }'
回應
{
  "ok": true,
  "data": {
    "filename": "…",
    "result": {
      "rows": [],
      "summary": "…",
      "fileError": "…"
    }
  }
}

/agencies

同業

GET/api/v1/agencies
agency.read

參數

status選填
enum
activearchived

同業狀態篩選(active 啟用中/archived 已封存;省略為全部)

owner選填
string

負責業務篩選(傳明確使用者 ID;none=只列尚未指派負責業務者;all 或省略=全部)

hasTaxId選填
enum
yesno

是否有統一編號篩選(yes 僅列有統編者/no 僅列無統編者)

回應欄位 · data[]

id
string

同業 id(前綴 `agc_`)。

name
string

同業公司名 / 個人團主名稱。

taxId
string | null

統一編號(個人團主可留空)。

contactName
string | null

主要聯絡人姓名(未填 → null)。

phone
string | null

聯絡電話(未填 → null)。

email
string | null

聯絡 Email(未填 → null)。

address
string | null

公司地址(未填 → null)。

paymentTerm
string | null

帳期 / 結算方式(自由文字,例:'月結 30 天')。

ownerUserId
string | null

負責業務 user id(NULL = 未指派)。

ownerName
string | null

負責業務顯示名;未指派為 null。

status
"active" | "archived"

同業狀態:active 啟用中 / archived 已封存。

note
string | null

內部備註(未填 → null)。

orderCount
number

累計訂單數(COUNT orders WHERE agency_id = id)。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/agencies \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "name": "…",
      "taxId": "…",
      "contactName": "…",
      "phone": "…",
      "email": "…",
      "address": "…",
      "paymentTerm": "…",
      "ownerUserId": "…",
      "ownerName": "…",
      "status": "active",
      "note": "…",
      "orderCount": 0,
      "createdAt": "2026-06-30T08:00:00.000Z",
      "updatedAt": "2026-06-30T08:00:00.000Z"
    }
  ]
}
POST/api/v1/agencies
agency.manage

參數

name必填
string· max 200 · min 1

同業公司名稱(B2B 旅行社或個人團主名稱)

taxId選填
string

統一編號(選填)

contactName選填
string

主要聯絡人姓名(選填)

phone選填
string

聯絡電話(選填)

email選填
value

聯絡 Email(選填;留空字串視為未填)

address選填
string

公司地址(選填)

paymentTerm選填
string

付款條件/帳期約定(選填,如月結 30 天)

ownerUserId選填
string· max 128

指派的負責業務使用者 ID(選填)

status選填
enum

同業狀態(active 啟用中/archived 已封存;預設 active)

note選填
string

內部備註(選填)

回應欄位 · data

id
string

新建立同業的 ID(agc_ 前綴)。

請求
curl -X POST https://your-tenant.example.com/api/v1/agencies \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "<name>"
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…"
  }
}

單一同業完整資料

GET/api/v1/agencies/{id}
agency.read

參數

id路徑
string· min 1

同業 ID

回應欄位 · data

id
string

同業 id(前綴 `agc_`)。

name
string

同業公司名 / 個人團主名稱。

taxId
string | null

統一編號(個人團主可留空)。

contactName
string | null

主要聯絡人姓名(未填 → null)。

phone
string | null

聯絡電話(未填 → null)。

email
string | null

聯絡 Email(未填 → null)。

address
string | null

公司地址(未填 → null)。

paymentTerm
string | null

帳期 / 結算方式(自由文字,例:'月結 30 天')。

ownerUserId
string | null

負責業務 user id(NULL = 未指派)。

ownerName
string | null

負責業務顯示名;未指派為 null。

status
"active" | "archived"

同業狀態:active 啟用中 / archived 已封存。

note
string | null

內部備註(未填 → null)。

orderCount
number

累計訂單數(COUNT orders WHERE agency_id = id)。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/agencies/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "id": "…",
    "name": "…",
    "taxId": "…",
    "contactName": "…",
    "phone": "…",
    "email": "…",
    "address": "…",
    "paymentTerm": "…",
    "ownerUserId": "…",
    "ownerName": "…",
    "status": "active",
    "note": "…",
    "orderCount": 0,
    "createdAt": "2026-06-30T08:00:00.000Z",
    "updatedAt": "2026-06-30T08:00:00.000Z"
  }
}
PATCH/api/v1/agencies/{id}
agency.manage

參數

id路徑
string· min 1

要更新的同業 ID

name選填
string· max 200 · min 1

同業公司名稱(省略則不更動)

taxId選填
string

統一編號(省略則不更動)

contactName選填
string

主要聯絡人姓名(省略則不更動)

phone選填
string

聯絡電話(省略則不更動)

email選填
value

聯絡 Email(省略則不更動;空字串視為清空)

address選填
string

公司地址(省略則不更動)

paymentTerm選填
string

付款條件/帳期約定(省略則不更動)

ownerUserId選填
string· max 128

指派的負責業務使用者 ID(省略則不更動)

status選填
enum

同業狀態(active 啟用中/archived 已封存;省略則不更動)

note選填
string

內部備註(省略則不更動)

回應欄位 · data

ok
boolean

固定為 true:同業資料已更新。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/agencies/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

上下架同業

POST/api/v1/agencies/{id}/status
agency.manage

參數

id路徑
string· min 1

同業 ID

status必填
enum

目標狀態(active 上架啟用/archived 下架封存)

回應欄位 · data

ok
boolean

固定為 true:同業啟用/停用狀態已更新。

請求
curl -X POST https://your-tenant.example.com/api/v1/agencies/<id>/status \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "<status>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

負責業務指派候選清單

GET/api/v1/agencies/assignable-staff
agency.read

回應欄位 · data[]

userId
string

員工使用者 id(可作為負責業務指派的 ownerUserId)。

name
string

員工顯示名。

role
string

角色代碼(admin / sales / op / accountant)。

請求
curl -X GET https://your-tenant.example.com/api/v1/agencies/assignable-staff \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "userId": "…",
      "name": "…",
      "role": "…"
    }
  ]
}

同業名單匯出

GET/api/v1/agencies/export
agency.read

參數

status選填
enum
activearchived

同業狀態篩選(active 啟用中/archived 已封存;省略為全部)

owner選填
string

負責業務篩選(傳明確使用者 ID;none=只列尚未指派負責業務者;all 或省略=全部)

hasTaxId選填
enum
yesno

是否有統一編號篩選(yes 僅列有統編者/no 僅列無統編者)

回應欄位 · data

rows
object[]

同業匯出資料列(依 owner 篩選後的全表快照,供試算表匯出)。

id
string

同業 id(前綴 `agc_`)。

name
string

同業公司名 / 個人團主名稱。

taxId
string | null

統一編號(個人團主可留空)。

contactName
string | null

主要聯絡人姓名(未填 → null)。

phone
string | null

聯絡電話(未填 → null)。

email
string | null

聯絡 Email(未填 → null)。

address
string | null

公司地址(未填 → null)。

paymentTerm
string | null

帳期 / 結算方式(自由文字,例:'月結 30 天')。

ownerUserId
string | null

負責業務 user id(NULL = 未指派)。

ownerName
string | null

負責業務顯示名;未指派為 null。

status
"active" | "archived"

同業狀態:active 啟用中 / archived 已封存。

note
string | null

內部備註(未填 → null)。

orderCount
number

累計訂單數(COUNT orders WHERE agency_id = id)。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/agencies/export \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "rows": [
      {
        "id": "…",
        "name": "…",
        "taxId": "…",
        "contactName": "…",
        "phone": "…",
        "email": "…",
        "address": "…",
        "paymentTerm": "…",
        "ownerUserId": "…",
        "ownerName": "…",
        "status": "active",
        "note": "…",
        "orderCount": 0,
        "createdAt": "2026-06-30T08:00:00.000Z",
        "updatedAt": "2026-06-30T08:00:00.000Z"
      }
    ]
  }
}

/members

list/search the tenant customer

GET/api/v1/members
member.read

參數

q選填
string

關鍵字,模糊比對會員姓名、Email 或電話

county選填
string

縣市篩選,僅回傳通訊地址在該縣市的會員

year選填
string· 格式限定

加入年份(西元四位數),僅回傳該年註冊的會員

page選填
integer

分頁頁碼,從 1 起算,預設第 1 頁

pageSize選填
integer· max 200

每頁筆數,上限 200,預設由後端決定

回應欄位 · data

rows
object[]

當前頁的會員列。

userId
string

會員(顧客)的 user id。

email
string

會員 Email(登入帳號)。

name
string

會員姓名。

createdAt
Date

會員註冊時間。

phone
string | null

聯絡電話(未填 → null)。

address
string | null

通訊地址(未填 → null)。

birthDate
string | null

生日 YYYY-MM-DD(未填 → null)。

orderCount
number

累計訂單數(含所有狀態與 kind)。

paidOrderCount
number

已付清 / 已完成的訂單數(payment_state in paid/overpaid 或 booking_state=completed)。

totalSpent
number

累計消費(上述已付清訂單的應收總額,TWD 整數)。

lastOrderAt
Date | null

最後一筆訂單建立時間(無訂單 → null)。

pdpaSignedAt
Date | null

最新版 PDPA 同意書簽署時間(未簽 → null)。

anonymizedAt
Date | null

PDPA 匿名化時間;非空 = 已匿名化。

total
number

符合篩選的會員總數。

page
number

當前頁碼(從 1 起算)。

pageSize
number

每頁筆數。

請求
curl -X GET https://your-tenant.example.com/api/v1/members \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "rows": [
      {
        "userId": "…",
        "email": "…",
        "name": "…",
        "createdAt": "2026-06-30T08:00:00.000Z",
        "phone": "…",
        "address": "…",
        "birthDate": "…",
        "orderCount": 0,
        "paidOrderCount": 0,
        "totalSpent": 0,
        "lastOrderAt": null,
        "pdpaSignedAt": null,
        "anonymizedAt": null
      }
    ],
    "total": 0,
    "page": 0,
    "pageSize": 0
  }
}

full member detail

GET/api/v1/members/{id}
member.read

參數

id路徑
string· min 1

會員(顧客)的使用者 ID

回應欄位 · data

profile
object

會員基本資料 + 訂單彙整。

userId
string

會員(顧客)的 user id。

email
string

會員 Email(登入帳號)。

name
string

會員姓名。

createdAt
Date

會員註冊時間。

phone
string | null

聯絡電話(未填 → null)。

address
string | null

通訊地址(未填 → null)。

birthDate
string | null

生日 YYYY-MM-DD(未填 → null)。

orderCount
number

累計訂單數(含所有狀態與 kind)。

paidOrderCount
number

已付清 / 已完成的訂單數(payment_state in paid/overpaid 或 booking_state=completed)。

totalSpent
number

累計消費(上述已付清訂單的應收總額,TWD 整數)。

lastOrderAt
Date | null

最後一筆訂單建立時間(無訂單 → null)。

pdpaSignedAt
Date | null

最新版 PDPA 同意書簽署時間(未簽 → null)。

anonymizedAt
Date | null

PDPA 匿名化時間;非空 = 已匿名化。

orders
object[]

近期訂單列表(上限 50 筆,含 lodging)。

id
string

訂單 id。

orderNumber
string

人類可讀訂單編號。

status
string

金流模型 v2:deriveOrderDisplayStatus(booking/payment/refund) 派生的單一顯示狀態。

total
number

該會員所有訂單的應收總額(TWD 整數)。

createdAt
Date

訂單建立時間。

tripTitle
string

行程 / 產品標題。

consents
object[]

已簽署的同意書紀錄(上限 50 筆)。

id
string

簽署紀錄 id。

kind
string

同意書類型(pdpa / tour_agreement / cancellation_policy / refund_policy)。

version
number

簽署當下的範本版本號。

signedAt
Date

簽署時間。

ipAddress
string | null

簽署時來源 IP(未記錄 → null)。

請求
curl -X GET https://your-tenant.example.com/api/v1/members/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "profile": {
      "userId": "…",
      "email": "…",
      "name": "…",
      "createdAt": "2026-06-30T08:00:00.000Z",
      "phone": "…",
      "address": "…",
      "birthDate": "…",
      "orderCount": 0,
      "paidOrderCount": 0,
      "totalSpent": 0,
      "lastOrderAt": null,
      "pdpaSignedAt": null,
      "anonymizedAt": null
    },
    "orders": [
      {
        "id": "…",
        "orderNumber": "…",
        "status": "…",
        "total": 0,
        "createdAt": "2026-06-30T08:00:00.000Z",
        "tripTitle": "…"
      }
    ],
    "consents": [
      {
        "id": "…",
        "kind": "…",
        "version": 0,
        "signedAt": "2026-06-30T08:00:00.000Z",
        "ipAddress": "…"
      }
    ]
  }
}

irreversible PDPA anonymization of one

POST/api/v1/members/{id}/anonymize
member.update

參數

id路徑
string· min 1

欲匿名化的會員(顧客)使用者 ID

reason選填
string

匿名化原因,記入稽核紀錄備查

回應欄位 · data

ok
boolean

固定為 true:會員個資已匿名化(PDPA 刪除權)。

請求
curl -X POST https://your-tenant.example.com/api/v1/members/<id>/anonymize \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

given a batch of member

GET/api/v1/members/expiry-warnings
member.read

參數

ids必填
string

以逗號分隔的會員使用者 ID 批次,上限 200 個,回傳其中護照即將到期者

回應欄位 · data

userIds
string[]

證件即將到期(或已過期)需提醒的會員 user id 清單。

請求
curl -X GET "https://your-tenant.example.com/api/v1/members/expiry-warnings?ids=<ids>" \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "userIds": [
      "…"
    ]
  }
}

member directory KPI cards

GET/api/v1/members/stats
member.read

回應欄位 · data

totalMembers
number

會員(顧客)總數(排除員工帳號)。

newThisMonth
number

本月新註冊會員數。

withOrders
number

有下過訂單的會員數。

averageOrders
number

平均訂單數(只計有訂單者,避免零訂單稀釋)。

請求
curl -X GET https://your-tenant.example.com/api/v1/members/stats \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "totalMembers": 0,
    "newThisMonth": 0,
    "withOrders": 0,
    "averageOrders": 0
  }
}

/orders

list/search/filter orders

GET/api/v1/orders
order.read

參數

status選填
string

依訂單顯示狀態篩選(如 pending、paid、cancelled)

assignment選填
string

依派發狀態篩選(如 unassigned、assigned)

rooming選填
string

依分房狀態篩選

dateFrom選填
string

出發日期區間起(格式 YYYY-MM-DD,含當日)

dateTo選填
string

出發日期區間迄(格式 YYYY-MM-DD,含當日)

q選填
string

關鍵字搜尋(訂單編號、訂購人姓名或 Email 等)

agencyId選填
string

依合作旅行社 ID 篩選(同業單)

page選填
integer

頁碼,從 1 起算,預設第 1 頁

pageSize選填
integer· max 200

每頁筆數,上限 200

回應欄位 · data

rows
object[]

當前頁的訂單列(tour-centric,每筆 tour line 一列)。

id
string

訂單 id(前綴 `ord_`)。

orderNumber
string

人類可讀訂單編號(每租戶 sequence 產生,如 `20260707-0001`)。

bookingState
string

預訂狀態(真相軸):pending_payment → confirmed → completed;cancelled 為終態。

paymentState
string

付款狀態(派生自分類帳、快取於此供過濾):unpaid / partially_paid / deposit_paid / paid / overpaid。paid 只代表「應收被現金覆蓋」,不代表錢未退。

refundState
string

退款狀態(派生快取,只算會影響應收的已付退款):none / partially_refunded / refunded。

grossReceivableTwd
number

應收(TWD 整數,派生自應收分類帳)。

collectedTwd
number

收到現金(TWD 整數,派生)。

customerCashAppliedTwd
number

客戶現金淨套用(收款減已退現金,TWD 整數,派生)。

outstandingTwd
number

未收(應收減客戶現金淨套用,TWD 整數,派生)。

partySize
number

參團人數(tour 訂單)。

createdAt
Date

訂單建立時間。

notes
string | null

訂單備註(未填 → null)。

userId
string

下單客戶的 user id(同庫 user 表)。

userName
string

下單客戶顯示名。

userEmail
string

下單客戶 Email。

primaryTravelerName
string | null

主要旅客姓名(is_primary,未登記 → null)。

primaryTravelerPhone
string | null

主要旅客電話(未登記 → null)。

tripId
string

行程 id(tour 訂單經梯次反查;lodging 為空字串)。

tripTitle
string

行程 / 產品標題。

tripSlug
string

行程 slug。

departureId
string

梯次 id(tour 訂單;lodging 為空字串)。

departureDate
string

出發日 YYYY-MM-DD(lodging 為入住日)。

returnDate
string

回程日 YYYY-MM-DD(lodging 為退房日)。

assignedToUserId
string | null

派發給哪位業務的 user id(未派發 → null)。

assigneeName
string | null

承辦業務顯示名(未派發 / 查無 → null)。

assignmentStatus
string

派發狀態:unassigned / assigned / reassigned / pending_review。

assignedAt
Date | null

最近一次派發時間(未派發 → null)。

assignedByUserId
string | null

執行派發者的 user id(未派發 → null)。

createdByUserId
string | null

S5: who created the order. null / equal to `userId` = customer self-service (自助下單); a staff id ≠ userId = 業務代訂 / K單. Distinct from assignment — a self-service order can still be assigned to a sales rep.

pendingConsent
boolean

是否尚缺最新版 PDPA 同意書簽署(true = 待客戶重簽)。

roomingStatus
RoomingStatus

分房狀態:由訂單旅客的分房偏好與已分配房間派生。 'unregistered' | 'registered' | 'needs_single' | 'assigned'。

lotteryState
string | null

抽籤狀態(null = FCFS 非抽籤)。'applied'|'won'|'lost'。

failoverFromOrderId
string | null

備案單反查主單用:備案單的 failover_from_order_id 指向主單 id。

isOverdue
boolean

逾期旗標:存在 status='open' 且 due_at 已過的收款計畫(未收齊的到期款)。 供列表列以 `bg-destructive/5` 標紅提示。由 OVERDUE_SUBSELECT 一次算回。

total
number

符合篩選的訂單總數(DISTINCT 訂單,非列數)。

page
number

當前頁碼(從 1 起算)。

pageSize
number

每頁筆數。

請求
curl -X GET https://your-tenant.example.com/api/v1/orders \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "rows": [
      {
        "id": "…",
        "orderNumber": "…",
        "bookingState": "…",
        "paymentState": "…",
        "refundState": "…",
        "grossReceivableTwd": 0,
        "collectedTwd": 0,
        "customerCashAppliedTwd": 0,
        "outstandingTwd": 0,
        "partySize": 0,
        "createdAt": "2026-06-30T08:00:00.000Z",
        "notes": "…",
        "userId": "…",
        "userName": "…",
        "userEmail": "…",
        "primaryTravelerName": "…",
        "primaryTravelerPhone": "…",
        "tripId": "…",
        "tripTitle": "…",
        "tripSlug": "…",
        "departureId": "…",
        "departureDate": "…",
        "returnDate": "…",
        "assignedToUserId": "…",
        "assigneeName": "…",
        "assignmentStatus": "…",
        "assignedAt": null,
        "assignedByUserId": "…",
        "createdByUserId": "…",
        "pendingConsent": true,
        "roomingStatus": "…",
        "lotteryState": "…",
        "failoverFromOrderId": "…",
        "isOverdue": true
      }
    ],
    "total": 0,
    "page": 0,
    "pageSize": 0
  }
}
POST/api/v1/orders
order.create

參數

tripId必填
string· min 1

行程 ID

departureId必填
string· min 1

梯次 ID,決定佔位的出發團

primaryEmail必填
string· min 1

訂購人 Email,須對應已註冊會員

partySize必填
integer

報名人數,決定佔位數,須為 1 至 20 之間整數

travelers必填
array

旅客名單,筆數須與報名人數一致

paymentMethod必填
enum
cashatmmanual

收款方式:cash 現金、atm 轉帳、manual 人工

customerType選填
enum
directagency

客戶類型:direct 直客、agency 同業,預設直客

paymentPlan選填
enum
fulldeposit

付款方案:full 全額、deposit 訂金,預設全額

receivingAccountId選填
string

收款帳戶 ID,指定本筆款項入帳的帳戶

notes選填
string

訂單備註

assigneeUserId選填
string

指定業績歸屬業務的使用者 ID,省略或等於自己則歸屬建單者;指定他人需具備訂單指派權限

回應欄位 · data

orderId
string

新建立訂單的 ID(ord_ 前綴)。

orderNumber
string

訂單編號(租戶內流水序號,對外顯示用)。

請求
curl -X POST https://your-tenant.example.com/api/v1/orders \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "tripId": "<tripId>",
    "departureId": "<departureId>",
    "primaryEmail": "<primaryEmail>",
    "partySize": 0,
    "travelers": [],
    "paymentMethod": "cash"
  }'
回應
{
  "ok": true,
  "data": {
    "orderId": "…",
    "orderNumber": "…"
  }
}

full kind-aware order detail

GET/api/v1/orders/{id}
order.read

參數

id路徑
string· min 1

訂單 ID

回應欄位 · data

id
string

訂單 id(前綴 `ord_`)。

orderNumber
string

人類可讀訂單編號(每租戶 sequence 產生,如 `20260707-0001`)。

bookingState
string

預訂狀態(真相軸):pending_payment → confirmed → completed;cancelled 為終態。

paymentState
string

付款狀態(派生自分類帳、快取於此供過濾):unpaid / partially_paid / deposit_paid / paid / overpaid。paid 只代表「應收被現金覆蓋」,不代表錢未退。

refundState
string

退款狀態(派生快取,只算會影響應收的已付退款):none / partially_refunded / refunded。

grossReceivableTwd
number

應收(TWD 整數,派生自應收分類帳)。

collectedTwd
number

收到現金(TWD 整數,派生)。

customerCashAppliedTwd
number

客戶現金淨套用(收款減已退現金,TWD 整數,派生)。

outstandingTwd
number

未收(應收減客戶現金淨套用,TWD 整數,派生)。

partySize
number

參團人數(tour 訂單)。

createdAt
Date

訂單建立時間。

notes
string | null

訂單備註(未填 → null)。

userId
string

下單客戶的 user id(同庫 user 表)。

userName
string

下單客戶顯示名。

userEmail
string

下單客戶 Email。

primaryTravelerName
string | null

主要旅客姓名(is_primary,未登記 → null)。

primaryTravelerPhone
string | null

主要旅客電話(未登記 → null)。

tripId
string

行程 id(tour 訂單經梯次反查;lodging 為空字串)。

tripTitle
string

行程 / 產品標題。

tripSlug
string

行程 slug。

departureId
string

梯次 id(tour 訂單;lodging 為空字串)。

departureDate
string

出發日 YYYY-MM-DD(lodging 為入住日)。

returnDate
string

回程日 YYYY-MM-DD(lodging 為退房日)。

assignedToUserId
string | null

派發給哪位業務的 user id(未派發 → null)。

assigneeName
string | null

承辦業務顯示名(未派發 / 查無 → null)。

assignmentStatus
string

派發狀態:unassigned / assigned / reassigned / pending_review。

assignedAt
Date | null

最近一次派發時間(未派發 → null)。

assignedByUserId
string | null

執行派發者的 user id(未派發 → null)。

createdByUserId
string | null

S5: who created the order. null / equal to `userId` = customer self-service (自助下單); a staff id ≠ userId = 業務代訂 / K單. Distinct from assignment — a self-service order can still be assigned to a sales rep.

pendingConsent
boolean

是否尚缺最新版 PDPA 同意書簽署(true = 待客戶重簽)。

roomingStatus
RoomingStatus

分房狀態:由訂單旅客的分房偏好與已分配房間派生。 'unregistered' | 'registered' | 'needs_single' | 'assigned'。

lotteryState
string | null

抽籤狀態(null = FCFS 非抽籤)。'applied'|'won'|'lost'。

failoverFromOrderId
string | null

備案單反查主單用:備案單的 failover_from_order_id 指向主單 id。

isOverdue
boolean

逾期旗標:存在 status='open' 且 due_at 已過的收款計畫(未收齊的到期款)。 供列表列以 `bg-destructive/5` 標紅提示。由 OVERDUE_SUBSELECT 一次算回。

kind
"lodging" | "tour"

訂單種類(kind-agnostic 外殼)。'tour' 用既有 tour 區塊(梯次/分房/登山審核); 'lodging' 隱藏 tour-only 區、改顯示住宿 header(見 `lodging`)。共用的金流/旅客/ 派發/同意書區塊兩者皆 order-scoped 通用。

lodging
AdminLodgingHeader | null

lodging 住宿 header(房型/住期/房數/人數);tour 為 null。

travelers
object[]

旅客名單(含 PII 遮罩欄;主要旅客排前)。

id
string

旅客 id(前綴 `trv_`)。

fullName
string

旅客姓名。

idNumberMask
string | null

遮罩碼(jsonb→mask,零解密);NULL = 未填。全碼走 reveal action(Task 7)。

passportNoMask
string | null

護照號碼遮罩碼(零解密);NULL = 未填。全碼走 order-scoped reveal。

birthDate
string | null

生日 YYYY-MM-DD(未填 → null)。

phone
string | null

聯絡電話(未填 → null)。

email
string | null

聯絡 Email(未填 → null)。

emergencyContactName
string | null

緊急聯絡人姓名(未填 → null)。

emergencyContactPhone
string | null

緊急聯絡人電話(未填 → null)。

isPrimary
boolean

是否為主要旅客(訂單聯絡人)。

gender
string | null

性別(分房硬約束 + 顯示):'male'|'female'|'other'|null。明文。

roomPreference
string | null

分房房型偏好(下單登記)。

roommatePref
string | null

指定房友 / 特殊需求自由文字。

diet
string | null

飲食需求(葷素)明文;null = 未填。非 PII,不走 reveal。

medicalNotes
string | null

醫療 / 過敏 / 病史備註明文;null = 未填。非 PII,不走 reveal。

address
string | null

通訊地址(未填 → null)。

roomLabel
string | null

團控已排房號的房間 label(null = 待團控分房)。

chargeLines
object[]

應收分類帳(itemized)。

id
string

應收明細列 id。

type
string

應收類型:base(原始價)/ room_upgrade(房升補款)/ adjustment / failover_deposit_credit 等。

amountTwd
number

金額(TWD 整數,signed;credit / 沖銷為負)。

description
string

明細說明文字。

sourceType
string

來源:system(系統派生)/ manual(人工登錄)等。

reversesChargeLineId
string | null

若為沖銷列,指向被沖銷的應收明細列 id(否則 null)。

createdAt
Date

建立時間。

transactions
object[]

現金分類帳。

id
string

現金交易列 id。

direction
string

金流方向:in(收款)/ out(退款、扣款、沖銷)。

type
string

交易類型:payment / refund / chargeback / reversal。

amountTwd
number

交易金額(TWD 整數,正值)。

feeTwd
number

金流商手續費(TWD 整數)。

netTwd
number

淨額 = amount − fee(TWD 整數)。

provider
string

金流商:manual / ecpay / test 等。

providerTradeNo
string | null

金流商交易序號(manual 入帳可能為 null)。

refundId
string | null

若屬退款,指向 refunds 列 id(否則 null)。

occurredAt
Date

交易發生時間。

schedules
object[]

收款計畫(current + historical)。

id
string

收款計畫列 id。

purpose
string

用途:full(全額)/ deposit(訂金)/ balance(尾款)/ adjustment(補款)。

targetAmountTwd
number

應收目標金額(TWD 整數)。

status
string

計畫狀態:open(未收齊)/ satisfied(已收齊)。

dueAt
Date | null

到期日(null = 未設)。

sequence
number

排序序號(deposit → balance → adjustment)。

請求
curl -X GET https://your-tenant.example.com/api/v1/orders/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "id": "…",
    "orderNumber": "…",
    "bookingState": "…",
    "paymentState": "…",
    "refundState": "…",
    "grossReceivableTwd": 0,
    "collectedTwd": 0,
    "customerCashAppliedTwd": 0,
    "outstandingTwd": 0,
    "partySize": 0,
    "createdAt": "2026-06-30T08:00:00.000Z",
    "notes": "…",
    "userId": "…",
    "userName": "…",
    "userEmail": "…",
    "primaryTravelerName": "…",
    "primaryTravelerPhone": "…",
    "tripId": "…",
    "tripTitle": "…",
    "tripSlug": "…",
    "departureId": "…",
    "departureDate": "…",
    "returnDate": "…",
    "assignedToUserId": "…",
    "assigneeName": "…",
    "assignmentStatus": "…",
    "assignedAt": null,
    "assignedByUserId": "…",
    "createdByUserId": "…",
    "pendingConsent": true,
    "roomingStatus": "…",
    "lotteryState": "…",
    "failoverFromOrderId": "…",
    "isOverdue": true,
    "kind": "lodging",
    "lodging": null,
    "travelers": [
      {
        "id": "…",
        "fullName": "…",
        "idNumberMask": "…",
        "passportNoMask": "…",
        "birthDate": "…",
        "phone": "…",
        "email": "…",
        "emergencyContactName": "…",
        "emergencyContactPhone": "…",
        "isPrimary": true,
        "gender": "…",
        "roomPreference": "…",
        "roommatePref": "…",
        "diet": "…",
        "medicalNotes": "…",
        "address": "…",
        "roomLabel": "…"
      }
    ],
    "chargeLines": [
      {
        "id": "…",
        "type": "…",
        "amountTwd": 0,
        "description": "…",
        "sourceType": "…",
        "reversesChargeLineId": "…",
        "createdAt": "2026-06-30T08:00:00.000Z"
      }
    ],
    "transactions": [
      {
        "id": "…",
        "direction": "…",
        "type": "…",
        "amountTwd": 0,
        "feeTwd": 0,
        "netTwd": 0,
        "provider": "…",
        "providerTradeNo": "…",
        "refundId": "…",
        "occurredAt": "2026-06-30T08:00:00.000Z"
      }
    ],
    "schedules": [
      {
        "id": "…",
        "purpose": "…",
        "targetAmountTwd": 0,
        "status": "…",
        "dueAt": null,
        "sequence": 0
      }
    ]
  }
}

manual charge adjustment

POST/api/v1/orders/{id}/adjust
order.adjust

參數

id路徑
string· min 1

訂單 ID

kind必填
enum
surchargeallowance

調整類型:surcharge 加收、allowance 減免

amountTwd必填
integer

調整金額(新台幣,正整數)

description必填
string· min 1

調整事由說明

回應欄位 · data

ok
boolean

固定為 true:訂單金額調整已套用。

請求
curl -X POST https://your-tenant.example.com/api/v1/orders/<id>/adjust \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "surcharge",
    "amountTwd": 0,
    "description": "<description>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

首次派發訂單給承辦業務

POST/api/v1/orders/{id}/assign
order.assign

參數

id路徑
string· min 1

訂單 ID

assigneeUserId必填
string· min 1

受派業務的使用者 ID

reason選填
string· max 500

派發事由說明(上限 500 字)

回應欄位 · data

ok
boolean

固定為 true:訂單已指派承辦。

idempotent
boolean

true = 該訂單原已指派給同一承辦,本次為冪等無變更。

請求
curl -X POST https://your-tenant.example.com/api/v1/orders/<id>/assign \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "assigneeUserId": "<assigneeUserId>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "idempotent": true
  }
}

產生/重用尾款

POST/api/v1/orders/{id}/balance-link
order.update

參數

id路徑
string· min 1

訂單 ID

回應欄位 · data

ok
boolean

固定為 true:尾款付款連結已產生。

amountTwd
number

本次尾款金額(TWD 整數)。

scheduleId
string

對應的收款計畫 ID。

請求
curl -X POST https://your-tenant.example.com/api/v1/orders/<id>/balance-link \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "amountTwd": 0,
    "scheduleId": "…"
  }
}

cancel a tour order

POST/api/v1/orders/{id}/cancel
order.update

參數

id路徑
string· min 1

訂單 ID

reason選填
string

取消事由說明

回應欄位 · data

ok
boolean

固定為 true:訂單已取消(座位釋出、booking_state 轉 cancelled)。

請求
curl -X POST https://your-tenant.example.com/api/v1/orders/<id>/cancel \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

業務自派搶單

POST/api/v1/orders/{id}/claim
order.claim

參數

id路徑
string· min 1

訂單 ID

回應欄位 · data

ok
boolean

固定為 true:訂單已由當前承辦認領。

請求
curl -X POST https://your-tenant.example.com/api/v1/orders/<id>/claim \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

線控手動抽籤裁決:won

POST/api/v1/orders/{id}/lottery/resolve
lottery.manage

參數

id路徑
string· min 1

訂單 ID

outcome必填
enum
wonlost

抽籤裁決結果:won 中籤確認、lost 未中籤(啟動備案或取消)

回應欄位 · data

ok
boolean

固定為 true:抽籤結果已登錄。

outcome
"won" | "lost"

抽籤結果:won 中籤 / lost 未中籤。

請求
curl -X POST https://your-tenant.example.com/api/v1/orders/<id>/lottery/resolve \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "outcome": "won"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "outcome": "won"
  }
}

mark an order paid by manual

POST/api/v1/orders/{id}/mark-paid
payment.update

參數

id路徑
string· min 1

訂單 ID

note選填
string

對帳備註,記錄人工核款說明

receivingAccountId選填
string

收款帳戶 ID,指定本筆款項入帳的帳戶

回應欄位 · data

idempotent
boolean

true = 訂單原已為已付狀態,本次為冪等無變更。

請求
curl -X POST https://your-tenant.example.com/api/v1/orders/<id>/mark-paid \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "idempotent": true
  }
}

重新指派已派發訂單

POST/api/v1/orders/{id}/reassign
order.reassign

參數

id路徑
string· min 1

訂單 ID

assigneeUserId必填
string· min 1

重新指派的承接業務使用者 ID

reason選填
string· max 500

重派事由說明(上限 500 字)

回應欄位 · data

ok
boolean

固定為 true:訂單已改派承辦。

idempotent
boolean

true = 目標承辦與原承辦相同,本次為冪等無變更。

請求
curl -X POST https://your-tenant.example.com/api/v1/orders/<id>/reassign \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "assigneeUserId": "<assigneeUserId>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "idempotent": true
  }
}

create + submit a customer refund

POST/api/v1/orders/{id}/refunds
refund.create

參數

id路徑
string· min 1

訂單 ID

refundKind必填
enum
receivable_reductionoverpayment_return

退款種類:receivable_reduction 應收減免、overpayment_return 溢收退還

reason必填
string· min 1

退款事由說明

amountTwd必填
integer

退款總金額(新台幣,正整數)

executionMethod選填
enum
chargebackremit

退款執行方式:chargeback 原路退刷、remit 銀行匯款

originAccountId選填
string

出款來源帳戶 ID(匯款退款時指定)

adminFeeTwd選填
integer

手續費/行政費(新台幣,非負整數)

remitFeeTwd選填
integer

匯款轉帳費(新台幣,非負整數)

payeeAccountName選填
string

受款人戶名(匯款退款時填寫)

payeeBankCode選填
string

受款銀行代碼(匯款退款時填寫)

payeeAccountNumber選填
string

受款銀行帳號(匯款退款時填寫)

lines選填
array

退款明細列;省略時依退款總額處理

回應欄位 · data

id
string

退款單 id(前綴 `rfnd_`)。

refundNumber
string

人類可讀退款單號。

status
RefundStatus

退款工作流狀態:draft → submitted → approved → processing → paid。

請求
curl -X POST https://your-tenant.example.com/api/v1/orders/<id>/refunds \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "refundKind": "receivable_reduction",
    "reason": "<reason>",
    "amountTwd": 0
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…",
    "refundNumber": "…",
    "status": "…"
  }
}

approve a submitted

POST/api/v1/orders/{id}/refunds/{refundId}/approve
refund.approve

參數

refundId路徑
string· min 1

退款單 ID

回應欄位 · data

ok
boolean

固定為 true:退款申請已核准。

請求
curl -X POST https://your-tenant.example.com/api/v1/orders/{id}/refunds/<refundId>/approve \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

mark an approved

POST/api/v1/orders/{id}/refunds/{refundId}/mark-paid
refund.mark_paid

參數

id路徑
string· min 1

訂單 ID(path)

refundId路徑
string· min 1

退款單 ID

bankReference選填
string

出款的銀行交易參考號(匯款憑證)

receivingAccountId選填
string

出款帳戶 ID;remit 退款須指定具匯款能力的帳戶

回應欄位 · data

ok
boolean

固定為 true:退款已標記為完成出款。

請求
curl -X POST https://your-tenant.example.com/api/v1/orders/<id>/refunds/<refundId>/mark-paid \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

reject a submitted

POST/api/v1/orders/{id}/refunds/{refundId}/reject
refund.reject

參數

refundId路徑
string· min 1

退款單 ID

reason選填
string

退件事由說明

回應欄位 · data

ok
boolean

固定為 true:退款申請已駁回。

請求
curl -X POST https://your-tenant.example.com/api/v1/orders/{id}/refunds/<refundId>/reject \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

reverse an existing charge line

POST/api/v1/orders/{id}/reverse
order.adjust

參數

id路徑
string· min 1

訂單 ID

chargeLineId必填
string· min 1

欲沖正的應收項目(charge line)ID

description必填
string· min 1

沖正事由說明

回應欄位 · data

ok
boolean

固定為 true:訂單已沖銷(沖回應收與已認列項)。

請求
curl -X POST https://your-tenant.example.com/api/v1/orders/<id>/reverse \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "chargeLineId": "<chargeLineId>",
    "description": "<description>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

人工核可/駁回登山資格審核

POST/api/v1/orders/{id}/review-screening
screening.review

參數

id路徑
string· min 1

訂單 ID

decision必填
enum
approvereject

登山資格審核裁決:approve 核可、reject 駁回

note選填
string· max 500

審核註記說明(上限 500 字)

回應欄位 · data

ok
boolean

固定為 true:名單複核結果已登錄。

請求
curl -X POST https://your-tenant.example.com/api/v1/orders/<id>/review-screening \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "decision": "approve"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

新增旅客到訂單

POST/api/v1/orders/{id}/travelers
order.update

參數

fullName選填
string· min 1

旅客全名,須與證件一致;新增旅客時必填,更新時可省略

phone選填
string

旅客聯絡電話

email選填
string

旅客電子郵件

birthDate選填
string

旅客出生日期(格式 YYYY-MM-DD)

emergencyContactName選填
string

緊急聯絡人姓名

emergencyContactPhone選填
string

緊急聯絡人電話

gender選填
enum
malefemaleother

旅客性別:male 男、female 女、other 其他

roomPreference選填
string

房型偏好(用於分房作業)

roommatePref選填
string

指定同住室友(用於分房作業)

diet選填
string

飲食需求(葷 / 素 / 蛋奶素… 自由值),供餐食葷素彙總

medicalNotes選填
string

醫療 / 過敏 / 病史備註(自由文字),供出團安全警示

address選填
string

旅客通訊地址

idNumber選填
string

身分證字號,屬個資將加密保存

passportNo選填
string

護照號碼,屬個資將加密保存

id路徑
string· min 1

訂單 ID

回應欄位 · data

ok
boolean

固定為 true:旅客已新增至訂單。

travelerId
string

新建立旅客的 ID(trv_ 前綴)。

請求
curl -X POST https://your-tenant.example.com/api/v1/orders/<id>/travelers \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "travelerId": "…"
  }
}

更新旅客資料

PATCH/api/v1/orders/{id}/travelers/{travelerId}
order.update

參數

fullName選填
string· min 1

旅客全名,須與證件一致;新增旅客時必填,更新時可省略

phone選填
string

旅客聯絡電話

email選填
string

旅客電子郵件

birthDate選填
string

旅客出生日期(格式 YYYY-MM-DD)

emergencyContactName選填
string

緊急聯絡人姓名

emergencyContactPhone選填
string

緊急聯絡人電話

gender選填
enum
malefemaleother

旅客性別:male 男、female 女、other 其他

roomPreference選填
string

房型偏好(用於分房作業)

roommatePref選填
string

指定同住室友(用於分房作業)

diet選填
string

飲食需求(葷 / 素 / 蛋奶素… 自由值),供餐食葷素彙總

medicalNotes選填
string

醫療 / 過敏 / 病史備註(自由文字),供出團安全警示

address選填
string

旅客通訊地址

idNumber選填
string

身分證字號,屬個資將加密保存

passportNo選填
string

護照號碼,屬個資將加密保存

id路徑
string· min 1

訂單 ID

travelerId路徑
string· min 1

旅客 ID

回應欄位 · data

ok
boolean

固定為 true:旅客資料已更新。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/orders/<id>/travelers/<travelerId> \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

移除旅客

DELETE/api/v1/orders/{id}/travelers/{travelerId}
order.update

參數

id路徑
string· min 1

訂單 ID

travelerId路徑
string· min 1

旅客 ID

回應欄位 · data

ok
boolean

固定為 true:旅客已自訂單移除。

請求
curl -X DELETE https://your-tenant.example.com/api/v1/orders/<id>/travelers/<travelerId> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

顯示旅客證號/護照全碼

POST/api/v1/orders/{id}/travelers/{travelerId}/reveal
order.read

參數

id路徑
string· min 1

訂單 ID

travelerId路徑
string· min 1

旅客 ID

field必填
enum
idNumberpassportNo

欲顯示全碼的個資欄位:idNumber 身分證字號、passportNo 護照號碼

回應欄位 · data

field
"idNumber" | "passportNo"

本次解密的欄位:idNumber 身分證字號 / passportNo 護照號碼。

value
string | null

解密後的證件明碼;null = 該欄未填。每次呼叫都會寫入解密稽核紀錄。

請求
curl -X POST https://your-tenant.example.com/api/v1/orders/<id>/travelers/<travelerId>/reveal \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "field": "idNumber"
  }'
回應
{
  "ok": true,
  "data": {
    "field": "idNumber",
    "value": "…"
  }
}

更新旅客分房需求

PATCH/api/v1/orders/{id}/travelers/{travelerId}/rooming
order.update

參數

roomPreference選填
string

房型偏好(用於分房作業)

roommatePref選填
string

指定同住室友(用於分房作業)

id路徑
string· min 1

訂單 ID

travelerId路徑
string· min 1

旅客 ID

回應欄位 · data

ok
boolean

固定為 true:旅客分房設定已更新。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/orders/<id>/travelers/<travelerId>/rooming \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

批次把多張訂單派給同一位業務

POST/api/v1/orders/bulk-assign
order.assign

參數

orderIds必填
array· max 100 · min 1

欲批次派發的訂單 ID 陣列(1 至 100 筆)

assigneeUserId必填
string· min 1

受派業務的使用者 ID(所有訂單派給同一人)

reason選填
string· max 500

派發事由說明(上限 500 字)

回應欄位 · data

ok
boolean

固定為 true:批次指派已執行。

assignedCount
number

成功指派的訂單筆數。

skippedCount
number

略過的訂單筆數(如已指派或不在可指派範圍)。

請求
curl -X POST https://your-tenant.example.com/api/v1/orders/bulk-assign \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "orderIds": [],
    "assigneeUserId": "<assigneeUserId>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "assignedCount": 0,
    "skippedCount": 0
  }
}

匯出訂單

GET/api/v1/orders/export
order.read

參數

status選填
string

依訂單顯示狀態篩選(如 pending、paid、cancelled)

assignment選填
string

依派發狀態篩選(如 unassigned、assigned)

rooming選填
string

依分房狀態篩選

dateFrom選填
string

出發日期區間起(格式 YYYY-MM-DD,含當日)

dateTo選填
string

出發日期區間迄(格式 YYYY-MM-DD,含當日)

q選填
string

關鍵字搜尋(訂單編號、訂購人姓名或 Email 等)

agencyId選填
string

依合作旅行社 ID 篩選(同業單)

回應欄位 · data

rows
object[]

符合篩選條件的所有列(逐頁累積;達安全上限時截斷)。

id
string

訂單 id(前綴 `ord_`)。

orderNumber
string

人類可讀訂單編號(每租戶 sequence 產生,如 `20260707-0001`)。

bookingState
string

預訂狀態(真相軸):pending_payment → confirmed → completed;cancelled 為終態。

paymentState
string

付款狀態(派生自分類帳、快取於此供過濾):unpaid / partially_paid / deposit_paid / paid / overpaid。paid 只代表「應收被現金覆蓋」,不代表錢未退。

refundState
string

退款狀態(派生快取,只算會影響應收的已付退款):none / partially_refunded / refunded。

grossReceivableTwd
number

應收(TWD 整數,派生自應收分類帳)。

collectedTwd
number

收到現金(TWD 整數,派生)。

customerCashAppliedTwd
number

客戶現金淨套用(收款減已退現金,TWD 整數,派生)。

outstandingTwd
number

未收(應收減客戶現金淨套用,TWD 整數,派生)。

partySize
number

參團人數(tour 訂單)。

createdAt
Date

訂單建立時間。

notes
string | null

訂單備註(未填 → null)。

userId
string

下單客戶的 user id(同庫 user 表)。

userName
string

下單客戶顯示名。

userEmail
string

下單客戶 Email。

primaryTravelerName
string | null

主要旅客姓名(is_primary,未登記 → null)。

primaryTravelerPhone
string | null

主要旅客電話(未登記 → null)。

tripId
string

行程 id(tour 訂單經梯次反查;lodging 為空字串)。

tripTitle
string

行程 / 產品標題。

tripSlug
string

行程 slug。

departureId
string

梯次 id(tour 訂單;lodging 為空字串)。

departureDate
string

出發日 YYYY-MM-DD(lodging 為入住日)。

returnDate
string

回程日 YYYY-MM-DD(lodging 為退房日)。

assignedToUserId
string | null

派發給哪位業務的 user id(未派發 → null)。

assigneeName
string | null

承辦業務顯示名(未派發 / 查無 → null)。

assignmentStatus
string

派發狀態:unassigned / assigned / reassigned / pending_review。

assignedAt
Date | null

最近一次派發時間(未派發 → null)。

assignedByUserId
string | null

執行派發者的 user id(未派發 → null)。

createdByUserId
string | null

S5: who created the order. null / equal to `userId` = customer self-service (自助下單); a staff id ≠ userId = 業務代訂 / K單. Distinct from assignment — a self-service order can still be assigned to a sales rep.

pendingConsent
boolean

是否尚缺最新版 PDPA 同意書簽署(true = 待客戶重簽)。

roomingStatus
RoomingStatus

分房狀態:由訂單旅客的分房偏好與已分配房間派生。 'unregistered' | 'registered' | 'needs_single' | 'assigned'。

lotteryState
string | null

抽籤狀態(null = FCFS 非抽籤)。'applied'|'won'|'lost'。

failoverFromOrderId
string | null

備案單反查主單用:備案單的 failover_from_order_id 指向主單 id。

isOverdue
boolean

逾期旗標:存在 status='open' 且 due_at 已過的收款計畫(未收齊的到期款)。 供列表列以 `bg-destructive/5` 標紅提示。由 OVERDUE_SUBSELECT 一次算回。

total
number

符合篩選條件的總筆數。

truncated
boolean

是否因達安全上限而截斷(true 表未回傳完整結果,呼叫端應提示)。

請求
curl -X GET https://your-tenant.example.com/api/v1/orders/export \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "rows": [
      {
        "id": "…",
        "orderNumber": "…",
        "bookingState": "…",
        "paymentState": "…",
        "refundState": "…",
        "grossReceivableTwd": 0,
        "collectedTwd": 0,
        "customerCashAppliedTwd": 0,
        "outstandingTwd": 0,
        "partySize": 0,
        "createdAt": "2026-06-30T08:00:00.000Z",
        "notes": "…",
        "userId": "…",
        "userName": "…",
        "userEmail": "…",
        "primaryTravelerName": "…",
        "primaryTravelerPhone": "…",
        "tripId": "…",
        "tripTitle": "…",
        "tripSlug": "…",
        "departureId": "…",
        "departureDate": "…",
        "returnDate": "…",
        "assignedToUserId": "…",
        "assigneeName": "…",
        "assignmentStatus": "…",
        "assignedAt": null,
        "assignedByUserId": "…",
        "createdByUserId": "…",
        "pendingConsent": true,
        "roomingStatus": "…",
        "lotteryState": "…",
        "failoverFromOrderId": "…",
        "isOverdue": true
      }
    ],
    "total": 0,
    "truncated": true
  }
}

order KPI counts

GET/api/v1/orders/stats
order.read

回應欄位 · data

pendingPayment
number

待付款訂單數(未取消 / 未完成 / 未退款且 payment_state=unpaid)。

depositPaid
number

已付訂金訂單數(payment_state=deposit_paid)。

paid
number

已收齊訂單數(payment_state in paid/overpaid)。

cancelled
number

已取消訂單數(booking_state=cancelled)。

refunded
number

有退款的訂單數(refund_state in refunded/partially_refunded)。

completed
number

已完成訂單數(booking_state=completed)。

thisMonthPaidTwd
number

本月實收現金(payment_transactions direction=in 加總,TWD 整數)。

thisMonthNewOrders
number

本月新建訂單數。

thisMonthCancelled
number

本月取消訂單數。

請求
curl -X GET https://your-tenant.example.com/api/v1/orders/stats \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "pendingPayment": 0,
    "depositPaid": 0,
    "paid": 0,
    "cancelled": 0,
    "refunded": 0,
    "completed": 0,
    "thisMonthPaidTwd": 0,
    "thisMonthNewOrders": 0,
    "thisMonthCancelled": 0
  }
}

/equipment

list the equipment master

GET/api/v1/equipment/items
equipment.read

參數

activeOnly選填
boolean

只列出啟用中(可租借)的品項

回應欄位 · data[]

id
string

裝備主檔品項 id(equipmentItem_ 前綴)。

name
string

品名。

category
string | null

分類(如帳篷/睡袋/爐具;未分類為 null)。

spec
string | null

規格描述(尺寸/型號等;可空)。

rentPriceTwd
number

每日租金單價(TWD)。

depositTwd
number

每件押金(TWD)。

totalCount
number

庫存總件數。

outCount
number

目前在外(已借出未歸還)件數。

maintenanceCount
number

維修中件數(不可借出)。

availableCount
number

可租 = total − out − maintenance(派生,便利 UI)。

isActive
boolean

是否啟用(可租借)。

createdAt
Date

建檔時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/equipment/items \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "name": "…",
      "category": "…",
      "spec": "…",
      "rentPriceTwd": 0,
      "depositTwd": 0,
      "totalCount": 0,
      "outCount": 0,
      "maintenanceCount": 0,
      "availableCount": 0,
      "isActive": true,
      "createdAt": "2026-06-30T08:00:00.000Z",
      "updatedAt": "2026-06-30T08:00:00.000Z"
    }
  ]
}

create a master item

POST/api/v1/equipment/items
equipment.manage

參數

name必填
string· max 200 · min 1

裝備品項名稱

category選填
string· max 50

裝備分類(如帳篷、睡袋;選填)

spec選填
string· max 500

規格說明(如尺寸、型號;選填)

rentPriceTwd選填
integer· min 0

每日租金(台幣)

depositTwd選填
integer· min 0

每件押金(台幣)

totalCount選填
integer· min 0

總庫存數量

maintenanceCount選填
integer· min 0

維修中而不可租借的數量

isActive選填
boolean

是否啟用(可供租借)

回應欄位 · data

id
string

新建立的裝備品項 id。

請求
curl -X POST https://your-tenant.example.com/api/v1/equipment/items \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "<name>"
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…"
  }
}

single equipment master item detail.

GET/api/v1/equipment/items/{id}
equipment.read

參數

id路徑
string· min 1

裝備品項 ID

回應欄位 · data

id
string

裝備主檔品項 id(equipmentItem_ 前綴)。

name
string

品名。

category
string | null

分類(如帳篷/睡袋/爐具;未分類為 null)。

spec
string | null

規格描述(尺寸/型號等;可空)。

rentPriceTwd
number

每日租金單價(TWD)。

depositTwd
number

每件押金(TWD)。

totalCount
number

庫存總件數。

outCount
number

目前在外(已借出未歸還)件數。

maintenanceCount
number

維修中件數(不可借出)。

availableCount
number

可租 = total − out − maintenance(派生,便利 UI)。

isActive
boolean

是否啟用(可租借)。

createdAt
Date

建檔時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/equipment/items/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "id": "…",
    "name": "…",
    "category": "…",
    "spec": "…",
    "rentPriceTwd": 0,
    "depositTwd": 0,
    "totalCount": 0,
    "outCount": 0,
    "maintenanceCount": 0,
    "availableCount": 0,
    "isActive": true,
    "createdAt": "2026-06-30T08:00:00.000Z",
    "updatedAt": "2026-06-30T08:00:00.000Z"
  }
}

update a master item

PATCH/api/v1/equipment/items/{id}
equipment.manage

參數

id路徑
string· min 1

要更新的裝備品項 ID

name必填
string· max 200 · min 1

裝備品項名稱

category選填
string· max 50

裝備分類(如帳篷、睡袋;選填)

spec選填
string· max 500

規格說明(如尺寸、型號;選填)

rentPriceTwd選填
integer· min 0

每日租金(台幣)

depositTwd選填
integer· min 0

每件押金(台幣)

totalCount選填
integer· min 0

總庫存數量

maintenanceCount選填
integer· min 0

維修中而不可租借的數量

isActive選填
boolean

是否啟用(可供租借)

回應欄位 · data

ok
boolean

更新成功旗標,恆為 true。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/equipment/items/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "<name>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

list rental tickets

GET/api/v1/equipment/rentals
equipment.read

參數

returnState選填
enum
rentedreturnedoverdue

依歸還狀態篩選:rented 在租中、returned 已歸還、overdue 逾期

reconState選填
enum
pendingreconcileddeposit_pending

依驗收結算狀態篩選:pending 待驗收、reconciled 已結算、deposit_pending 待退押金

orderId選填
string

只列出綁定此訂單 ID 的租借單

departureId選填
string

只列出綁定此梯次 ID 的租借單

回應欄位 · data[]

id
string

租借單 id(equipmentRental_ 前綴)。

orderId
string

掛載的訂單 id。

orderNumber
string | null

訂單編號(JOIN;可空)。

departureId
string | null

綁定的梯次 id(可不綁梯次時 null)。

departureLabel
string | null

梯次可讀標籤:團號 ‧ 行程名 ‧ 出發日(無綁梯次時 null)。

renterName
string | null

租借人姓名(可空)。

rentStartDate
string | null

租期起日(YYYY-MM-DD;可空)。

rentEndDate
string | null

租期迄日(YYYY-MM-DD;可空)。

returnedAt
Date | null

歸還驗收時間(尚未歸還為 null)。

returnState
ReturnState

歸還狀態:rented 租借中/returned 已歸還/overdue 逾期。

inspectedAt
Date | null

驗收時間(尚未驗收為 null)。

damageCostTwd
number | null

破損/遺失賠償金額(TWD;無為 null)。

reconState
ReconState

對款狀態:pending 待對款/reconciled 已結清/deposit_pending 押金待退或待扣。

notes
string | null

備註(可空)。

createdAt
Date

建單時間。

updatedAt
Date

最後更新時間。

lines
object[]

租借明細(借出的品項清單)。

id
string

租借明細 id(equipmentRentalLine_ 前綴)。

equipmentItemId
string

借出的裝備主檔品項 id。

itemName
string | null

主檔品名快照(JOIN,便利顯示;改主檔不回寫單)。

quantity
number

借出數量。

rentPriceTwdSnapshot
number

成交單位總價快照(每日單價 × 計價日數;TWD)。

depositTwdSnapshot
number

成交每件押金快照(TWD,不乘天數)。

returnedQuantity
number | null

已歸還數量(尚未歸還為 null)。

rentTotalTwd
number

成交租金合計(Σ rent snapshot × qty)。

depositTotalTwd
number

成交押金合計(Σ deposit snapshot × qty)。

請求
curl -X GET https://your-tenant.example.com/api/v1/equipment/rentals \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "orderId": "…",
      "orderNumber": "…",
      "departureId": "…",
      "departureLabel": "…",
      "renterName": "…",
      "rentStartDate": "…",
      "rentEndDate": "…",
      "returnedAt": null,
      "returnState": "…",
      "inspectedAt": null,
      "damageCostTwd": 0,
      "reconState": "…",
      "notes": "…",
      "createdAt": "2026-06-30T08:00:00.000Z",
      "updatedAt": "2026-06-30T08:00:00.000Z",
      "lines": [
        {
          "id": "…",
          "equipmentItemId": "…",
          "itemName": "…",
          "quantity": 0,
          "rentPriceTwdSnapshot": 0,
          "depositTwdSnapshot": 0,
          "returnedQuantity": 0
        }
      ],
      "rentTotalTwd": 0,
      "depositTotalTwd": 0
    }
  ]
}

open a rental ticket

POST/api/v1/equipment/rentals
equipment.manage

參數

orderId必填
string· min 1

租借單綁定的訂單 ID(租金與押金會掛入該訂單金流)

departureId選填
string

關聯的梯次 ID(選填)

renterName選填
string· max 100

租借人姓名(選填)

rentStartDate選填
string· 格式限定

租借起始日,格式 YYYY-MM-DD(選填)

rentEndDate選填
string· 格式限定

租借結束日,格式 YYYY-MM-DD(選填)

notes選填
string· max 1000

租借單備註(選填)

lines必填
array· min 1

租借明細清單(至少一筆品項)

回應欄位 · data

rentalId
string

新開立的租借單 id。

請求
curl -X POST https://your-tenant.example.com/api/v1/equipment/rentals \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "orderId": "<orderId>",
    "lines": []
  }'
回應
{
  "ok": true,
  "data": {
    "rentalId": "…"
  }
}

single rental ticket detail

GET/api/v1/equipment/rentals/{id}
equipment.read

參數

id路徑
string· min 1

租借單 ID

回應欄位 · data

id
string

租借單 id(equipmentRental_ 前綴)。

orderId
string

掛載的訂單 id。

orderNumber
string | null

訂單編號(JOIN;可空)。

departureId
string | null

綁定的梯次 id(可不綁梯次時 null)。

departureLabel
string | null

梯次可讀標籤:團號 ‧ 行程名 ‧ 出發日(無綁梯次時 null)。

renterName
string | null

租借人姓名(可空)。

rentStartDate
string | null

租期起日(YYYY-MM-DD;可空)。

rentEndDate
string | null

租期迄日(YYYY-MM-DD;可空)。

returnedAt
Date | null

歸還驗收時間(尚未歸還為 null)。

returnState
ReturnState

歸還狀態:rented 租借中/returned 已歸還/overdue 逾期。

inspectedAt
Date | null

驗收時間(尚未驗收為 null)。

damageCostTwd
number | null

破損/遺失賠償金額(TWD;無為 null)。

reconState
ReconState

對款狀態:pending 待對款/reconciled 已結清/deposit_pending 押金待退或待扣。

notes
string | null

備註(可空)。

createdAt
Date

建單時間。

updatedAt
Date

最後更新時間。

lines
object[]

租借明細(借出的品項清單)。

id
string

租借明細 id(equipmentRentalLine_ 前綴)。

equipmentItemId
string

借出的裝備主檔品項 id。

itemName
string | null

主檔品名快照(JOIN,便利顯示;改主檔不回寫單)。

quantity
number

借出數量。

rentPriceTwdSnapshot
number

成交單位總價快照(每日單價 × 計價日數;TWD)。

depositTwdSnapshot
number

成交每件押金快照(TWD,不乘天數)。

returnedQuantity
number | null

已歸還數量(尚未歸還為 null)。

rentTotalTwd
number

成交租金合計(Σ rent snapshot × qty)。

depositTotalTwd
number

成交押金合計(Σ deposit snapshot × qty)。

請求
curl -X GET https://your-tenant.example.com/api/v1/equipment/rentals/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "id": "…",
    "orderId": "…",
    "orderNumber": "…",
    "departureId": "…",
    "departureLabel": "…",
    "renterName": "…",
    "rentStartDate": "…",
    "rentEndDate": "…",
    "returnedAt": null,
    "returnState": "…",
    "inspectedAt": null,
    "damageCostTwd": 0,
    "reconState": "…",
    "notes": "…",
    "createdAt": "2026-06-30T08:00:00.000Z",
    "updatedAt": "2026-06-30T08:00:00.000Z",
    "lines": [
      {
        "id": "…",
        "equipmentItemId": "…",
        "itemName": "…",
        "quantity": 0,
        "rentPriceTwdSnapshot": 0,
        "depositTwdSnapshot": 0,
        "returnedQuantity": 0
      }
    ],
    "rentTotalTwd": 0,
    "depositTotalTwd": 0
  }
}

flag a single rented ticket

POST/api/v1/equipment/rentals/{id}/mark-overdue
equipment.manage

參數

id路徑
string· min 1

要標記為逾期的租借單 ID

回應欄位 · data

ok
boolean

標記逾期成功旗標,恆為 true。

請求
curl -X POST https://your-tenant.example.com/api/v1/equipment/rentals/<id>/mark-overdue \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

receive a rental back

POST/api/v1/equipment/rentals/{id}/return
equipment.manage

參數

id路徑
string· min 1

要驗收歸還的租借單 ID

returnedLines必填
array· min 1

各明細的歸還數量清單

damageCostTwd選填
integer· min 0

損壞賠償金額(台幣,選填)

回應欄位 · data

ok
boolean

驗收歸還成功旗標,恆為 true。

請求
curl -X POST https://your-tenant.example.com/api/v1/equipment/rentals/<id>/return \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "returnedLines": []
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

the minimal order picker

GET/api/v1/equipment/rentals/order-options
equipment.read

參數

limit選填
integer· max 200

回傳訂單筆數上限(最多 200,預設取最近多筆)

回應欄位 · data[]

orderId
string

訂單 id。

orderNumber
string | null

訂單編號(可空)。

customerName
string | null

訂購人姓名(可空)。

請求
curl -X GET https://your-tenant.example.com/api/v1/equipment/rentals/order-options \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "orderId": "…",
      "orderNumber": "…",
      "customerName": "…"
    }
  ]
}

/guide-roster

指派 / 重派 guide 到梯次

POST/api/v1/guide-roster/assignments
guide_roster.manage

參數

departureId必填
string· max 64 · min 1

指派的目標梯次 ID

guideId必填
string· max 64 · min 1

被指派的領隊/嚮導 ID

role必填
enum

指派角色(leader 領隊/assistant 隨隊助理)

status必填
enum

指派狀態(tentative 預塞暫定/confirmed 正式確認)

回應欄位 · data

id
string

新建立(或重派後)的指派紀錄 id。

請求
curl -X POST https://your-tenant.example.com/api/v1/guide-roster/assignments \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "departureId": "<departureId>",
    "guideId": "<guideId>",
    "role": "<role>",
    "status": "<status>"
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…"
  }
}

移除某筆指派

DELETE/api/v1/guide-roster/assignments/{id}
guide_roster.manage

參數

id路徑
string· max 64 · min 1

要移除的指派紀錄 ID

回應欄位 · data

ok
boolean

移除成功旗標,恆為 true。

請求
curl -X DELETE https://your-tenant.example.com/api/v1/guide-roster/assignments/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

正式確認某筆指派

POST/api/v1/guide-roster/assignments/{id}/confirm
guide_roster.manage

參數

id路徑
string· max 64 · min 1

要正式確認的指派紀錄 ID

回應欄位 · data

ok
boolean

確認成功旗標,恆為 true。

請求
curl -X POST https://your-tenant.example.com/api/v1/guide-roster/assignments/<id>/confirm \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

換領隊

POST/api/v1/guide-roster/change-leader
guide_roster.manage

參數

departureId必填
string· max 64 · min 1

要換領隊的目標梯次 ID

fromGuideId選填
string· max 64 · min 1

原領隊嚮導 ID(選填;省略表示該梯次原本無領隊)

toGuideId必填
string· max 64 · min 1

新任領隊嚮導 ID

reason必填
string· max 500 · min 1

換領隊的原因(必填,記入稽核)

回應欄位 · data

id
string

新任領隊的指派紀錄 id。

removedGuideIds
string[]

被移除的舊領隊嚮導 id 清單(DB 權威)。

請求
curl -X POST https://your-tenant.example.com/api/v1/guide-roster/change-leader \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "departureId": "<departureId>",
    "toGuideId": "<toGuideId>",
    "reason": "<reason>"
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…",
    "removedGuideIds": [
      "…"
    ]
  }
}

pre-check whether assigning a guide

GET/api/v1/guide-roster/conflict-check
guide_roster.read

參數

departureId必填
string· min 1

欲指派的目標梯次 ID

guideId必填
string· min 1

欲檢查檔期衝突的領隊/嚮導 ID

請求
curl -X GET "https://your-tenant.example.com/api/v1/guide-roster/conflict-check?departureId=<departureId>&guideId=<guideId>" \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": null
}

schedule conflicts for the selected

GET/api/v1/guide-roster/conflicts
guide_roster.read

參數

month必填
string· 格式限定

查詢月份(YYYY-MM 格式)

回應欄位 · data[]

guideId
string

發生衝突的嚮導 id。

guideName
string

發生衝突的嚮導姓名。

a
object

衝突梯次之一(含梯次 id/行程名/起訖日)。

departureId
string

梯次 id。

tripTitle
string

行程名稱。

departureDate
string

出發日(YYYY-MM-DD)。

returnDate
string

回程日(YYYY-MM-DD)。

b
object

與 a 日期重疊的另一梯次(含梯次 id/行程名/起訖日)。

departureId
string

梯次 id。

tripTitle
string

行程名稱。

departureDate
string

出發日(YYYY-MM-DD)。

returnDate
string

回程日(YYYY-MM-DD)。

請求
curl -X GET "https://your-tenant.example.com/api/v1/guide-roster/conflicts?month=<month>" \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "guideId": "…",
      "guideName": "…",
      "a": {
        "departureId": "…",
        "tripTitle": "…",
        "departureDate": "…",
        "returnDate": "…"
      },
      "b": {
        "departureId": "…",
        "tripTitle": "…",
        "departureDate": "…",
        "returnDate": "…"
      }
    }
  ]
}

the selected month's departures

GET/api/v1/guide-roster/departures
guide_roster.read

參數

month必填
string· 格式限定

查詢月份(YYYY-MM 格式)

includeCancelled選填
boolean

是否一併納入已取消的梯次(預設不納入)

回應欄位 · data[]

id
string

梯次 id。

tripId
string

所屬行程 id。

tripTitle
string

行程名稱。

departureDate
string

出發日(YYYY-MM-DD)。

returnDate
string

回程日(YYYY-MM-DD)。

days
number

帶團天數(含頭尾)。

capacity
number

團位容量(總名額)。

bookedCount
number

已成團報名人數。

status
string

梯次狀態(如 open 開放/full 已滿/cancelled 已取消)。

assignments
object[]

該梯次所有指派(領隊在前)。

id
string

指派紀錄 id。

guideId
string

被指派的嚮導 id。

guideName
string

被指派的嚮導姓名。

role
"leader" | "assistant"

指派角色:leader 領隊/assistant 隨隊助理。

status
"tentative" | "confirmed"

指派狀態:tentative 預塞暫定/confirmed 正式確認。

請求
curl -X GET "https://your-tenant.example.com/api/v1/guide-roster/departures?month=<month>" \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "tripId": "…",
      "tripTitle": "…",
      "departureDate": "…",
      "returnDate": "…",
      "days": 0,
      "capacity": 0,
      "bookedCount": 0,
      "status": "…",
      "assignments": [
        {
          "id": "…",
          "guideId": "…",
          "guideName": "…",
          "role": "leader",
          "status": "tentative"
        }
      ]
    }
  ]
}

roster

GET/api/v1/guide-roster/guides
guide_roster.read

參數

month必填
string· 格式限定

查詢月份(YYYY-MM 格式)

includeInactive選填
boolean

是否一併列出已停用的嚮導(預設不列出)

回應欄位 · data[]

id
string

嚮導 id。

name
string

嚮導姓名。

rosterRole
"leader" | "assistant" | "both"

名冊職能:leader 領隊/assistant 隨隊助理/both 皆可。

specialties
string[]

可帶路線 / 專長;未設為空陣列。

status
string

嚮導狀態:active 啟用/inactive 停用。

maxDaysPerMonth
number | null

單月可帶上限(天);NULL = 不限。

monthDays
number

本月 confirmed 指派的帶團天數彙總。

monthTrips
number

本月 confirmed 帶團梯次數。

hasTentative
boolean

本月是否含 tentative(預塞)指派。

availability
Availability

派生載量狀態。

請求
curl -X GET "https://your-tenant.example.com/api/v1/guide-roster/guides?month=<month>" \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "name": "…",
      "rosterRole": "leader",
      "specialties": [
        "…"
      ],
      "status": "…",
      "maxDaysPerMonth": 0,
      "monthDays": 0,
      "monthTrips": 0,
      "hasTentative": true,
      "availability": "…"
    }
  ]
}

/guides

list/search guides

GET/api/v1/guides
guide.read

參數

slug選填
string· min 1

依嚮導公開頁網址代稱(slug)精確查單筆(選填)

status選填
enum
allactiveinactive

嚮導狀態篩選(all 全部/active 啟用/inactive 停用)

q選填
string

關鍵字搜尋(比對嚮導姓名等欄位)

page選填
integer

頁碼(從 1 起算)

pageSize選填
integer· max 200

每頁筆數(上限 200)

請求
curl -X GET https://your-tenant.example.com/api/v1/guides \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": "…"
}

create a guide

POST/api/v1/guides
guide.manage

參數

name必填
string· max 100 · min 1

嚮導/領隊姓名

slug選填
string· 格式限定

公開頁網址代稱(選填,小寫英數與連字號;省略則自動產生)

bio選填
string· max 20000

嚮導簡介/經歷(選填)

avatarUrl選填
string· max 500

大頭照圖片網址(選填,http/https)

specialties選填
string

專長領域(選填,以逗號分隔多項)

yearsExperience選填
integer· max 80 · min 0

帶團年資(年數,0~80;選填)

contactPhone選填
string· max 40

聯絡電話(選填)

contactEmail選填
string · email· max 120

聯絡 Email(選填)

status選填
enum
activeinactive

嚮導狀態(active 啟用/inactive 停用;預設 active)

回應欄位 · data

id
string

新建立的嚮導 id。

slug
string

嚮導公開頁網址代稱(未帶則系統自動產生)。

請求
curl -X POST https://your-tenant.example.com/api/v1/guides \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "<name>"
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…",
    "slug": "…"
  }
}

single guide detail

GET/api/v1/guides/{id}
guide.read

參數

id路徑
string· min 1

嚮導 ID

回應欄位 · data

id
string

嚮導 id(guide_ 前綴)。

name
string

嚮導/領隊姓名。

slug
string

公開頁網址代稱(slug;小寫英數與連字號)。

bio
string | null

簡介/經歷(可空)。

avatarUrl
string | null

大頭照圖片網址(可空)。

specialties
string[]

專長領域清單。

yearsExperience
number | null

帶團年資(年數;可空)。

contactPhone
string | null

聯絡電話(可空)。

contactEmail
string | null

聯絡 Email(可空)。

status
GuideStatus

嚮導狀態:active 啟用/inactive 停用。

engagementType
"external" | "full_time" | "partner"

僱用型態:full_time 正式/partner 協作/external 外聘。

createdAt
Date

建檔時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/guides/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "id": "…",
    "name": "…",
    "slug": "…",
    "bio": "…",
    "avatarUrl": "…",
    "specialties": [
      "…"
    ],
    "yearsExperience": 0,
    "contactPhone": "…",
    "contactEmail": "…",
    "status": "…",
    "engagementType": "external",
    "createdAt": "2026-06-30T08:00:00.000Z",
    "updatedAt": "2026-06-30T08:00:00.000Z"
  }
}

update a guide

PATCH/api/v1/guides/{id}
guide.manage

參數

id路徑
string· min 1

要更新的嚮導 ID

name選填
string· max 100 · min 1

嚮導/領隊姓名(省略則不更動)

slug選填
string· 格式限定

公開頁網址代稱(小寫英數與連字號;省略則不更動)

bio選填
string· max 20000

嚮導簡介/經歷(省略則不更動)

avatarUrl選填
string· max 500

大頭照圖片網址(http/https;省略則不更動)

specialties選填
string

專長領域(以逗號分隔多項;省略則不更動)

yearsExperience選填
integer· max 80 · min 0

帶團年資(年數,0~80;省略則不更動)

contactPhone選填
string· max 40

聯絡電話(省略則不更動)

contactEmail選填
string · email· max 120

聯絡 Email(省略則不更動)

status選填
enum
activeinactive

嚮導狀態(active 啟用/inactive 停用;省略則不更動)

回應欄位 · data

ok
boolean

更新成功旗標,恆為 true。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/guides/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

archive a guide

POST/api/v1/guides/{id}/archive
guide.manage

參數

id路徑
string· min 1

要封存(狀態改為停用)的嚮導 ID

回應欄位 · data

ok
boolean

封存成功旗標,恆為 true。

請求
curl -X POST https://your-tenant.example.com/api/v1/guides/<id>/archive \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

開通某既有 guide 的嚮導 portal 登入帳號

POST/api/v1/guides/{id}/invite-account
guide.manage

參數

id路徑
string· min 1

要開通登入帳號的嚮導 ID

email必填
string · email· max 120

嚮導 portal 登入帳號的 Email

name必填
string· max 100 · min 1

嚮導帳號的顯示姓名

回應欄位 · data

tempPassword
string

一次性明文暫時密碼(僅此次回傳,請立即轉交嚮導並要求首次登入改密)。

email
string

已開通登入帳號的 Email。

請求
curl -X POST https://your-tenant.example.com/api/v1/guides/<id>/invite-account \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "<email>",
    "name": "<name>"
  }'
回應
{
  "ok": true,
  "data": {
    "tempPassword": "…",
    "email": "…"
  }
}

/journal

list/search 嚮導手記 posts

GET/api/v1/journal
journal.read

參數

status選填
enum
alldraftpublishedarchived

依狀態篩選:all 全部、draft 草稿、published 已發佈、archived 已封存

q選填
string

關鍵字搜尋(標題/內容)

page選填
integer

頁碼(從 1 起)

pageSize選填
integer· max 200

每頁筆數(上限 200)

回應欄位 · data

rows
object[]

本頁的手記文章列表。

id
string

手記文章 id(journalPost_ 前綴)。

slug
string

文章公開頁網址代稱(slug)。

title
string

文章標題。

excerpt
string | null

摘要(列表/SEO 用;可空)。

coverImageUrl
string | null

封面圖網址(可空)。

contentMdx
string

內文原始 MDX 內容。

authorGuideId
`guide_${string}` | null

作者嚮導 id(未指定作者時 null)。

seoTitle
string | null

SEO 標題(覆寫 <title>;可空)。

seoDescription
string | null

SEO 描述(meta description;可空)。

ogImageUrl
string | null

Open Graph 分享圖網址(可空)。

status
JournalStatus

文章狀態:draft 草稿/published 已發佈/archived 已封存。

publishedAt
Date | null

首次發佈時間(尚未發佈為 null)。

createdAt
Date

建檔時間。

updatedAt
Date

最後更新時間。

total
number

符合條件的文章總數(跨頁)。

page
number

目前頁碼(從 1 起)。

pageSize
number

每頁筆數。

請求
curl -X GET https://your-tenant.example.com/api/v1/journal \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "rows": [
      {
        "id": "…",
        "slug": "…",
        "title": "…",
        "excerpt": "…",
        "coverImageUrl": "…",
        "contentMdx": "…",
        "authorGuideId": "…",
        "seoTitle": "…",
        "seoDescription": "…",
        "ogImageUrl": "…",
        "status": "…",
        "publishedAt": null,
        "createdAt": "2026-06-30T08:00:00.000Z",
        "updatedAt": "2026-06-30T08:00:00.000Z"
      }
    ],
    "total": 0,
    "page": 0,
    "pageSize": 0
  }
}

create a 嚮導手記 post

POST/api/v1/journal
journal.manage

參數

title必填
string· max 200 · min 1

手記標題,顯示於前台與後台列表

slug選填
string· 格式限定

網址代稱(slug);僅小寫英數與連字號,省略時由系統依標題產生

excerpt選填
string· max 1000

摘要,列表與分享預覽用;null 清除

coverImageUrl選填
string· max 500

封面圖網址(http/https);null 清除

contentMdx必填
string· max 100000 · min 1

內文(MDX 格式)

authorGuideId選填
string

作者嚮導 ID;null 表示無指定作者

seoTitle選填
string· max 200

SEO 標題,省略時用 title;null 清除

seoDescription選填
string· max 500

SEO 描述(meta description);null 清除

ogImageUrl選填
string· max 500

Open Graph 分享圖網址(http/https);null 清除

status選填
enum
draftpublishedarchived

發佈狀態:draft 草稿、published 已發佈、archived 已封存

回應欄位 · data

id
string

新建立的手記文章 id。

slug
string

文章公開頁網址代稱(slug)。

請求
curl -X POST https://your-tenant.example.com/api/v1/journal \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "<title>",
    "contentMdx": "<contentMdx>"
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…",
    "slug": "…"
  }
}

full 嚮導手記 post detail

GET/api/v1/journal/{id}
journal.read

參數

id路徑
string· min 1

嚮導手記文章 ID

回應欄位 · data

id
string

手記文章 id(journalPost_ 前綴)。

slug
string

文章公開頁網址代稱(slug)。

title
string

文章標題。

excerpt
string | null

摘要(列表/SEO 用;可空)。

coverImageUrl
string | null

封面圖網址(可空)。

contentMdx
string

內文原始 MDX 內容。

authorGuideId
`guide_${string}` | null

作者嚮導 id(未指定作者時 null)。

seoTitle
string | null

SEO 標題(覆寫 <title>;可空)。

seoDescription
string | null

SEO 描述(meta description;可空)。

ogImageUrl
string | null

Open Graph 分享圖網址(可空)。

status
JournalStatus

文章狀態:draft 草稿/published 已發佈/archived 已封存。

publishedAt
Date | null

首次發佈時間(尚未發佈為 null)。

createdAt
Date

建檔時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/journal/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "id": "…",
    "slug": "…",
    "title": "…",
    "excerpt": "…",
    "coverImageUrl": "…",
    "contentMdx": "…",
    "authorGuideId": "…",
    "seoTitle": "…",
    "seoDescription": "…",
    "ogImageUrl": "…",
    "status": "…",
    "publishedAt": null,
    "createdAt": "2026-06-30T08:00:00.000Z",
    "updatedAt": "2026-06-30T08:00:00.000Z"
  }
}

update a 嚮導手記 post

PATCH/api/v1/journal/{id}
journal.manage

參數

title必填
string· max 200 · min 1

手記標題,顯示於前台與後台列表

slug選填
string· 格式限定

網址代稱(slug);僅小寫英數與連字號,省略時由系統依標題產生

excerpt選填
string· max 1000

摘要,列表與分享預覽用;null 清除

coverImageUrl選填
string· max 500

封面圖網址(http/https);null 清除

contentMdx必填
string· max 100000 · min 1

內文(MDX 格式)

authorGuideId選填
string

作者嚮導 ID;null 表示無指定作者

seoTitle選填
string· max 200

SEO 標題,省略時用 title;null 清除

seoDescription選填
string· max 500

SEO 描述(meta description);null 清除

ogImageUrl選填
string· max 500

Open Graph 分享圖網址(http/https);null 清除

status選填
enum
draftpublishedarchived

發佈狀態:draft 草稿、published 已發佈、archived 已封存

id路徑
string· min 1

嚮導手記文章 ID

回應欄位 · data

ok
boolean

更新成功旗標,恆為 true。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/journal/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "<title>",
    "contentMdx": "<contentMdx>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

archive a 嚮導手記 post

POST/api/v1/journal/{id}/archive
journal.manage

參數

id路徑
string· min 1

嚮導手記文章 ID

回應欄位 · data

ok
boolean

封存成功旗標,恆為 true。

請求
curl -X POST https://your-tenant.example.com/api/v1/journal/<id>/archive \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

active guides as author options for journal

GET/api/v1/journal/authors
journal.read

回應欄位 · data[]

value
string

作者嚮導 id(作為選項值)。

label
string

顯示用的嚮導姓名。

請求
curl -X GET https://your-tenant.example.com/api/v1/journal/authors \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "value": "…",
      "label": "…"
    }
  ]
}

/rooms

指派旅客進房

POST/api/v1/rooms/{roomId}/travelers
departure.update

參數

roomId路徑
string· min 1

目標房間 ID,旅客將被指派入住此房

travelerId必填
string· min 1

欲指派的旅客 ID,須與房間屬於同一梯次

回應欄位 · data

ok
boolean

指派入房成功旗標,恆為 true。

請求
curl -X POST https://your-tenant.example.com/api/v1/rooms/<roomId>/travelers \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "travelerId": "<travelerId>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

把旅客移出房間

DELETE/api/v1/rooms/travelers/{travelerId}
departure.update

參數

travelerId路徑
string· min 1

欲移出房間的旅客 ID

回應欄位 · data

ok
boolean

移出房間成功旗標,恆為 true。

請求
curl -X DELETE https://your-tenant.example.com/api/v1/rooms/travelers/<travelerId> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

/exchange-rates

list the Bank-of-Taiwan published FX rate board

GET/api/v1/exchange-rates
account_transfer.read模組:accounting

參數

currency選填
string

幣別篩選(ISO 4217 三碼,如 JPY / USD);省略則回傳所有幣別

monthFrom選填
string· 格式限定

起始月份(YYYY-MM,含當月);省略則不設下界

monthTo選填
string· 格式限定

結束月份(YYYY-MM,含當月);省略則不設上界

回應欄位 · data[]

id
string

匯率牌價列 ID。

rateDate
string

掛牌日期('YYYY-MM-DD',Asia/Taipei)。

currency
string

ISO 4217('JPY' / 'IDR' / 'USD'…)。

cashBuy
string | null

各報價 canonical「1 外幣 = ? 台幣」(numeric → 字串原值保精度;NULL = 該幣別無此報價)。

cashSell
string | null

現金賣出匯率「1 外幣 = ? 台幣」(字串保精度;null = 無此報價)。

spotBuy
string | null

即期買入匯率「1 外幣 = ? 台幣」(字串保精度;null = 無此報價)。

spotSell
string | null

即期賣出匯率「1 外幣 = ? 台幣」(字串保精度;null = 無此報價)。

source
ExchangeRateSource

牌價來源:bot 台銀自動抓取 / manual 租戶手動覆蓋。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/exchange-rates \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "rateDate": "…",
      "currency": "…",
      "cashBuy": "…",
      "cashSell": "…",
      "spotBuy": "…",
      "spotSell": "…",
      "source": "…",
      "createdAt": "2026-06-30T08:00:00.000Z",
      "updatedAt": "2026-06-30T08:00:00.000Z"
    }
  ]
}

manual FX rate override

PUT/api/v1/exchange-rates/manual
account_transfer.manage

參數

rateDate必填
string· 格式限定

匯率掛牌日期(YYYY-MM-DD),與幣別共同決定覆蓋哪一筆牌價

currency必填
string· 格式限定

幣別(ISO 4217 三碼大寫,如 JPY / USD)

cashBuy選填
string· 格式限定

現金買入匯率(正數最多 6 位小數,以字串表達);四種報價至少填一個,留空傳 null

cashSell選填
string· 格式限定

現金賣出匯率(正數最多 6 位小數,以字串表達);四種報價至少填一個,留空傳 null

spotBuy選填
string· 格式限定

即期買入匯率(正數最多 6 位小數,以字串表達);四種報價至少填一個,留空傳 null

spotSell選填
string· 格式限定

即期賣出匯率(正數最多 6 位小數,以字串表達);四種報價至少填一個,留空傳 null

回應欄位 · data

ok
boolean

是否覆蓋寫入成功。

id
string

寫入 / 更新的 manual 匯率牌價列 ID。

請求
curl -X PUT https://your-tenant.example.com/api/v1/exchange-rates/manual \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "rateDate": "<rateDate>",
    "currency": "<currency>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "id": "…"
  }
}

resolve the canonical "1 foreign unit =

GET/api/v1/exchange-rates/resolve
account_transfer.read

參數

currency必填
string· min 1

要換算的外幣幣別(ISO 4217 三碼,如 JPY / USD)

date必填
string· 格式限定

換算基準日期(YYYY-MM-DD),套用手動優先 + 往前承接的解析規則

quote選填
enum
cash_buycash_sellspot_buyspot_sell

報價類型:cash_buy 現金買入、cash_sell 現金賣出、spot_buy 即期買入、spot_sell 即期賣出;省略預設 spot_sell

回應欄位 · data

currency
string

換算的外幣幣別(ISO 4217 三碼)。

date
string

換算基準日期(YYYY-MM-DD)。

quote
"cash_buy" | "cash_sell" | "spot_buy" | "spot_sell"

使用的報價類型(cash_buy / cash_sell / spot_buy / spot_sell)。

rate
string | null

解析出的匯率「1 外幣 = ? 台幣」(字串保精度);查無適用牌價為 null。

請求
curl -X GET "https://your-tenant.example.com/api/v1/exchange-rates/resolve?currency=<currency>&date=<date>" \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "currency": "…",
    "date": "…",
    "quote": "cash_buy",
    "rate": "…"
  }
}

/payment-requests

list/search/filter 對外應付

GET/api/v1/payment-requests
payable.read

參數

status選填
enum
draftsubmittedapprovedpaidrejectedcancelledall

依狀態篩選(draft 草稿 / submitted 已送審 / approved 已核准 / paid 已付款 / rejected 已退件 / cancelled 已取消 / all 全部)

payeeType選填
enum
supplierguidestaff_commissionotherall

依收款對象類型篩選(supplier 供應商 / guide 領隊嚮導 / staff_commission 員工獎金 / other 其他 / all 全部)

departureId選填
string

依關聯梯次 id 篩選

createdByUserId選填
string

依建單人 user id 篩選

q選填
string

關鍵字搜尋(請款單號、收款對象名稱等)

page選填
integer

頁碼(從 1 起算)

pageSize選填
integer· max 200

每頁筆數(上限 200)

回應欄位 · data

rows
object[]

本頁請款單列。

id
string

請款單 ID。

requestNumber
string

請款單號(人可讀,每租戶流水號)。

status
PaymentRequestStatus

核簽工作流狀態:draft / submitted / approved / paid / rejected / cancelled。

payeeType
PayeeType

收款對象類型:supplier 供應商 / guide 領隊嚮導 / staff_commission 員工獎金 / other 其他。

payeeName
string

收款對象名稱。

amountTwd
number

請款總額(TWD 整數;= 細項小計合計,代扣稅前)。

netAmountTwd
number

實付淨額(TWD 整數;= 請款總額 − 代扣稅額,即實際匯款金額)。

taxAmountTwd
number

代扣稅額(TWD 整數)。

departureId
string | null

關聯梯次 ID;未歸屬特定出團為 null。

departureLabel
string | null

關聯梯次顯示標籤(行程名稱+出發日);無則為 null。

description
string

請款單摘要說明。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

createdByUserId
string

建單人 user ID。

createdByName
string | null

建單人姓名;查無為 null。

paidAt
Date | null

標記付款完成時間;未付為 null。

submittedAt
Date | null

送審時間;未送審為 null。

approvedAt
Date | null

核准時間;未核准為 null。

total
number

符合篩選條件的總筆數(跨全部分頁)。

page
number

目前頁碼(從 1 起算)。

pageSize
number

每頁筆數。

請求
curl -X GET https://your-tenant.example.com/api/v1/payment-requests \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "rows": [
      {
        "id": "…",
        "requestNumber": "…",
        "status": "…",
        "payeeType": "…",
        "payeeName": "…",
        "amountTwd": 0,
        "netAmountTwd": 0,
        "taxAmountTwd": 0,
        "departureId": "…",
        "departureLabel": "…",
        "description": "…",
        "createdAt": "2026-06-30T08:00:00.000Z",
        "updatedAt": "2026-06-30T08:00:00.000Z",
        "createdByUserId": "…",
        "createdByName": "…",
        "paidAt": null,
        "submittedAt": null,
        "approvedAt": null
      }
    ],
    "total": 0,
    "page": 0,
    "pageSize": 0
  }
}
POST/api/v1/payment-requests
payable.create

參數

payeeType必填
enum
supplierguidestaff_commissionother

收款對象類型(supplier 供應商 / guide 領隊嚮導 / staff_commission 員工獎金 / other 其他)

payeeName必填
string· min 1

收款對象名稱

payeeBankAccount選填
string

收款銀行帳號

payeeBankName選填
string

收款銀行名稱

payeeBankBranch選填
string

收款銀行分行

payeeTaxId選填
string

收款對象統一編號 / 稅籍編號

departureId選填
string

關聯梯次 id(將此請款歸屬至特定出團)

description必填
string· min 1

請款單摘要說明

taxAmountTwd選填
integer

稅額(TWD),未填視為 0

items必填
array· min 1

請款細項陣列(至少一筆)

submitImmediately選填
boolean

是否建立後立即送審(true 則同交易送出,跳過草稿)

回應欄位 · data

id
string

新建立請款單的 id。

requestNumber
string

新建立請款單的單號(人可讀)。

status
PaymentRequestStatus

建立後狀態(draft,或 submitImmediately 時為 submitted)。

請求
curl -X POST https://your-tenant.example.com/api/v1/payment-requests \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "payeeType": "supplier",
    "payeeName": "<payeeName>",
    "description": "<description>",
    "items": []
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…",
    "requestNumber": "…",
    "status": "…"
  }
}

單一對外應付請款單完整明細

GET/api/v1/payment-requests/{id}
payable.read

參數

id路徑
string· min 1

請款單 id(路徑參數)

回應欄位 · data

payeeBankAccount
string | null

收款銀行帳號。

payeeBankName
string | null

收款銀行名稱。

payeeBankBranch
string | null

收款銀行分行。

payeeTaxId
string | null

收款對象統一編號 / 稅籍編號。

submittedByUserId
string | null

送審人 user ID;未送審為 null。

submittedByName
string | null

送審人姓名;無則為 null。

approvedByUserId
string | null

核准人 user ID;未核准為 null。

approvedByName
string | null

核准人姓名;無則為 null。

paidByUserId
string | null

標記付款人 user ID;未付為 null。

paidByName
string | null

標記付款人姓名;無則為 null。

rejectedAt
Date | null

退件時間;未退件為 null。

rejectedByName
string | null

退件人姓名;無則為 null。

rejectionReason
string | null

退件原因;無則為 null。

cancelledAt
Date | null

取消時間;未取消為 null。

cancelledByName
string | null

取消人姓名;無則為 null。

cancellationReason
string | null

取消原因;無則為 null。

pdfGeneratedAt
Date | null

請款單 PDF 產生時間;未產生為 null。

paperPrintedAt
Date | null

紙本列印時間;未列印為 null。

paperSignedBy
string | null

紙本簽核人;未簽為 null。

bankReference
string | null

銀行匯款交易參考號(付款後回填);無則為 null。

items
object[]

請款細項清單。

id
string

請款細項 ID。

category
string

細項類別(如住宿、交通、餐食)。

description
string

細項說明。

quantity
number

數量。

unitPriceTwd
number

單價(TWD 整數;負值表折讓)。

totalTwd
number

細項小計(TWD 整數;= 數量 × 單價)。

notes
string | null

細項備註;無則為 null。

sortOrder
number

顯示排序(由小到大)。

audit
object[]

稽核軌跡(狀態機每次轉移一筆,時間新到舊或建立序)。

id
string

稽核記錄 ID。

action
string

動作代號(如 payable.create、payable.submit、payable.approve)。

createdAt
Date

動作發生時間。

actorUserId
string | null

操作者 user ID;系統動作為 null。

actorName
string | null

操作者姓名;無則為 null。

metadata
unknown

動作附帶的結構化資料(欄位隨 action 而定)。

ipAddress
string | null

操作來源 IP;無則為 null。

id
string

請款單 ID。

requestNumber
string

請款單號(人可讀,每租戶流水號)。

status
PaymentRequestStatus

核簽工作流狀態:draft / submitted / approved / paid / rejected / cancelled。

payeeType
PayeeType

收款對象類型:supplier 供應商 / guide 領隊嚮導 / staff_commission 員工獎金 / other 其他。

payeeName
string

收款對象名稱。

amountTwd
number

請款總額(TWD 整數;= 細項小計合計,代扣稅前)。

netAmountTwd
number

實付淨額(TWD 整數;= 請款總額 − 代扣稅額,即實際匯款金額)。

taxAmountTwd
number

代扣稅額(TWD 整數)。

departureId
string | null

關聯梯次 ID;未歸屬特定出團為 null。

departureLabel
string | null

關聯梯次顯示標籤(行程名稱+出發日);無則為 null。

description
string

請款單摘要說明。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

createdByUserId
string

建單人 user ID。

createdByName
string | null

建單人姓名;查無為 null。

paidAt
Date | null

標記付款完成時間;未付為 null。

submittedAt
Date | null

送審時間;未送審為 null。

approvedAt
Date | null

核准時間;未核准為 null。

請求
curl -X GET https://your-tenant.example.com/api/v1/payment-requests/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "payeeBankAccount": "…",
    "payeeBankName": "…",
    "payeeBankBranch": "…",
    "payeeTaxId": "…",
    "submittedByUserId": "…",
    "submittedByName": "…",
    "approvedByUserId": "…",
    "approvedByName": "…",
    "paidByUserId": "…",
    "paidByName": "…",
    "rejectedAt": null,
    "rejectedByName": "…",
    "rejectionReason": "…",
    "cancelledAt": null,
    "cancelledByName": "…",
    "cancellationReason": "…",
    "pdfGeneratedAt": null,
    "paperPrintedAt": null,
    "paperSignedBy": "…",
    "bankReference": "…",
    "items": [
      {
        "id": "…",
        "category": "…",
        "description": "…",
        "quantity": 0,
        "unitPriceTwd": 0,
        "totalTwd": 0,
        "notes": "…",
        "sortOrder": 0
      }
    ],
    "audit": [
      {
        "id": "…",
        "action": "…",
        "createdAt": "2026-06-30T08:00:00.000Z",
        "actorUserId": "…",
        "actorName": "…",
        "metadata": "…",
        "ipAddress": "…"
      }
    ],
    "id": "…",
    "requestNumber": "…",
    "status": "…",
    "payeeType": "…",
    "payeeName": "…",
    "amountTwd": 0,
    "netAmountTwd": 0,
    "taxAmountTwd": 0,
    "departureId": "…",
    "departureLabel": "…",
    "description": "…",
    "createdAt": "2026-06-30T08:00:00.000Z",
    "updatedAt": "2026-06-30T08:00:00.000Z",
    "createdByUserId": "…",
    "createdByName": "…",
    "paidAt": null,
    "submittedAt": null,
    "approvedAt": null
  }
}

核可請款單

POST/api/v1/payment-requests/{id}/approve
payable.approve

參數

id路徑
string· min 1

請款單 id(路徑參數)

回應欄位 · data

ok
boolean

是否核可成功(submitted→approved)。

請求
curl -X POST https://your-tenant.example.com/api/v1/payment-requests/<id>/approve \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

取消請款單

POST/api/v1/payment-requests/{id}/cancel
payable.create

參數

id路徑
string· min 1

請款單 id(路徑參數)

reason選填
string

取消原因;留空預設為「使用者取消」(上限 200 字)

回應欄位 · data

ok
boolean

是否取消成功(idempotent,已取消再呼叫仍為 true)。

請求
curl -X POST https://your-tenant.example.com/api/v1/payment-requests/<id>/cancel \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

標記請款單已付

POST/api/v1/payment-requests/{id}/mark-paid
payable.mark_paid

參數

id路徑
string· min 1

請款單 id(路徑參數)

bankReference必填
string· min 1

網銀交易序號 / 轉帳憑證號(必填)

paperSignedBy選填
string

紙本簽核人姓名

receivingAccountId選填
string

出款帳戶 id(從哪個收款帳戶付出)

回應欄位 · data

ok
boolean

是否標記付款成功(approved→paid)。

請求
curl -X POST https://your-tenant.example.com/api/v1/payment-requests/<id>/mark-paid \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "bankReference": "<bankReference>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

標記 PDF/紙本已產生

POST/api/v1/payment-requests/{id}/mark-printed
payable.print

參數

id路徑
string· min 1

請款單 id(路徑參數)

回應欄位 · data

ok
boolean

是否標記 PDF / 紙本已產生成功(idempotent)。

請求
curl -X POST https://your-tenant.example.com/api/v1/payment-requests/<id>/mark-printed \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

記錄紙本簽核人

POST/api/v1/payment-requests/{id}/mark-signed
payable.create

參數

id路徑
string· min 1

請款單 id(路徑參數)

signedBy必填
string· min 1

紙本簽核人姓名(必填)

回應欄位 · data

ok
boolean

是否記錄紙本簽核人成功。

請求
curl -X POST https://your-tenant.example.com/api/v1/payment-requests/<id>/mark-signed \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "signedBy": "<signedBy>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

退件請款單

POST/api/v1/payment-requests/{id}/reject
payable.approve

參數

id路徑
string· min 1

請款單 id(路徑參數)

reason必填
string· min 1

退件原因(必填,回饋給建單人)

回應欄位 · data

ok
boolean

是否退件成功(submitted→draft)。

請求
curl -X POST https://your-tenant.example.com/api/v1/payment-requests/<id>/reject \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "<reason>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

送審請款單

POST/api/v1/payment-requests/{id}/submit
payable.create

參數

id路徑
string· min 1

請款單 id(路徑參數)

回應欄位 · data

ok
boolean

是否送審成功(draft→submitted)。

請求
curl -X POST https://your-tenant.example.com/api/v1/payment-requests/<id>/submit \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

對外應付請款單 KPI 計數

GET/api/v1/payment-requests/stats
payable.read

回應欄位 · data

draftCount
number

草稿狀態的請款單數。

submittedCount
number

已送審待核准的請款單數。

approvedCount
number

已核准待付款的請款單數。

paidCount
number

已付款的請款單數。

thisMonthPaidCount
number

本月已付款的請款單數。

thisMonthAmount
number

本月已付款的實付淨額合計(TWD 整數;台北月起算)。

totalApprovedAmount
number

已核准未付的實付淨額合計(TWD 整數;待出款金額)。

請求
curl -X GET https://your-tenant.example.com/api/v1/payment-requests/stats \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "draftCount": 0,
    "submittedCount": 0,
    "approvedCount": 0,
    "paidCount": 0,
    "thisMonthPaidCount": 0,
    "thisMonthAmount": 0,
    "totalApprovedAmount": 0
  }
}

由某梯次的

GET/api/v1/payment-requests/supplier-suggestions
payable.create

參數

departureId必填
string· min 1

梯次 id;用於推導該梯次住宿供應商的請款細項建議

回應欄位 · data[]

category
string

建議的請款細項類別(如住宿)。

description
string

建議的細項說明(住宿廠商 × 房型 × 晚數)。

quantity
number

建議數量(間數 × 晚數)。

unitPriceTwd
number

建議單價(TWD 整數;每間每晚成本)。

totalTwd
number

建議小計(TWD 整數;= 數量 × 單價)。

suggestedPayee
string | null

建議的收款對象(住宿供應商名稱);查無為 null。

請求
curl -X GET "https://your-tenant.example.com/api/v1/payment-requests/supplier-suggestions?departureId=<departureId>" \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "category": "…",
      "description": "…",
      "quantity": 0,
      "unitPriceTwd": 0,
      "totalTwd": 0,
      "suggestedPayee": "…"
    }
  ]
}

/payments

list/search/filter the customer→agency payment ledger

GET/api/v1/payments
payment.read

參數

status選填
string

依金流狀態篩選(如 paid 已收款 / pending 待付 / failed 失敗 / refunded 已退款)

method選填
string

依付款方式篩選(如信用卡、ATM 轉帳)

dateFrom選填
string

收款日期區間起日(YYYY-MM-DD)

dateTo選填
string

收款日期區間迄日(YYYY-MM-DD)

q選填
string

關鍵字搜尋(訂單編號、客戶名稱等)

page選填
integer

頁碼(從 1 起算)

pageSize選填
integer· max 200

每頁筆數(上限 200)

回應欄位 · data

rows
object[]

本頁付款嘗試列。

id
string

付款嘗試(payment attempt)ID,此列的唯一識別。

orderId
string

所屬訂單 ID。

orderNumber
string

所屬訂單編號(人可讀)。

merchantTradeNo
string

provider_order_ref(= 我們產的 MerchantTradeNo)。

providerTradeNo
string | null

金流商回傳的交易序號(未成交或手動入帳為 null)。

provider
string

金流商代號(如 ecpay、test;手動入帳為 manual)。

paymentMethod
string

付款方式(如信用卡、ATM 虛擬帳號)。

amountTwd
number

此筆嘗試的金額(TWD 整數)。

status
string

attempt 狀態:pending | submitted | succeeded | failed | expired。

refunded
boolean

此 attempt 是否關聯到任何退款 / 退單交易(out 方向)。

paidAt
Date | null

實際入帳(現金結算)時間;未結算為 null。

createdAt
Date

此筆付款嘗試的建立時間。

customerName
string

付款客戶姓名。

customerEmail
string

付款客戶 email。

tripTitle
string

訂單對應的行程名稱。

total
number

符合篩選條件的總筆數(跨全部分頁)。

page
number

目前頁碼(從 1 起算)。

pageSize
number

每頁筆數。

請求
curl -X GET https://your-tenant.example.com/api/v1/payments \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "rows": [
      {
        "id": "…",
        "orderId": "…",
        "orderNumber": "…",
        "merchantTradeNo": "…",
        "providerTradeNo": "…",
        "provider": "…",
        "paymentMethod": "…",
        "amountTwd": 0,
        "status": "…",
        "refunded": true,
        "paidAt": null,
        "createdAt": "2026-06-30T08:00:00.000Z",
        "customerName": "…",
        "customerEmail": "…",
        "tripTitle": "…"
      }
    ],
    "total": 0,
    "page": 0,
    "pageSize": 0
  }
}

匯出金流分類帳

GET/api/v1/payments/export
payment.read

參數

status選填
string

依金流狀態篩選(如 paid 已收款 / pending 待付 / failed 失敗 / refunded 已退款)

method選填
string

依付款方式篩選(如信用卡、ATM 轉帳)

dateFrom選填
string

收款日期區間起日(YYYY-MM-DD)

dateTo選填
string

收款日期區間迄日(YYYY-MM-DD)

q選填
string

關鍵字搜尋(訂單編號、客戶名稱等)

回應欄位 · data

rows
object[]

符合篩選條件的所有列(逐頁累積;達安全上限時截斷)。

id
string

付款嘗試(payment attempt)ID,此列的唯一識別。

orderId
string

所屬訂單 ID。

orderNumber
string

所屬訂單編號(人可讀)。

merchantTradeNo
string

provider_order_ref(= 我們產的 MerchantTradeNo)。

providerTradeNo
string | null

金流商回傳的交易序號(未成交或手動入帳為 null)。

provider
string

金流商代號(如 ecpay、test;手動入帳為 manual)。

paymentMethod
string

付款方式(如信用卡、ATM 虛擬帳號)。

amountTwd
number

此筆嘗試的金額(TWD 整數)。

status
string

attempt 狀態:pending | submitted | succeeded | failed | expired。

refunded
boolean

此 attempt 是否關聯到任何退款 / 退單交易(out 方向)。

paidAt
Date | null

實際入帳(現金結算)時間;未結算為 null。

createdAt
Date

此筆付款嘗試的建立時間。

customerName
string

付款客戶姓名。

customerEmail
string

付款客戶 email。

tripTitle
string

訂單對應的行程名稱。

total
number

符合篩選條件的總筆數。

truncated
boolean

是否因達安全上限而截斷(true 表未回傳完整結果,呼叫端應提示)。

請求
curl -X GET https://your-tenant.example.com/api/v1/payments/export \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "rows": [
      {
        "id": "…",
        "orderId": "…",
        "orderNumber": "…",
        "merchantTradeNo": "…",
        "providerTradeNo": "…",
        "provider": "…",
        "paymentMethod": "…",
        "amountTwd": 0,
        "status": "…",
        "refunded": true,
        "paidAt": null,
        "createdAt": "2026-06-30T08:00:00.000Z",
        "customerName": "…",
        "customerEmail": "…",
        "tripTitle": "…"
      }
    ],
    "total": 0,
    "truncated": true
  }
}

payment KPI counts

GET/api/v1/payments/stats
payment.read

回應欄位 · data

totalAmount
number

累計實收現金(payment_transactions in)。

paidCount
number

已成功收款的付款嘗試數。

pendingCount
number

待付 / 處理中的付款嘗試數(pending、submitted)。

failedCount
number

失敗或逾期的付款嘗試數(failed、expired)。

refundedCount
number

有關聯退款 / 退單的付款嘗試數。

thisMonthAmount
number

本月累計實收現金(TWD 整數)。

請求
curl -X GET https://your-tenant.example.com/api/v1/payments/stats \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "totalAmount": 0,
    "paidCount": 0,
    "pendingCount": 0,
    "failedCount": 0,
    "refundedCount": 0,
    "thisMonthAmount": 0
  }
}

/reconciliation

逐收款帳戶現金進出對帳

GET/api/v1/reconciliation/accounts
receiving_account.read

參數

dateFrom選填
string

對帳期間起日(YYYY-MM-DD,含當日),以 Asia/Taipei 牆鐘日界計;省略則不設下界

dateTo選填
string

對帳期間迄日(YYYY-MM-DD,含整日),以 Asia/Taipei 牆鐘日界計;省略則不設上界

回應欄位 · data[]

accountId
string | null

收款帳戶 id;null = 未歸戶桶。

code
string | null

帳戶代碼;未歸戶桶為 null。

displayName
string | null

帳戶顯示名;未歸戶桶為 null。

kind
ReceivingAccountKind | null

帳戶類型(bank / cash / gateway);未歸戶桶為 null。

inTwd
number

期間內 direction='in' 的金額合計。

outTwd
number

期間內 payment_transactions direction='out' 的金額合計(客戶退款 / gateway 出)。

payableOutTwd
number

期間內供應商出款合計(payables paid 的 net_amount_twd;非 order-scoped,獨立來源 §3.1)。

netTwd
number

淨額 = in − out − payableOut(不扣手續費,純現金流向;對帳找銀行入帳用毛額)。

txCount
number

期間內這帳戶的活動筆數(payment_transactions + payables paid)。

請求
curl -X GET https://your-tenant.example.com/api/v1/reconciliation/accounts \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "accountId": "…",
      "code": "…",
      "displayName": "…",
      "kind": null,
      "inTwd": 0,
      "outTwd": 0,
      "payableOutTwd": 0,
      "netTwd": 0,
      "txCount": 0
    }
  ]
}

未結掛帳追蹤

GET/api/v1/reconciliation/obligations
account_settlement.read模組:accounting

參數

period選填
string

月結來源期間(YYYY-MM),篩選由該期月結互抵推導出的掛帳;省略則不限期間

reason選填
string

掛帳原因代碼,篩選特定成因的掛帳;省略則不限原因

status選填
string

掛帳狀態(如未結清 / 已結清),篩選特定結清狀態;省略則含全部

回應欄位 · data[]

id
string

帳戶間掛帳 ID。

debtorAccountId
string

欠款方(債務人)收款帳戶 ID。

creditorAccountId
string

收款方(債權人)收款帳戶 ID。

amountTwd
number

應補目標總額(TWD 整數,恆正)。

settledAmountTwd
number

已結清金額(TWD 整數,0 ≤ settled ≤ amount)。

outstandingTwd
number

待結餘額(派生 = amount − settled,>= 0)。

reason
ObligationReason

掛帳成因:period_settlement 月結互抵 / advance_repayment 代墊償還 / refund_advance 退款代墊 / adjustment 手動調整。

originPeriod
string

產生月份(YYYY-MM,Asia/Taipei)。

status
ObligationStatus

結清狀態:outstanding 未結 / partially_settled 部分結清 / settled 已結清。

note
string | null

備註;無則為 null。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/reconciliation/obligations \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "debtorAccountId": "…",
      "creditorAccountId": "…",
      "amountTwd": 0,
      "settledAmountTwd": 0,
      "outstandingTwd": 0,
      "reason": "…",
      "originPeriod": "…",
      "status": "…",
      "note": "…",
      "createdAt": "2026-06-30T08:00:00.000Z",
      "updatedAt": "2026-06-30T08:00:00.000Z"
    }
  ]
}

收款帳戶目錄清單

GET/api/v1/reconciliation/receiving-accounts
receiving_account.read

參數

activeOnly選填
boolean

是否只回傳啟用中的收款帳戶(true/false);省略則含停用

回應欄位 · data[]

id
string

收款帳戶 ID。

code
string

帳戶代碼(租戶內唯一穩定識別)。

displayName
string

帳戶顯示名。

kind
ReceivingAccountKind

帳戶類型:bank 銀行 / cash 現金 / gateway 金流閘道。

bankName
string | null

銀行名稱;現金/閘道帳戶為 null。

accountNo
string | null

銀行帳號;現金/閘道帳戶為 null。

canReceive
boolean

可收款(幾乎都 true)。

canRemit
boolean

可對外匯款(ATM / 匯出退款 / 補款匯出)。荒野只有永豐。

canChargeback
boolean

可刷退(退回原信用卡)。荒野只有綠界(gateway)。

isDeprecated
boolean

廢帳戶:仍可零星收款,但其收款需由他帳戶代墊歸集。荒野=RU 台銀 / 登山社。

isSettlementMaster
boolean

主結算帳戶:所有資金最終向它彙整。每租戶恰一個(partial unique index)。荒野=永豐。

currency
string

帳戶幣別(ISO 4217;既有帳戶皆 'TWD',外幣帳戶如 IDR / USD)。

isActive
boolean

此帳戶是否啟用。

displayOrder
number

後台清單排序序位(小者在前)。

usedCount
number

被多少 payment_transactions 引用(UI 鎖頭 / 「使用中 N」)。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/reconciliation/receiving-accounts \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "code": "…",
      "displayName": "…",
      "kind": "…",
      "bankName": "…",
      "accountNo": "…",
      "canReceive": true,
      "canRemit": true,
      "canChargeback": true,
      "isDeprecated": true,
      "isSettlementMaster": true,
      "currency": "…",
      "isActive": true,
      "displayOrder": 0,
      "usedCount": 0,
      "createdAt": "2026-06-30T08:00:00.000Z",
      "updatedAt": "2026-06-30T08:00:00.000Z"
    }
  ]
}

退款執行清單

GET/api/v1/reconciliation/refund-executions
account_settlement.read模組:accounting

參數

status選填
enum
approvedpaid

退款狀態篩選:approved 待執行(已核准)、paid 已執行(已出款);省略則合併回傳兩者

回應欄位 · data

rows
object[]

退款執行列(合併 approved 待執行 + paid 已執行,或收斂為指定段)。

id
string

退款單 ID。

refundNumber
string

退款單號(人可讀,每租戶流水號)。

orderId
string

所屬訂單 ID。

orderNumber
string | null

所屬訂單編號(人可讀);無則為 null。

status
RefundStatus

退款工作流狀態:draft / submitted / approved / processing / paid / failed / cancelled。

refundKind
RefundKind

退款種類:receivable_reduction 減應收退款(取消 / 降價 / 服務失敗)/ overpayment_return 溢收退還(不動應收,只退多收現金)。

affectsReceivable
boolean

是否減少應收(receivable_reduction 為 true、overpayment_return 為 false;溢收退還不列入 refund_state)。

amountTwd
number

退款金額(TWD 整數,正值)。

method
RefundMethod

退款方式:original_gateway 原路退刷 / bank_transfer 銀行匯款 / cash 現金 / manual 手動。

reason
string

退款原因說明。

createdAt
Date

退款單建立時間。

paidAt
Date | null

實際退款出款(現金結算)時間;未執行為 null。

createdByName
string | null

建單人姓名;無則為 null。

executionMethod
RefundExecutionMethod | null

退款執行方法:chargeback 原信用卡刷退 / remit 匯出;未指定為 null。

originAccountId
string | null

出款來源帳戶 ID(從哪個收款帳戶退出);未指定為 null。

adminFeeTwd
number

內扣手續費(TWD 整數;自退款金額中扣除的行政費)。

remitFeeTwd
number

匯款手續費(TWD 整數;銀行匯出的轉帳費)。

payeeAccountName
string | null

收款人戶名(匯款退款用);無則為 null。

payeeBankCode
string | null

收款銀行代碼(匯款退款用);無則為 null。

payeeAccountNumber
string | null

收款帳號(匯款退款用);無則為 null。

total
number

回傳的退款執行筆數。

請求
curl -X GET https://your-tenant.example.com/api/v1/reconciliation/refund-executions \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "rows": [
      {
        "id": "…",
        "refundNumber": "…",
        "orderId": "…",
        "orderNumber": "…",
        "status": "…",
        "refundKind": "…",
        "affectsReceivable": true,
        "amountTwd": 0,
        "method": "…",
        "reason": "…",
        "createdAt": "2026-06-30T08:00:00.000Z",
        "paidAt": null,
        "createdByName": "…",
        "executionMethod": null,
        "originAccountId": "…",
        "adminFeeTwd": 0,
        "remitFeeTwd": 0,
        "payeeAccountName": "…",
        "payeeBankCode": "…",
        "payeeAccountNumber": "…"
      }
    ],
    "total": 0
  }
}

子系統 B 月結互抵派生總覽

GET/api/v1/reconciliation/settlement-overview
account_settlement.read模組:accounting

參數

period必填
string· 格式限定

要查詢月結互抵總覽的結算期(YYYY-MM)

回應欄位 · data

period
string

結算月份(YYYY-MM,Asia/Taipei)。

matrix
object

兩層互抵矩陣(各帳戶對主結算帳戶的有向淨額 + 未分類彙總)。

lines
object[]

各帳戶對主結算帳戶(或其類別 final)的有向淨額;恆正、方向由 debtor/creditor。

unclassified
object

未分類(未標費用類型)收款彙總,不進互抵,供 UI 提示補 tag。

obligations
object[]

本期相關掛帳(period_settlement,含結清進度)。

id
string

帳戶間掛帳 ID。

debtorAccountId
string

欠款方(債務人)收款帳戶 ID。

creditorAccountId
string

收款方(債權人)收款帳戶 ID。

amountTwd
number

應補目標總額(TWD 整數,恆正)。

settledAmountTwd
number

已結清金額(TWD 整數,0 ≤ settled ≤ amount)。

outstandingTwd
number

待結餘額(派生 = amount − settled,>= 0)。

reason
ObligationReason

掛帳成因:period_settlement 月結互抵 / advance_repayment 代墊償還 / refund_advance 退款代墊 / adjustment 手動調整。

originPeriod
string

產生月份(YYYY-MM,Asia/Taipei)。

status
ObligationStatus

結清狀態:outstanding 未結 / partially_settled 部分結清 / settled 已結清。

note
string | null

備註;無則為 null。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

carriedForward
object

跨期掛帳結轉基數(上期未結 period_settlement 殘額,已種入 matrix 淨額;此處供顯示明細 + 小計)。

lines
object[]

上期未結 period_settlement 殘額逐筆明細(已種入本期互抵基數)。

totalTwd
number

結轉殘額小計(TWD 整數)。

請求
curl -X GET "https://your-tenant.example.com/api/v1/reconciliation/settlement-overview?period=<period>" \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "period": "…",
    "matrix": {
      "lines": [],
      "unclassified": "…"
    },
    "obligations": [
      {
        "id": "…",
        "debtorAccountId": "…",
        "creditorAccountId": "…",
        "amountTwd": 0,
        "settledAmountTwd": 0,
        "outstandingTwd": 0,
        "reason": "…",
        "originPeriod": "…",
        "status": "…",
        "note": "…",
        "createdAt": "2026-06-30T08:00:00.000Z",
        "updatedAt": "2026-06-30T08:00:00.000Z"
      }
    ],
    "carriedForward": {
      "lines": [],
      "totalTwd": 0
    }
  }
}

跑當期月結互抵派生 + upsert

POST/api/v1/reconciliation/settlement/compute
account_settlement.read模組:accounting

參數

period必填
string· 格式限定

要計算月結互抵的結算期(YYYY-MM),可重跑且冪等(不回退已結額)

回應欄位 · data

period
string

結算月份(YYYY-MM,Asia/Taipei)。

matrix
object

兩層互抵矩陣(各帳戶對主結算帳戶的有向淨額 + 未分類彙總)。

lines
object[]

各帳戶對主結算帳戶(或其類別 final)的有向淨額;恆正、方向由 debtor/creditor。

unclassified
object

未分類(未標費用類型)收款彙總,不進互抵,供 UI 提示補 tag。

upserts
object[]

本次 run 對每條互抵列 upsert 的結果(含冪等護欄調整)。

debtorAccountId
string

欠款方(債務人)收款帳戶 ID。

creditorAccountId
string

收款方(債權人)收款帳戶 ID。

derivedAmountTwd
number

本次派生的目標淨額。

appliedAmountTwd
number

實際落地的掛帳 amount_twd(受冪等護欄約束,不低於已 settled)。

obligationId
string

對應的帳戶間掛帳 ID(本次 upsert 的目標列)。

action
"created" | "updated" | "floored_to_settled"

本次動作:created 新建 / updated 更新 / floored_to_settled 派生低於已結被護欄下限鎖住。

adjustmentTwd
number

派生目標低於已結額、被 floor 時的差額(保留為 adjustment 線索;> 0 表示有缺口)。

adjustmentObligationId
string | null

floor 缺口另記的 adjustment 掛帳 id(action='floored_to_settled' 時非 null)。

deletedObligationIds
string[]

本次 run 刪除的失效派生掛帳 id(settled=0 且不在新派生)。

請求
curl -X POST https://your-tenant.example.com/api/v1/reconciliation/settlement/compute \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "period": "<period>"
  }'
回應
{
  "ok": true,
  "data": {
    "period": "…",
    "matrix": {
      "lines": [],
      "unclassified": "…"
    },
    "upserts": [
      {
        "debtorAccountId": "…",
        "creditorAccountId": "…",
        "derivedAmountTwd": 0,
        "appliedAmountTwd": 0,
        "obligationId": "…",
        "action": "created",
        "adjustmentTwd": 0,
        "adjustmentObligationId": "…"
      }
    ],
    "deletedObligationIds": [
      "…"
    ]
  }
}
GET/api/v1/reconciliation/statement-imports
bank_statement.read模組:accounting

參數

account必填
string· min 1

收款帳戶 ID,回傳該帳戶的對帳單批次 / 行 / 進度彙總

回應欄位 · data

imports
object[]

該帳戶的對帳單批次清單(新到舊)。

id
string

對帳單批次 ID。

periodStart
string

批次期間起日('YYYY-MM-DD',含當日)。

periodEnd
string

批次期間迄日('YYYY-MM-DD',含當日)。

filename
string

匯入的檔名。

createdAt
Date

匯入時間。

lineCount
number

批內總行數。

autoCount
number

自動配對的行數。

manualCount
number

人工配對的行數。

unmatchedCount
number

尚未配對的行數。

ignoredCount
number

已略過(ignored)的行數。

excludedCount
number

已解除配對(excluded)的行數。

lines
object[]

該帳戶所有對帳單行(跨批次)。

id
string

對帳單行 ID。

importId
string

所屬對帳單批次 ID。

lineNo
number

檔案內行號(1 起算)。

txnDate
string

交易日期('YYYY-MM-DD')。

direction
"out" | "in"

現金流向:in 存入 / out 支出。

amountTwd
number

金額(TWD 整數)。

memo
string

摘要 / 備註文字。

status
string

配對狀態:unmatched 未配 / auto 自動 / manual 人工 / ignored 略過 / excluded 已解除。

matchedSourceType
string | null

已配對來源種類(payment_transaction / payable / account_transfer);未配為 null。

matchedSourceId
string | null

已配對來源 ID;未配為 null。

ignoredReason
string | null

略過原因;非 ignored 為 null。

progress
object

配對進度彙總。

total
number

總行數。

matched
number

已配對行數(auto + manual)。

unmatched
number

未配對行數。

ignored
number

已略過行數。

excluded
number

已解除配對行數。

請求
curl -X GET "https://your-tenant.example.com/api/v1/reconciliation/statement-imports?account=<account>" \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "imports": [
      {
        "id": "…",
        "periodStart": "…",
        "periodEnd": "…",
        "filename": "…",
        "createdAt": "2026-06-30T08:00:00.000Z",
        "lineCount": 0,
        "autoCount": 0,
        "manualCount": 0,
        "unmatchedCount": 0,
        "ignoredCount": 0,
        "excludedCount": 0
      }
    ],
    "lines": [
      {
        "id": "…",
        "importId": "…",
        "lineNo": 0,
        "txnDate": "…",
        "direction": "out",
        "amountTwd": 0,
        "memo": "…",
        "status": "…",
        "matchedSourceType": "…",
        "matchedSourceId": "…",
        "ignoredReason": "…"
      }
    ],
    "progress": {
      "total": 0,
      "matched": 0,
      "unmatched": 0,
      "ignored": 0,
      "excluded": 0
    }
  }
}
POST/api/v1/reconciliation/statement-imports
bank_statement.manage模組:accounting

參數

receivingAccountId必填
string· min 1

收款帳戶 ID(僅支援 TWD 的 bank / cash 帳戶)

periodStart必填
string· 格式限定

對帳單期間起日(含當日)

periodEnd必填
string· 格式限定

對帳單期間迄日(含當日)

filename必填
string· min 1

上傳檔名,副檔名須為 .xlsx 或 .csv

contentBase64必填
string· min 1

對帳單檔案內容的 base64 編碼字串(固定範本填好後另存)

回應欄位 · data

importId
string

新建立的對帳單批次 ID。

autoMatched
number

匯入後即自動配對成功的行數。

unmatched
number

匯入後仍未配對的行數。

請求
curl -X POST https://your-tenant.example.com/api/v1/reconciliation/statement-imports \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "receivingAccountId": "<receivingAccountId>",
    "periodStart": "<periodStart>",
    "periodEnd": "<periodEnd>",
    "filename": "<filename>",
    "contentBase64": "<contentBase64>"
  }'
回應
{
  "ok": true,
  "data": {
    "importId": "…",
    "autoMatched": 0,
    "unmatched": 0
  }
}

刪整批

DELETE/api/v1/reconciliation/statement-imports/{importId}
bank_statement.manage模組:accounting

參數

importId路徑
string· min 1

對帳單批次 ID

回應欄位 · data

ok
boolean

是否刪除整批成功(批內無人工痕跡才可刪)。

請求
curl -X DELETE https://your-tenant.example.com/api/v1/reconciliation/statement-imports/<importId> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

對該批

POST/api/v1/reconciliation/statement-imports/{importId}/auto-match
bank_statement.manage模組:accounting

參數

importId路徑
string· min 1

對帳單批次 ID

回應欄位 · data

matched
number

本輪新增自動配對的行數。

請求
curl -X POST https://your-tenant.example.com/api/v1/reconciliation/statement-imports/<importId>/auto-match \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "matched": 0
  }
}

某帳戶內、未被

GET/api/v1/reconciliation/statement-imports/candidates
bank_statement.read模組:accounting

參數

account必填
string· min 1

收款帳戶 ID,回傳該帳戶未配對的 ERP 現金流水候選

回應欄位 · data[]

sourceType
ErpSourceType

ERP 來源種類:payment_transaction 收款交易 / payable 出款 / account_transfer 帳戶移轉。

sourceId
string

ERP 來源紀錄 ID。

date
string

'YYYY-MM-DD'(Asia/Taipei 牆鐘日)。

direction
"out" | "in"

現金流向:in 進帳 / out 出帳。

amountTwd
number

金額(TWD 整數)。

label
string

顯示標籤(來源摘要,供人工配對時辨識)。

請求
curl -X GET "https://your-tenant.example.com/api/v1/reconciliation/statement-imports/candidates?account=<account>" \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "sourceType": "…",
      "sourceId": "…",
      "date": "…",
      "direction": "out",
      "amountTwd": 0,
      "label": "…"
    }
  ]
}

銀行對帳單匯入固定範本下載

GET/api/v1/reconciliation/statement-imports/template
bank_statement.read模組:accounting

回應欄位 · data

filename
string

建議另存的檔名(.xlsx,含日期戳)。

contentBase64
string

範本 .xlsx 內容的 base64 編碼字串(CLI 端解碼另存)。

請求
curl -X GET https://your-tenant.example.com/api/v1/reconciliation/statement-imports/template \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "filename": "…",
    "contentBase64": "…"
  }
}

兩階段匯入的第一階段 dry-run

POST/api/v1/reconciliation/statement-imports/validate
bank_statement.manage模組:accounting

參數

receivingAccountId必填
string· min 1

收款帳戶 ID(僅支援 TWD 的 bank / cash 帳戶)

periodStart必填
string· 格式限定

對帳單期間起日(含當日)

periodEnd必填
string· 格式限定

對帳單期間迄日(含當日)

filename必填
string· min 1

上傳檔名,副檔名須為 .xlsx 或 .csv

contentBase64必填
string· min 1

對帳單檔案內容的 base64 編碼字串

回應欄位 · data

accountId
string

對帳的收款帳戶 ID。

periodStart
string

對帳單期間起日('YYYY-MM-DD',含當日)。

periodEnd
string

對帳單期間迄日('YYYY-MM-DD',含當日)。

filename
string

上傳檔名。

lines
object[]

解析後的各行預覽(含「若 commit 是否會被自動配對」)。

lineNo
number

檔案內行號(1 起算)。

txnDate
string

交易日期('YYYY-MM-DD')。

direction
"out" | "in"

現金流向:in 存入 / out 支出。

amountTwd
number

金額(TWD 整數)。

memo
string

摘要 / 備註文字。

willAuto
boolean

若現在 commit,這行是否會被自動配對(同語意孤立邊)。

parseErrors
object[]

解析錯誤 + 期間外的行(依行號排序;commit 端會 fail-closed 拒)。

lineNo
number

出錯的對帳單行號(原始列,從 1 起算)。

message
string

錯誤說明(解析失敗原因或期間外提示)。

willAutoCount
number

若現在 commit,預計會被自動配對的行數。

willUnmatchedCount
number

若現在 commit,預計仍未配對的行數。

periodOverlap
boolean

宣告期間是否與既有批次重疊(commit 會被擋)。

請求
curl -X POST https://your-tenant.example.com/api/v1/reconciliation/statement-imports/validate \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "receivingAccountId": "<receivingAccountId>",
    "periodStart": "<periodStart>",
    "periodEnd": "<periodEnd>",
    "filename": "<filename>",
    "contentBase64": "<contentBase64>"
  }'
回應
{
  "ok": true,
  "data": {
    "accountId": "…",
    "periodStart": "…",
    "periodEnd": "…",
    "filename": "…",
    "lines": [
      {
        "lineNo": 0,
        "txnDate": "…",
        "direction": "out",
        "amountTwd": 0,
        "memo": "…",
        "willAuto": true
      }
    ],
    "parseErrors": [
      {
        "lineNo": 0,
        "message": "…"
      }
    ],
    "willAutoCount": 0,
    "willUnmatchedCount": 0,
    "periodOverlap": true
  }
}

略過一條對帳單行 →

POST/api/v1/reconciliation/statement-lines/{lineId}/ignore
bank_statement.manage模組:accounting

參數

lineId路徑
string· min 1

對帳單行 ID

reason必填
string· min 1

略過原因(必填;如「手續費」「利息」)

回應欄位 · data

ok
boolean

是否標記略過成功(狀態轉為 ignored)。

請求
curl -X POST https://your-tenant.example.com/api/v1/reconciliation/statement-lines/<lineId>/ignore \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "<reason>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

人工配對一條對帳單行到指定

POST/api/v1/reconciliation/statement-lines/{lineId}/match
bank_statement.manage模組:accounting

參數

lineId路徑
string· min 1

對帳單行 ID

sourceType必填
enum

配對來源種類:payment_transaction / payable / account_transfer

sourceId必填
string· min 1

配對來源 ID(該帳戶內未被配對的 ERP 候選)

回應欄位 · data

ok
boolean

是否人工配對成功(同帳戶 / 同金額 / 同方向)。

請求
curl -X POST https://your-tenant.example.com/api/v1/reconciliation/statement-lines/<lineId>/match \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "sourceType": "<sourceType>",
    "sourceId": "<sourceId>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

解除配對 → 'excluded'

POST/api/v1/reconciliation/statement-lines/{lineId}/unmatch
bank_statement.manage模組:accounting

參數

lineId路徑
string· min 1

對帳單行 ID

回應欄位 · data

ok
boolean

是否解除配對成功(狀態轉為 excluded)。

請求
curl -X POST https://your-tenant.example.com/api/v1/reconciliation/statement-lines/<lineId>/unmatch \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

帳戶間移轉統一分類帳查詢

GET/api/v1/reconciliation/transfers
account_settlement.read

參數

kind選填
string

移轉類型篩選(fx_conversion 換匯 / replenishment 補款 / advance 代墊 / backfill 回填 / refund_payout 退款匯出 / reversal 沖正);省略則含全部

account選填
string

帳戶 ID 篩選,回傳該帳戶為出帳或進帳方的移轉;省略則不限帳戶

dateFrom選填
string

移轉日期起日(YYYY-MM-DD,含當日);省略則不設下界

dateTo選填
string

移轉日期迄日(YYYY-MM-DD,含當日);省略則不設上界

settlementPeriod選填
string

對應月結期間(YYYY-MM)篩選;省略則不限月結

obligation選填
string

掛帳 ID 篩選,回傳沖減該筆掛帳的移轉;省略則不限掛帳

回應欄位 · data[]

id
string

帳戶間移轉 ID。

kind
AccountTransferKind

移轉類型:fx_conversion 換匯 / replenishment 補款 / advance 代墊 / backfill 回填 / refund_payout 退款匯出 / opening 期初 / reversal 沖正。

fromAccountId
string | null

出帳帳戶 ID;期初等單邊移轉為 null。

toAccountId
string | null

進帳帳戶 ID;單邊移轉為 null。

amountTwd
number

移轉金額(TWD 整數)。

feeTwd
number

手續費(TWD 整數)。

currency
string | null

外幣幣別(ISO 4217;純台幣移轉為 null)。

foreignAmount
number | null

外幣金額(整數;非外幣移轉為 null)。

feeForeign
number | null

外幣手續費(整數;無則為 null)。

grossRate
string | null

換匯牌價(numeric → 字串原值保精度;顯示/溯源用)。

settlementPeriod
string | null

對應月結期間(YYYY-MM);未歸屬月結為 null。

obligationId
string | null

沖減的帳戶間掛帳 ID;未沖減掛帳為 null。

reversesTransferId
string | null

被本筆沖正的原移轉 ID(kind='reversal' 時非 null)。

occurredAt
string

移轉日期('YYYY-MM-DD',date 欄)。

note
string | null

備註;無則為 null。

createdByUserId
string

登錄人 user ID。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/reconciliation/transfers \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "kind": "…",
      "fromAccountId": "…",
      "toAccountId": "…",
      "amountTwd": 0,
      "feeTwd": 0,
      "currency": "…",
      "foreignAmount": 0,
      "feeForeign": 0,
      "grossRate": "…",
      "settlementPeriod": "…",
      "obligationId": "…",
      "reversesTransferId": "…",
      "occurredAt": "…",
      "note": "…",
      "createdByUserId": "…",
      "createdAt": "2026-06-30T08:00:00.000Z",
      "updatedAt": "2026-06-30T08:00:00.000Z"
    }
  ]
}
POST/api/v1/reconciliation/transfers
account_transfer.manage模組:accounting

參數

kind選填
enum· 前處理正規化(省略則補預設 / null)

移轉類型:fx_conversion 換匯、replenishment 補款、advance 代墊、backfill 回填、refund_payout 退款匯出、reversal 沖正

fromAccountId選填
string· min 1 · 前處理正規化

出帳(轉出)帳戶 ID;與進帳帳戶至少填一個,null 表示無出帳方

toAccountId選填
string· min 1 · 前處理正規化

進帳(轉入)帳戶 ID;與出帳帳戶至少填一個,null 表示無進帳方

amountTwd選填
integer· 前處理正規化(省略則補預設 / null)

移轉台幣淨額(整數,不可為負);沖減掛帳時須大於 0

feeTwd選填
integer· 前處理正規化(省略則補預設 / null)

此筆移轉產生的手續費(台幣整數,不可為負)

occurredAt選填
string· 格式限定 · 前處理正規化

移轉發生日期(YYYY-MM-DD)

settlementPeriod選填
string· 格式限定 · 前處理正規化

對應月結期間(YYYY-MM),標記此移轉沖減哪一期互抵;換匯不掛單一月結,傳 null

currency選填
string· 格式限定 · 前處理正規化

換匯外幣幣別(ISO 4217 三碼);非換匯傳 null

foreignAmount選填
integer· 前處理正規化(省略則補預設 / null)

換匯外幣金額(整數最小單位,須大於 0);非換匯傳 null

grossRate選填
string· 格式限定 · 前處理正規化

換匯牌價(正數,最多 6 位小數,以字串表達避免精度遺失);非換匯傳 null

obligationId選填
string· 格式限定 · 前處理正規化

選填沖減的掛帳 ID(aob_ 開頭);換匯不沖減掛帳須傳 null

回應欄位 · data

ok
boolean

是否登錄成功(移轉 + 沖減掛帳的原子交易皆完成)。

請求
curl -X POST https://your-tenant.example.com/api/v1/reconciliation/transfers \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

/accrual-ledger

掛帳台帳

GET/api/v1/accrual-ledger
ledger.read

參數

period必填
string· 格式限定

出團月(格式 YYYY-MM,Asia/Taipei 時區)

回應欄位 · data

period
string

結算期間(YYYY-MM,Asia/Taipei 出團月)。

departureSummary
object[]

梯次彙總(區塊 1):出團月落於 period 的各梯次收入 / 成本 / 毛利。

departureId
string

梯次 ID。

tripTitle
string

團名。

departureDate
string

出團日期(YYYY-MM-DD)。

pax
number

出團人數(該梯次確認人數)。

revenueTwd
number

總收入(梯次成交應收,排除已取消訂單,TWD 整數)。

realCostTwd
number

真實成本合計(TWD 整數)= 房費底價成本 + 已核准的逐筆成本。逐筆成本區塊不含房費 (房費由分房資料另計),故逐筆成本加總會小於此值,差額即房費(設計如此)。

grossProfitTwd
number

毛利毛估 = revenue − realCost(含房費)。

costLines
object[]

成本掛帳逐筆(區塊 2):該期梯次上所有 departure_costs 成本列。

id
string

成本列 ID。

tripTitle
string

團名。

departureDate
string

所屬梯次出團日期(YYYY-MM-DD)。

category
string

成本分類(如 交通 / 餐費 / 保險 / 嚮導)。

vendor
string | null

廠商:已建檔廠商名優先,否則用成本列上填寫的廠商名;null = 未填。

amountTwd
number

代墊額(真實成本,TWD 整數)。

invoiceAmountTwd
number

憑證額(外帳可申報金額,TWD 整數)。

isDeclarable
boolean

有無發票憑證。

reviewStatus
string

覆核狀態:掛了支出證明單則用其 status(pending/approved),否則由有無憑證派生。

payables
object[]

應付清單(區塊 3):該期歸屬的請款單(payables)。

payableNumber
string

請款單號(人類可讀)。

tripTitle
string

團名(未綁定梯次的手動請款顯示「未綁定梯次」)。

payeeName
string

受款對象(供應商 / 嚮導 / 派車人等)。

amountTwd
number

請款金額(整數 TWD)。

status
string

draft | submitted | approved | paid | cancelled | rejected。

receivables
object[]

應收清單(區塊 4):該期梯次上的 tour 訂單應收 / 實收 / 待收。

orderNumber
string

訂單編號。

tripTitle
string

團名(該訂單在期間內任一梯次的團名)。

receivableTwd
number

應收金額(TWD 整數)。

receivedTwd
number

實收金額(收款減退款,TWD 整數)。

outstandingTwd
number

待收 = receivable − received。

請求
curl -X GET "https://your-tenant.example.com/api/v1/accrual-ledger?period=<period>" \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "period": "…",
    "departureSummary": [
      {
        "departureId": "…",
        "tripTitle": "…",
        "departureDate": "…",
        "pax": 0,
        "revenueTwd": 0,
        "realCostTwd": 0,
        "grossProfitTwd": 0
      }
    ],
    "costLines": [
      {
        "id": "…",
        "tripTitle": "…",
        "departureDate": "…",
        "category": "…",
        "vendor": "…",
        "amountTwd": 0,
        "invoiceAmountTwd": 0,
        "isDeclarable": true,
        "reviewStatus": "…"
      }
    ],
    "payables": [
      {
        "payableNumber": "…",
        "tripTitle": "…",
        "payeeName": "…",
        "amountTwd": 0,
        "status": "…"
      }
    ],
    "receivables": [
      {
        "orderNumber": "…",
        "tripTitle": "…",
        "receivableTwd": 0,
        "receivedTwd": 0,
        "outstandingTwd": 0
      }
    ]
  }
}

掛帳台帳的「梯次彙總」

GET/api/v1/accrual-ledger/departure-summary
ledger.read

參數

period必填
string· 格式限定

出團月(格式 YYYY-MM,Asia/Taipei 時區)

回應欄位 · data

period
string

結算期間(YYYY-MM,Asia/Taipei 出團月),回聲請求參數。

departureSummary
object[]

梯次彙總:出團月落於 period 的各梯次收入 / 真實成本 / 毛估毛利。

departureId
string

梯次 ID。

tripTitle
string

團名。

departureDate
string

出團日期(YYYY-MM-DD)。

pax
number

出團人數(該梯次確認人數)。

revenueTwd
number

總收入(梯次成交應收,排除已取消訂單,TWD 整數)。

realCostTwd
number

真實成本合計(TWD 整數)= 房費底價成本 + 已核准的逐筆成本。逐筆成本區塊不含房費 (房費由分房資料另計),故逐筆成本加總會小於此值,差額即房費(設計如此)。

grossProfitTwd
number

毛利毛估 = revenue − realCost(含房費)。

請求
curl -X GET "https://your-tenant.example.com/api/v1/accrual-ledger/departure-summary?period=<period>" \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "period": "…",
    "departureSummary": [
      {
        "departureId": "…",
        "tripTitle": "…",
        "departureDate": "…",
        "pax": 0,
        "revenueTwd": 0,
        "realCostTwd": 0,
        "grossProfitTwd": 0
      }
    ]
  }
}

/cost-templates

list reusable series-tour cost templates

GET/api/v1/cost-templates
cost_template.read

參數

status選填
enum
activearchived

依狀態篩選:active 啟用、archived 已封存

active選填
boolean

啟用時只回傳輕量的 { id, name } 綁定挑選清單(行程設定的成本範本下拉用)

回應欄位 · data[]

id
string

成本範本 id(ct_ 前綴)。

name
string

成本範本名稱。

請求
curl -X GET https://your-tenant.example.com/api/v1/cost-templates \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "name": "…"
    }
  ]
}
POST/api/v1/cost-templates
cost_template.manage

參數

name必填
string· max 120 · min 1

成本範本名稱

description選填
string· max 500

成本範本說明

status選填
enum
activearchived

範本狀態:active 啟用、archived 已封存

回應欄位 · data

id
string

新建成本範本 ID(ct_ 前綴)。

請求
curl -X POST https://your-tenant.example.com/api/v1/cost-templates \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "<name>"
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…"
  }
}

full cost-template detail

GET/api/v1/cost-templates/{id}
cost_template.read

參數

id路徑
string· min 1

成本範本 ID

回應欄位 · data

lines
object[]

成本行明細(品項 × 單價 × 數量模型)。

id
string

成本行 ID。

templateId
string

所屬成本範本 ID。

category
string

成本分類(如 交通 / 餐費 / 保險)。

vendorName
string | null

供應商 / 廠商名(選填)。

description
string | null

摘要說明(選填)。

unitPriceTwd
number | null

TWD 行的單價;外幣行 null。

currency
string

幣別('TWD' = 台幣行)。

unitPriceForeign
number | null

外幣行的外幣單價;TWD 行 null。

internalRateSource
TemplateRateSource | null

外幣行的內帳匯率來源;TWD 行 null。

fxAccountId
string | null

internalRateSource='fx_account' 時的外幣帳戶 id。

quantityMode
QuantityMode

數量模式:fixed 固定值 / headcount 依人頭公式(ceil(Σ人頭 / 組距))。

quantityFixed
number | null

fixed 模式的固定數量;headcount 模式為 null。

headcountComponents
HeadcountComponent[] | null

headcount 模式選定的人頭 component(passenger / leader / assistant / driver);fixed 為 null。

groupDivisor
number | null

headcount 模式的組距(每 N 人一組,ceil 進位);null = 直接加總。

isDeclarable
boolean

是否預設有合法憑證(帶入成本列的 is_declarable 初值)。

sortOrder
number

顯示排序。

id
string

成本範本 ID。

name
string

範本名稱。

description
string | null

範本說明(選填)。

status
"active" | "archived"

狀態:active 啟用 / archived 已封存。

lineCount
number

成本行數(派生)。

boundTripCount
number

綁定行程數(派生)。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/cost-templates/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "lines": [
      {
        "id": "…",
        "templateId": "…",
        "category": "…",
        "vendorName": "…",
        "description": "…",
        "unitPriceTwd": 0,
        "currency": "…",
        "unitPriceForeign": 0,
        "internalRateSource": null,
        "fxAccountId": "…",
        "quantityMode": "…",
        "quantityFixed": 0,
        "headcountComponents": null,
        "groupDivisor": 0,
        "isDeclarable": true,
        "sortOrder": 0
      }
    ],
    "id": "…",
    "name": "…",
    "description": "…",
    "status": "active",
    "lineCount": 0,
    "boundTripCount": 0,
    "createdAt": "2026-06-30T08:00:00.000Z",
    "updatedAt": "2026-06-30T08:00:00.000Z"
  }
}
PATCH/api/v1/cost-templates/{id}
cost_template.manage

參數

name必填
string· max 120 · min 1

成本範本名稱

description選填
string· max 500

成本範本說明

status選填
enum
activearchived

範本狀態:active 啟用、archived 已封存

id路徑
string· min 1

成本範本 ID

回應欄位 · data

ok
boolean

是否更新成功。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/cost-templates/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "<name>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

add a cost line to a template.

POST/api/v1/cost-templates/{id}/lines
cost_template.manage

參數

id路徑
string· min 1

成本範本 ID

line必填
object

成本明細列:含 category 科目、vendorName 廠商、unitPriceTwd 單價、quantityMode 計量方式(fixed 固定/headcount 人數)與對應數量/人數組成、isDeclarable 是否可報帳等欄位

回應欄位 · data

id
string

新建成本明細行 ID。

請求
curl -X POST https://your-tenant.example.com/api/v1/cost-templates/<id>/lines \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "line": "<line>"
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…"
  }
}

update or delete a

PATCH/api/v1/cost-templates/lines/{lineId}
cost_template.manage

參數

lineId路徑
string· min 1

成本範本明細行 ID

line必填
object

成本明細列更新內容:含 category 科目、vendorName 廠商、unitPriceTwd 單價、quantityMode 計量方式(fixed 固定/headcount 人數)與對應數量/人數組成、isDeclarable 是否可報帳等欄位

回應欄位 · data

ok
boolean

是否更新成功。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/cost-templates/lines/<lineId> \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "line": "<line>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}
DELETE/api/v1/cost-templates/lines/{lineId}
cost_template.manage

參數

lineId路徑
string· min 1

成本範本明細行 ID

回應欄位 · data

ok
boolean

是否刪除成功。

請求
curl -X DELETE https://your-tenant.example.com/api/v1/cost-templates/lines/<lineId> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

/internal-external-ledger

取消梯次待結轉列表

GET/api/v1/internal-external-ledger/cancelled-departures
ledger.read模組:accounting

回應欄位 · data[]

departureId
string

取消梯次 ID。

tripTitle
string

團名。

tripSlug
string

行程 slug(URL 識別)。

departureDate
string

原出團日期(YYYY-MM-DD)。

returnDate
string

原回程日期(YYYY-MM-DD)。

groupCode
string | null

團號(group-code),未產生為 null。

residualCostTwd
number

殘餘成本(TWD 整數):已核准的逐筆成本合計 + 房費底價成本合計。

approvedCostCount
number

已核准成本筆數。

pendingCostCount
number

待覆核成本筆數(UI 提示「還有待覆核成本」)。

roomCostTwd
number

房費殘餘成本(房費底價成本合計,整數 TWD)。

conversion
{ expenseId: string; amountTwd: number; period: string; description: string; } | null

結轉狀態:已結轉為特殊損益時的費用列資訊(expenseId / 金額 / 歸屬月 / 摘要);未結轉為 null。

請求
curl -X GET https://your-tenant.example.com/api/v1/internal-external-ledger/cancelled-departures \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "departureId": "…",
      "tripTitle": "…",
      "tripSlug": "…",
      "departureDate": "…",
      "returnDate": "…",
      "groupCode": "…",
      "residualCostTwd": 0,
      "approvedCostCount": 0,
      "pendingCostCount": 0,
      "roomCostTwd": 0,
      "conversion": "…"
    }
  ]
}

結轉取消

POST/api/v1/internal-external-ledger/cancelled-departures/convert
operating_expense.manage模組:accounting

參數

departureId必填
string· min 1

梯次 ID

categoryId必填
string· min 1

特殊損益費用科目 ID(kind=special)

period必填
string· 格式限定

歸屬月(取消月,格式 YYYY-MM)

amountTwd必填
integer

結轉金額(整數 TWD,預設殘餘成本)

description必填
string· min 1

摘要

note選填
string

備註(選填)

回應欄位 · data

id
string

新建立的殘餘成本營業費用列 ID(opx_ 前綴)。

residualCostTwd
number

結轉的殘餘成本金額(TWD 整數)。

請求
curl -X POST https://your-tenant.example.com/api/v1/internal-external-ledger/cancelled-departures/convert \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "departureId": "<departureId>",
    "categoryId": "<categoryId>",
    "period": "<period>",
    "amountTwd": 0,
    "description": "<description>"
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…",
    "residualCostTwd": 0
  }
}

撤銷取消

POST/api/v1/internal-external-ledger/cancelled-departures/revert
operating_expense.manage模組:accounting

參數

departureId必填
string· min 1

梯次 ID

回應欄位 · data

ok
boolean

固定為 true:已還原取消梯次的轉列,回到未轉列狀態。

請求
curl -X POST https://your-tenant.example.com/api/v1/internal-external-ledger/cancelled-departures/revert \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "departureId": "<departureId>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}
PATCH/api/v1/internal-external-ledger/costs/{costId}
departure_cost.manage

參數

category必填
string

成本類別代碼(須為有效的成本分類)

vendorName選填
string

廠商/供應商名稱

description選填
string

成本摘要說明

amountTwd選填
integer

真實成本(台幣整數)。台幣路徑必填;外幣路徑忽略,改由外幣金額乘匯率換算

currency選填
string

幣別;TWD 或留空走台幣路徑,其他幣別走外幣路徑

foreignAmount選填
integer

外幣金額(整數);僅外幣路徑使用

internalRateSource選填
enum
fx_accountpublishedmanual

內帳匯率來源:fx_account 外幣帳戶加權成本、published 台銀牌告、manual 手填成交率

fxAccountId選填
string

外幣帳戶 ID;內帳匯率來源為 fx_account 時使用

manualRate選填
string

手填成交匯率(字串保精度);內帳匯率來源為 manual 時使用

hasReceipt選填
boolean

是否有發票憑證;預設 true,false 表示無發票並強制可申報額為 0、改填支出證明單欄位

invoiceAmountTwd選填
integer

外帳可申報額覆寫(台幣整數,須大於等於 0、無上限)

payeeName選填
string

受款人姓名;無發票時的支出證明單欄位

reasonNoReceipt選填
string

無發票原因;無發票時的支出證明單欄位

proofSummary選填
string

支出證明摘要;無發票時的支出證明單欄位

quantityMode選填
enum
fixedheadcount

計價方式;未給=一次性總額,fixed=單價×固定數量,headcount=單價×ceil(Σ人頭/組距)

headcountComponents選填
array

依人頭計價的人頭組合(passenger/leader/assistant/driver,至少一項)

groupDivisor選填
integer

依人頭計價的組距(≥ 1;空=直接加總)

quantityFixed選填
integer

固定數量計價的數量(≥ 0)

unitPriceTwd選填
integer

單價(台幣整數);計價方式給值時必填

costId路徑
string· min 1

成本列 ID

回應欄位 · data

ok
boolean

固定為 true:成本列已更新。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/internal-external-ledger/costs/<costId> \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "category": "<category>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}
DELETE/api/v1/internal-external-ledger/costs/{costId}
departure_cost.manage

參數

costId路徑
string· min 1

成本列 ID

回應欄位 · data

ok
boolean

固定為 true:成本列已刪除。

請求
curl -X DELETE https://your-tenant.example.com/api/v1/internal-external-ledger/costs/<costId> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}
POST/api/v1/internal-external-ledger/costs/{costId}/approve-declaration
ledger.approve

參數

costId路徑
string· min 1

成本列 ID

回應欄位 · data

ok
boolean

固定為 true:成本自主申報已核准。

請求
curl -X POST https://your-tenant.example.com/api/v1/internal-external-ledger/costs/<costId>/approve-declaration \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

待覆核的嚮導申報

GET/api/v1/internal-external-ledger/declarations/pending
ledger.read模組:accounting

回應欄位 · data[]

id
string

成本列 ID。

departureId
string

所屬梯次 ID。

tripTitle
string

團名。

departureDate
string

出團日期(YYYY-MM-DD)。

category
string

成本分類。

vendorName
string | null

供應商 / 廠商名(選填)。

amountTwd
number

代墊 / 實付額(內帳真實成本,整數 TWD)。

invoiceAmountTwd
number

憑證 / 發票額(外帳可申報,整數 TWD)。

isDeclarable
boolean

是否取得合法憑證。

createdByName
string | null

登記者(經手人)姓名。

createdAt
Date

建立時間(嚮導送出時間)。

請求
curl -X GET https://your-tenant.example.com/api/v1/internal-external-ledger/declarations/pending \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "departureId": "…",
      "tripTitle": "…",
      "departureDate": "…",
      "category": "…",
      "vendorName": "…",
      "amountTwd": 0,
      "invoiceAmountTwd": 0,
      "isDeclarable": true,
      "createdByName": "…",
      "createdAt": "2026-06-30T08:00:00.000Z"
    }
  ]
}

per-departure 內外帳列表

GET/api/v1/internal-external-ledger/departures
ledger.read模組:accounting

參數

windowDays選填
integer

回看天數;只列出近 N 天內的梯次

tripId選填
string

行程 ID;只列出該行程的梯次

period選填
string· 格式限定

出團月(格式 YYYY-MM);只列出該月的梯次

回應欄位 · data[]

tripTitle
string

梯次標題(trip title)。

tripSlug
string

行程 slug(URL 識別)。

departureDate
string

出團日期(YYYY-MM-DD)。

returnDate
string

回程日期(YYYY-MM-DD)。

groupCode
string | null

團號(group-code),未產生為 null。

pax
number

報名人數(非取消單 party_size 合計)。

departureId
string

梯次 ID。

revenueTwd
number

本團收入(梯次應收,排除已取消訂單,TWD 整數)。

realCostTwd
number

內帳真實成本(TWD 整數)= 房費底價成本 + 已核准的逐筆成本合計。

declarableCostTwd
number

外帳可申報成本(各成本列憑證額合計,TWD 整數)。

nonDeclarableCostTwd
number

不可申報(無憑證)真實成本,逐列 Σ GREATEST(amount − invoice, 0)(非跨列 realCost − declarableCost)。

costBilledTwd
number

已轉請款成本。

costUnbilledTwd
number

未轉請款成本。

grossProfitTwd
number

**每梯次權威數=毛利** = revenue − realCost(不扣手續費 / 稅,operating-expenses §2.3)。 公司月損益(computeCompanyPnL)的「各區毛利」即逐梯次此值按區彙整;手續費 / 稅在公司層 用實際值扣一次,**不**用下面的預估費率重扣(避免雙重計)。

feeEcpayTwd
number

預估綠界手續費(**參考預估**,非權威;公司層用實際值,§2.3)。

feeFongshouTwd
number

預估豐收款手續費(**參考預估**,非權威)。

taxEstTwd
number

預估發票 / 營所稅(**參考預估**,非權威;公司層用實繳值)。

estimatedNetProfitTwd
number

**參考預估淨利**(非權威)= grossProfit − feeEcpay − feeFongshou − taxEst。純給現場 快速感覺(毛利扣預估費率),**非公司財務真相** —— 公司淨利以 operating-expenses 月損益表 (實際 overhead)為準。權威數請用 `grossProfitTwd`。

marginPct
number | null

毛利率(grossProfit / revenue),revenue=0 時為 null。

pendingProofCount
number

待核(pending)支出證明單數。

feeRates
object

套用的費率(呈現用)。

ecpayFeeBps
number

預估綠界手續費率(basis points,270 = 2.70%)。

fongshouFeeBps
number

預估豐收款手續費率(basis points,50 = 0.50%)。

profitTaxBps
number

預估發票 / 營所稅率(basis points,500 = 5.00%)。

請求
curl -X GET https://your-tenant.example.com/api/v1/internal-external-ledger/departures \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "tripTitle": "…",
      "tripSlug": "…",
      "departureDate": "…",
      "returnDate": "…",
      "groupCode": "…",
      "pax": 0,
      "departureId": "…",
      "revenueTwd": 0,
      "realCostTwd": 0,
      "declarableCostTwd": 0,
      "nonDeclarableCostTwd": 0,
      "costBilledTwd": 0,
      "costUnbilledTwd": 0,
      "grossProfitTwd": 0,
      "feeEcpayTwd": 0,
      "feeFongshouTwd": 0,
      "taxEstTwd": 0,
      "estimatedNetProfitTwd": 0,
      "marginPct": 0,
      "pendingProofCount": 0,
      "feeRates": {
        "ecpayFeeBps": 0,
        "fongshouFeeBps": 0,
        "profitTaxBps": 0
      }
    }
  ]
}

single

GET/api/v1/internal-external-ledger/departures/{departureId}
ledger.read模組:accounting

參數

departureId路徑
string· min 1

梯次 ID

回應欄位 · data

departureId
string

梯次 ID。

revenueTwd
number

本團收入(梯次應收,排除已取消訂單,TWD 整數)。

realCostTwd
number

內帳真實成本(TWD 整數)= 房費底價成本 + 已核准的逐筆成本合計。

declarableCostTwd
number

外帳可申報成本(各成本列憑證額合計,TWD 整數)。

nonDeclarableCostTwd
number

不可申報(無憑證)真實成本,逐列 Σ GREATEST(amount − invoice, 0)(非跨列 realCost − declarableCost)。

costBilledTwd
number

已轉請款成本。

costUnbilledTwd
number

未轉請款成本。

grossProfitTwd
number

**每梯次權威數=毛利** = revenue − realCost(不扣手續費 / 稅,operating-expenses §2.3)。 公司月損益(computeCompanyPnL)的「各區毛利」即逐梯次此值按區彙整;手續費 / 稅在公司層 用實際值扣一次,**不**用下面的預估費率重扣(避免雙重計)。

feeEcpayTwd
number

預估綠界手續費(**參考預估**,非權威;公司層用實際值,§2.3)。

feeFongshouTwd
number

預估豐收款手續費(**參考預估**,非權威)。

taxEstTwd
number

預估發票 / 營所稅(**參考預估**,非權威;公司層用實繳值)。

estimatedNetProfitTwd
number

**參考預估淨利**(非權威)= grossProfit − feeEcpay − feeFongshou − taxEst。純給現場 快速感覺(毛利扣預估費率),**非公司財務真相** —— 公司淨利以 operating-expenses 月損益表 (實際 overhead)為準。權威數請用 `grossProfitTwd`。

marginPct
number | null

毛利率(grossProfit / revenue),revenue=0 時為 null。

pendingProofCount
number

待核(pending)支出證明單數。

feeRates
object

套用的費率(呈現用)。

ecpayFeeBps
number

預估綠界手續費率(basis points,270 = 2.70%)。

fongshouFeeBps
number

預估豐收款手續費率(basis points,50 = 0.50%)。

profitTaxBps
number

預估發票 / 營所稅率(basis points,500 = 5.00%)。

請求
curl -X GET https://your-tenant.example.com/api/v1/internal-external-ledger/departures/<departureId> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "departureId": "…",
    "revenueTwd": 0,
    "realCostTwd": 0,
    "declarableCostTwd": 0,
    "nonDeclarableCostTwd": 0,
    "costBilledTwd": 0,
    "costUnbilledTwd": 0,
    "grossProfitTwd": 0,
    "feeEcpayTwd": 0,
    "feeFongshouTwd": 0,
    "taxEstTwd": 0,
    "estimatedNetProfitTwd": 0,
    "marginPct": 0,
    "pendingProofCount": 0,
    "feeRates": {
      "ecpayFeeBps": 0,
      "fongshouFeeBps": 0,
      "profitTaxBps": 0
    }
  }
}
POST/api/v1/internal-external-ledger/departures/{departureId}/convert-to-payable
departure_cost.manage

參數

departureId路徑
string· min 1

梯次 ID

costIds必填
array· min 1

要轉成請款核簽的成本列 ID 陣列(至少一筆,須為尚未轉請款者)

payeeType選填
enum
supplierguidestaff_commissionother

受款對象類型:supplier 供應商、guide 嚮導、staff_commission 員工佣金、other 其他

payeeName必填
string· min 1

受款對象名稱

payeeBankAccount選填
string

受款銀行帳號

payeeBankName選填
string

受款銀行名稱

payeeBankBranch選填
string

受款銀行分行

payeeTaxId選填
string

受款對象統一編號/稅籍編號

taxAmountTwd選填
integer

代扣稅額(台幣整數)

submitImmediately選填
boolean

是否建立後立即送出核簽(true 直接送審)

回應欄位 · data

payableId
string

新建立應付單的 ID(pay_ 前綴)。

payableNumber
string

應付單編號(租戶內流水序號,出款核簽用)。

請求
curl -X POST https://your-tenant.example.com/api/v1/internal-external-ledger/departures/<departureId>/convert-to-payable \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "costIds": [],
    "payeeName": "<payeeName>"
  }'
回應
{
  "ok": true,
  "data": {
    "payableId": "…",
    "payableNumber": "…"
  }
}
GET/api/v1/internal-external-ledger/departures/{departureId}/costs
ledger.read

參數

departureId路徑
string· min 1

梯次 ID

createdBy選填
string

登記者使用者 ID;只列出該人登記的成本列

回應欄位 · data[]

id
string

成本列 ID。

departureId
string

所屬梯次 ID。

category
string

成本分類(如 交通 / 餐費 / 保險 / 嚮導)。

vendorName
string | null

供應商 / 廠商名(選填)。

description
string | null

摘要說明(選填)。

receiptImageUrl
string | null

憑證照片 URL(G3-2);未附照片 null。app-route 私有 URL,讀取經 route 權限閘。

amountTwd
number

代墊 / 實付額(內帳真實成本,整數 TWD)。

invoiceAmountTwd
number

外帳可申報額(internal-external-ledger §2.1)。

isDeclarable
boolean

是否取得合法憑證。

reviewStatus
string

覆核狀態 'pending' | 'approved'(L'):pending 不計入淨利 / 可申報(UI 須標示、停用轉請款)。

currency
string

成本幣別(ISO 4217);'TWD' = 台幣列。

foreignAmount
number | null

外幣金額(最小單位整數);TWD 列 null。

internalRateSource
string | null

內帳匯率來源;TWD 列 null。

fxAccountId
string | null

internalRateSource='fx_account' 時的外幣帳戶 id。

internalRate
string | null

內帳匯率快照(numeric 字串);TWD 列 null。

externalRate
string | null

外帳匯率快照(numeric 字串,台銀牌告);TWD 列 null。

feeCategory
string | null

費用類型 tag(account-settlement §3.4,成本側類別→領域帳戶映射;null = 未 tag)。

quantityMode
QuantityMode | null

計價方式 'fixed' / 'headcount';一次性總額列 null。

headcountComponents
HeadcountComponent[] | null

headcount 人頭組合;非 headcount 列 null。

groupDivisor
number | null

headcount 組距;非 headcount 列 null。

quantity
number | null

解析後(headcount)或自訂(fixed)的數量;一次性總額列 null。

unitPriceTwd
number | null

單價(台幣整數);一次性總額列 null。

expenseProofId
string | null

無發票支出掛的支出證明單 id(null = 有憑證)。

proofNumber
string | null

支出證明單單號(join expense_proofs,null = 無)。

proofStatus
string | null

支出證明單狀態 'pending' | 'approved'(null = 無)。

payableId
string | null

已轉請款時連結的請款單 ID(null = 未轉請款)。

payableNumber
string | null

連結請款單的人類可讀單號(null = 未轉請款)。

payableStatus
string | null

連結請款單的狀態(draft / submitted / approved / paid…;null = 未轉請款)。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/internal-external-ledger/departures/<departureId>/costs \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "departureId": "…",
      "category": "…",
      "vendorName": "…",
      "description": "…",
      "receiptImageUrl": "…",
      "amountTwd": 0,
      "invoiceAmountTwd": 0,
      "isDeclarable": true,
      "reviewStatus": "…",
      "currency": "…",
      "foreignAmount": 0,
      "internalRateSource": "…",
      "fxAccountId": "…",
      "internalRate": "…",
      "externalRate": "…",
      "feeCategory": "…",
      "quantityMode": null,
      "headcountComponents": null,
      "groupDivisor": 0,
      "quantity": 0,
      "unitPriceTwd": 0,
      "expenseProofId": "…",
      "proofNumber": "…",
      "proofStatus": "…",
      "payableId": "…",
      "payableNumber": "…",
      "payableStatus": "…",
      "createdAt": "2026-06-30T08:00:00.000Z",
      "updatedAt": "2026-06-30T08:00:00.000Z"
    }
  ]
}
POST/api/v1/internal-external-ledger/departures/{departureId}/costs
departure_cost.manage

參數

category必填
string

成本類別代碼(須為有效的成本分類)

vendorName選填
string

廠商/供應商名稱

description選填
string

成本摘要說明

amountTwd選填
integer

真實成本(台幣整數)。台幣路徑必填;外幣路徑忽略,改由外幣金額乘匯率換算

currency選填
string

幣別;TWD 或留空走台幣路徑,其他幣別走外幣路徑

foreignAmount選填
integer

外幣金額(整數);僅外幣路徑使用

internalRateSource選填
enum
fx_accountpublishedmanual

內帳匯率來源:fx_account 外幣帳戶加權成本、published 台銀牌告、manual 手填成交率

fxAccountId選填
string

外幣帳戶 ID;內帳匯率來源為 fx_account 時使用

manualRate選填
string

手填成交匯率(字串保精度);內帳匯率來源為 manual 時使用

hasReceipt選填
boolean

是否有發票憑證;預設 true,false 表示無發票並強制可申報額為 0、改填支出證明單欄位

invoiceAmountTwd選填
integer

外帳可申報額覆寫(台幣整數,須大於等於 0、無上限)

payeeName選填
string

受款人姓名;無發票時的支出證明單欄位

reasonNoReceipt選填
string

無發票原因;無發票時的支出證明單欄位

proofSummary選填
string

支出證明摘要;無發票時的支出證明單欄位

quantityMode選填
enum
fixedheadcount

計價方式;未給=一次性總額,fixed=單價×固定數量,headcount=單價×ceil(Σ人頭/組距)

headcountComponents選填
array

依人頭計價的人頭組合(passenger/leader/assistant/driver,至少一項)

groupDivisor選填
integer

依人頭計價的組距(≥ 1;空=直接加總)

quantityFixed選填
integer

固定數量計價的數量(≥ 0)

unitPriceTwd選填
integer

單價(台幣整數);計價方式給值時必填

departureId路徑
string· min 1

梯次 ID

回應欄位 · data

id
string

新建立成本列的 ID(dc_ 前綴)。

expenseProofId
string | null

隨附憑證的 ID(若本次一併登記),無則為 null。

請求
curl -X POST https://your-tenant.example.com/api/v1/internal-external-ledger/departures/<departureId>/costs \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "category": "<category>"
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…",
    "expenseProofId": "…"
  }
}

支出

GET/api/v1/internal-external-ledger/departures/{departureId}/proofs
ledger.read模組:accounting

參數

departureId路徑
string· min 1

梯次 ID

回應欄位 · data[]

id
string

支出證明單 ID。

proofNumber
string

人類可讀單號(EP-YYMMDD-NNN)。

departureId
string

所屬梯次 ID。

payeeName
string

受款對象(自然人 / 廠商)。

amountTwd
number

金額(整數 TWD,對應所掛成本列的 amount_twd)。

reasonNoReceipt
string

無法取得單據的原因(如「自然人」)。

summary
string | null

支出內容及摘要(選填)。

handlerUserId
string

經手人(建單者)user ID。

approverUserId
string | null

核准人 user ID(強制 ≠ 經手人);未核准為 null。

status
ExpenseProofStatus

狀態:pending 待核准 / approved 已核准(核准後 append-only)。

approvedAt
Date | null

核准時間;未核准為 null。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/internal-external-ledger/departures/<departureId>/proofs \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "proofNumber": "…",
      "departureId": "…",
      "payeeName": "…",
      "amountTwd": 0,
      "reasonNoReceipt": "…",
      "summary": "…",
      "handlerUserId": "…",
      "approverUserId": "…",
      "status": "…",
      "approvedAt": null,
      "createdAt": "2026-06-30T08:00:00.000Z",
      "updatedAt": "2026-06-30T08:00:00.000Z"
    }
  ]
}
GET/api/v1/internal-external-ledger/departures/{departureId}/proofs/{proofId}
ledger.read模組:accounting

參數

departureId路徑
string· min 1

梯次 ID

proofId路徑
string· min 1

支出證明單 ID

回應欄位 · data

id
string

支出證明單 ID。

proofNumber
string

人類可讀單號(EP-YYMMDD-NNN)。

departureId
string

所屬梯次 ID。

payeeName
string

受款對象(自然人 / 廠商)。

amountTwd
number

金額(整數 TWD,對應所掛成本列的 amount_twd)。

reasonNoReceipt
string

無法取得單據的原因(如「自然人」)。

summary
string | null

支出內容及摘要(選填)。

handlerUserId
string

經手人(建單者)user ID。

approverUserId
string | null

核准人 user ID(強制 ≠ 經手人);未核准為 null。

status
ExpenseProofStatus

狀態:pending 待核准 / approved 已核准(核准後 append-only)。

approvedAt
Date | null

核准時間;未核准為 null。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/internal-external-ledger/departures/<departureId>/proofs/<proofId> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "id": "…",
    "proofNumber": "…",
    "departureId": "…",
    "payeeName": "…",
    "amountTwd": 0,
    "reasonNoReceipt": "…",
    "summary": "…",
    "handlerUserId": "…",
    "approverUserId": "…",
    "status": "…",
    "approvedAt": null,
    "createdAt": "2026-06-30T08:00:00.000Z",
    "updatedAt": "2026-06-30T08:00:00.000Z"
  }
}
POST/api/v1/internal-external-ledger/proofs/{proofId}/approve
ledger.approve

參數

proofId路徑
string· min 1

支出證明單 ID

回應欄位 · data

ok
boolean

固定為 true:憑證已核准。

請求
curl -X POST https://your-tenant.example.com/api/v1/internal-external-ledger/proofs/<proofId>/approve \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

/payouts

派生當月

GET/api/v1/payouts/aggregate
supplier.read模組:accounting

參數

period必填
string· 格式限定

出款月份(YYYY-MM),彙整該月已核准未付的應付

scope必填
enum
guidesupplierstaff

收款對象範圍(guide 領隊嚮導 / supplier 供應商 / staff 員工)

回應欄位 · data[]

payeeType
PayoutPayeeType

收款對象類型:guide 領隊嚮導 / supplier 供應商 / staff 員工。

payeeRefId
string

收款對象識別 key:供應商為其 ID,領隊 / 員工為收款人姓名。

payeeName
string

收款對象名稱。

payeeAccountName
string | null

收款人戶名(supplier 取 suppliers / guide 取 guides;staff 暫無主檔 → null)。

payeeBankCode
string | null

收款銀行代號(同上來源;無主檔為 null)。

payeeAccountNumber
string | null

收款帳號(同上來源;無主檔為 null,遮罩回傳)。

grossTwd
number

當月已核准未付的請款單淨額合計(TWD 整數)。

items
object[]

彙整明細(日期 + 團名 + 金額,唯讀派生,不另存)。

payableId
string

請款單 ID。

payableNumber
string

請款單人類可讀單號。

date
string | null

梯次出發日('YYYY-MM-DD');無連梯次時 null。

tripLabel
string | null

團名;無連梯次時 null。

amountTwd
number

該請款單的應付淨額(TWD 整數)。

請求
curl -X GET "https://your-tenant.example.com/api/v1/payouts/aggregate?period=<period>&scope=<scope>" \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "payeeType": "…",
      "payeeRefId": "…",
      "payeeName": "…",
      "payeeAccountName": "…",
      "payeeBankCode": "…",
      "payeeAccountNumber": "…",
      "grossTwd": 0,
      "items": [
        {
          "payableId": "…",
          "payableNumber": "…",
          "date": "…",
          "tripLabel": "…",
          "amountTwd": 0
        }
      ]
    }
  ]
}

建立出款批次草稿

POST/api/v1/payouts/batches
supplier.read模組:accounting

參數

period必填
string· 格式限定

出款月份(YYYY-MM)

payeeScope必填
enum

收款對象範圍(guide 領隊嚮導 / supplier 供應商 / staff 員工)

paidFromAccountId選填
string· min 1

出帳帳戶 id(從哪個收款帳戶付出);可留空待確認時指定

lines必填
array· min 1

納入批次的出款列(至少一列)

回應欄位 · data

id
string

新建立出款批次的 ID(pob_ 前綴)。

請求
curl -X POST https://your-tenant.example.com/api/v1/payouts/batches \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "period": "<period>",
    "payeeScope": "<payeeScope>",
    "lines": []
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…"
  }
}

確認出款批次

POST/api/v1/payouts/batches/{id}/confirm
payable.mark_paid模組:accounting

參數

id路徑
string· 格式限定

出款批次 id(路徑參數,格式 pob_…)

bankReference選填
string· max 64

網銀交易序號 / 轉帳憑證號(可選)

回應欄位 · data

ok
boolean

固定為 true:出款批次已確認送出。

請求
curl -X POST https://your-tenant.example.com/api/v1/payouts/batches/<id>/confirm \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

出款批次的標準四欄批次轉帳檔

GET/api/v1/payouts/batches/{id}/transfer-file
payable.mark_paid模組:accounting

參數

id路徑
string· min 1

出款批次 id(路徑參數)

format選填
enum
csvjson

輸出格式:json 完整匯出(預設)或 csv 僅回傳轉帳檔字串

請求
curl -X GET https://your-tenant.example.com/api/v1/payouts/batches/<id>/transfer-file \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": "…"
}

為某出款批次列簽發廠商自助確認

POST/api/v1/payouts/lines/{lineId}/confirm-token
supplier.read模組:accounting

參數

lineId路徑
string· 格式限定

出款批次列 id(路徑參數,格式 pobl_…)

回應欄位 · data

token
string

廠商自助確認 token(拼成對外確認頁網址;idempotent,重複簽發回原 token)。

請求
curl -X POST https://your-tenant.example.com/api/v1/payouts/lines/<lineId>/confirm-token \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "token": "…"
  }
}

出款批次的「出帳帳戶」選項

GET/api/v1/payouts/remit-accounts
supplier.read模組:accounting

回應欄位 · data[]

id
string

收款帳戶 ID。

code
string

帳戶代碼(租戶內唯一穩定識別)。

displayName
string

帳戶顯示名。

kind
ReceivingAccountKind

帳戶類型:bank 銀行 / cash 現金 / gateway 金流閘道。

bankName
string | null

銀行名稱;現金/閘道帳戶為 null。

accountNo
string | null

銀行帳號;現金/閘道帳戶為 null。

canReceive
boolean

可收款(幾乎都 true)。

canRemit
boolean

可對外匯款(ATM / 匯出退款 / 補款匯出)。荒野只有永豐。

canChargeback
boolean

可刷退(退回原信用卡)。荒野只有綠界(gateway)。

isDeprecated
boolean

廢帳戶:仍可零星收款,但其收款需由他帳戶代墊歸集。荒野=RU 台銀 / 登山社。

isSettlementMaster
boolean

主結算帳戶:所有資金最終向它彙整。每租戶恰一個(partial unique index)。荒野=永豐。

currency
string

帳戶幣別(ISO 4217;既有帳戶皆 'TWD',外幣帳戶如 IDR / USD)。

isActive
boolean

此帳戶是否啟用。

displayOrder
number

後台清單排序序位(小者在前)。

usedCount
number

被多少 payment_transactions 引用(UI 鎖頭 / 「使用中 N」)。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/payouts/remit-accounts \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "code": "…",
      "displayName": "…",
      "kind": "…",
      "bankName": "…",
      "accountNo": "…",
      "canReceive": true,
      "canRemit": true,
      "canChargeback": true,
      "isDeprecated": true,
      "isSettlementMaster": true,
      "currency": "…",
      "isActive": true,
      "displayOrder": 0,
      "usedCount": 0,
      "createdAt": "2026-06-30T08:00:00.000Z",
      "updatedAt": "2026-06-30T08:00:00.000Z"
    }
  ]
}

/pnl

list the company expense-category

GET/api/v1/pnl/expense-categories
operating_expense.read

參數

activeOnly選填
boolean

是否只回傳啟用中的費用類別;預設含停用列

回應欄位 · data[]

id
string

費用類別 ID。

code
string

科目代碼(租戶內唯一穩定識別,如 rent / salary_admin / tax_vat)。

displayName
string

顯示名(如 房租 / 行政薪資 / 營業稅)。

kind
"opex" | "tax" | "platform_fee" | "special"

費用大類:opex 營業費用 / tax 稅 / platform_fee 平台手續費 / special 特殊損益(損益表據此 roll-up)。

isActive
boolean

是否啟用(停用不刪,既有費用列仍引用得到)。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/pnl/expense-categories \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "code": "…",
      "displayName": "…",
      "kind": "opex",
      "isActive": true,
      "createdAt": "2026-06-30T08:00:00.000Z",
      "updatedAt": "2026-06-30T08:00:00.000Z"
    }
  ]
}

list company operating-expense ledger rows

GET/api/v1/pnl/expenses
operating_expense.read

參數

period選填
string

歸屬月(格式 YYYY-MM);只列出該月的費用

category選填
string

費用類別 ID;只列出該類別的費用

kind選填
enum
opextaxplatform_feespecial

費用大類:opex 營業費用、tax 稅、platform_fee 平台手續費、special 特殊損益

回應欄位 · data[]

id
string

費用列 ID。

categoryId
string

費用科目 ID。

categoryCode
string | null

費用科目代碼(如 rent / salary_admin)。

categoryDisplayName
string | null

費用科目顯示名。

categoryKind
string | null

費用科目大類(opex / tax / platform_fee / special)。

period
string

歸屬月(YYYY-MM,損益表據此彙整;可與支付日不同月)。

incurredOn
string | null

發生 / 支付日期(YYYY-MM-DD);金流商內扣 / 攤提無單一發生日者為 null。

amountTwd
number

金額(整數 TWD)。

description
string

摘要(廠商 / 品名,如 台中房租 / 委外廣告投放)。

paidFromAccountId
string | null

出帳帳戶 ID;金流商內扣者為 null。

paidFromAccountName
string | null

出帳帳戶顯示名。

frontedByUserId
string | null

代墊者 user ID;非空代表由此人代墊待回補(走請款回補代墊者)。

frontedByName
string | null

代墊者姓名。

payableId
string | null

若走出款核簽,連結的請款單 ID;否則 null。

payableNumber
string | null

連結請款單的人類可讀單號。

recurring
boolean

月固定標記(人工登記時備註「月固定」;自動生成走範本表,非此欄)。

status
"confirmed" | "draft"

'draft'(月固定範本自動生成、待確認,不入損益)| 'confirmed'(計入損益)。

origin
"manual" | "recurring" | "departure_conversion"

'manual'(手動登記)| 'recurring'(月固定範本自動生成)| 'departure_conversion'(取消梯次結轉,§3.4)。

sourceTemplateId
string | null

生成來源範本(origin='recurring');手動登記為 null。

note
string | null

備註。

createdByUserId
string

經手人 user ID(建立此費用列者)。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/pnl/expenses \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "categoryId": "…",
      "categoryCode": "…",
      "categoryDisplayName": "…",
      "categoryKind": "…",
      "period": "…",
      "incurredOn": "…",
      "amountTwd": 0,
      "description": "…",
      "paidFromAccountId": "…",
      "paidFromAccountName": "…",
      "frontedByUserId": "…",
      "frontedByName": "…",
      "payableId": "…",
      "payableNumber": "…",
      "recurring": true,
      "status": "confirmed",
      "origin": "manual",
      "sourceTemplateId": "…",
      "note": "…",
      "createdByUserId": "…",
      "createdAt": "2026-06-30T08:00:00.000Z",
      "updatedAt": "2026-06-30T08:00:00.000Z"
    }
  ]
}
POST/api/v1/pnl/expenses
operating_expense.manage模組:accounting

參數

categoryId必填
string· min 1

費用類別 ID(對應公司費用類別目錄)

period必填
string· 格式限定

歸屬月(格式 YYYY-MM),供月損益表彙整

description必填
string· min 1

費用摘要

amountTwd必填
integer

費用金額(台幣非負整數)

incurredOn選填
string

費用發生日期(格式 YYYY-MM-DD)

paidFromAccountId選填
string

支付來源帳戶 ID

frontedByUserId選填
string

代墊人使用者 ID(由員工先行墊付時填寫)

note選填
string

備註

recurring選填
boolean

是否為週期性費用

回應欄位 · data

ok
boolean

固定為 true:營業費用列已新增。

id
string

新建立營業費用列的 ID(opx_ 前綴)。

請求
curl -X POST https://your-tenant.example.com/api/v1/pnl/expenses \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "categoryId": "<categoryId>",
    "period": "<period>",
    "description": "<description>",
    "amountTwd": 0
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "id": "…"
  }
}

更正一筆公司營業費用

PATCH/api/v1/pnl/expenses/{id}
operating_expense.manage模組:accounting

參數

categoryId必填
string· min 1

費用類別 ID(對應公司費用類別目錄)

period必填
string· 格式限定

歸屬月(格式 YYYY-MM),供月損益表彙整

description必填
string· min 1

費用摘要

amountTwd必填
integer

費用金額(台幣非負整數)

incurredOn選填
string

費用發生日期(格式 YYYY-MM-DD)

paidFromAccountId選填
string

支付來源帳戶 ID

frontedByUserId選填
string

代墊人使用者 ID(由員工先行墊付時填寫)

note選填
string

備註

recurring選填
boolean

是否為週期性費用

id路徑
string· min 1

營業費用列 ID

payableId選填
string

關聯的請款核簽 ID;整列覆寫時須原樣帶回,省略則清為 null

回應欄位 · data

ok
boolean

固定為 true:營業費用列已更新。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/pnl/expenses/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "categoryId": "<categoryId>",
    "period": "<period>",
    "description": "<description>",
    "amountTwd": 0
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

the company monthly P&L statement

GET/api/v1/pnl/statement
operating_expense.read

參數

period必填
string· 格式限定

損益表結算月(格式 YYYY-MM)

extraIncome選填
integer

額外收入(台幣非負整數),併入公司淨利計算;預設 0

回應欄位 · data

period
string

結算期間(YYYY-MM)。

regions
object[]

各區毛利明細(出團月落 period 的梯次按區 roll-up)。

region
string

派生 region key(穩定,由 trip 屬性派生)。

label
string

顯示標籤(destination 原文 / 衍生)。

revenueTwd
number

本區成交應收(出團月落 period 的梯次合計,TWD 整數)。

directCostTwd
number

本區真實直接成本(TWD 整數)= 房費底價成本 + 已核准的逐筆成本合計。

marginTwd
number

本區毛利 = revenue − directCost。

departures
number

本區梯次數(出團月落 period)。

grossMarginTwd
number

各區毛利加總(整數 TWD)。

revenueTotalTwd
number

各區營收加總(整數 TWD)。

extraIncomeTwd
number

額外收入(GS 二、額外收入總計;本批無 schema 載體 → 0,見 §5)。

adminFeeIncomeTwd
number

行政手續費收入(退款收取的行政手續費,只計未出團 / 取消單,TWD 整數)。

otherIncomeTwd
number

其他收入合計 = extraIncome + adminFeeIncome(整數 TWD)。

expensesByKind
object[]

公司營業費用按 kind roll-up(opex / tax / platform_fee,只計已確認)。

kind
string

'opex' / 'tax' / 'platform_fee'。

amountTwd
number

該 kind 本期費用合計(整數 TWD)。

count
number

該 kind 本期費用筆數。

operatingExpenseTotalTwd
number

公司營業費用合計 = Σ opex / tax / platform_fee(整數 TWD)。

special
object[]

特殊損益逐筆(kind='special',一次性、獨立列,只計已確認)。

id
string

費用列 ID。

categoryId
string

費用科目 ID(特殊損益科目)。

categoryDisplayName
string | null

費用科目顯示名。

description
string

摘要(如 取消神山床位沒收訂金)。

amountTwd
number

金額(整數 TWD ≥ 0,DB CHECK operating_expenses_amount_nonneg)。**第一版 special 一律視為「損」**(扣減淨利,與營業費用同向)——對齊 GS 五月事件「取消神山床位沒收」= 損。schema 無 sign 欄,無法表達一次性「益」;一次性收益(§3.4)落地 sign 欄後再分流, 屆時 specialTotal 改帶號。當前 specialTotalTwd 一律從淨利扣減。

specialTotalTwd
number

特殊損益加總(整數 TWD,第一版一律視為損)。

netProfitTwd
number

公司淨利 = grossMargin + otherIncome − operatingExpenseTotal − specialTotal。

netMarginPct
number | null

淨利率(netProfit / revenueTotal),revenue=0 時 null。

請求
curl -X GET "https://your-tenant.example.com/api/v1/pnl/statement?period=<period>" \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "period": "…",
    "regions": [
      {
        "region": "…",
        "label": "…",
        "revenueTwd": 0,
        "directCostTwd": 0,
        "marginTwd": 0,
        "departures": 0
      }
    ],
    "grossMarginTwd": 0,
    "revenueTotalTwd": 0,
    "extraIncomeTwd": 0,
    "adminFeeIncomeTwd": 0,
    "otherIncomeTwd": 0,
    "expensesByKind": [
      {
        "kind": "…",
        "amountTwd": 0,
        "count": 0
      }
    ],
    "operatingExpenseTotalTwd": 0,
    "special": [
      {
        "id": "…",
        "categoryId": "…",
        "categoryDisplayName": "…",
        "description": "…",
        "amountTwd": 0
      }
    ],
    "specialTotalTwd": 0,
    "netProfitTwd": 0,
    "netMarginPct": 0
  }
}

/reports

tenant monthly

GET/api/v1/reports/monthly
order.read

參數

year必填
integer· max 2100 · min 2000

報表年份(西元四位數),月界以台北時區計

month必填
integer· max 12 · min 1

報表月份,1 至 12

回應欄位 · data

year
number

報表年份(西元四位數)。

month
number

報表月份(1-12,月界以 Asia/Taipei 計)。

totalOrders
number

本月建立的 tour 訂單數(依 created_at 計)。

paidOrders
number

本月有實收現金的 tour 訂單數(月內有 inbound 交易)。

cancelledOrders
number

本月取消的 tour 訂單數(依 updated_at 計)。

totalRevenue
number

collected_cash:本月實收現金 = SUM(payment_transactions in) within month。

refundedAmount
number

refunded_cash:本月退還現金 = SUM(payment_transactions out, refund/chargeback) within month。

netCash
number

net_cash:本月淨現金 = SUM(in:+amount, out:-amount) - SUM(fee) within month。

newCustomers
number

本月新註冊會員數(排除 staff 角色)。

byTrip
object[]

依行程銷售排行(前 10 名,按本月實收現金)。

tripId
string

行程 ID。

tripTitle
string

團名。

orderCount
number

該行程本月有實收現金的訂單數。

revenue
number

collected_cash by trip:本月實收現金(tour-scoped)。

byProvider
object[]

依金流商分組的本月實收現金。

provider
string

金流商代碼(如 ecpay / test)。

orderCount
number

該金流商本月有實收現金的訂單數。

amount
number

collected_cash by provider:本月實收現金(tour-scoped)。

dailyRevenue
object[]

collected_cash by day:本月逐日實收現金(tour-scoped,Asia/Taipei 日界), 整月零填滿(無入帳的日子 amount=0)。Σ amount === totalRevenue,與 KPI 對帳。

day
string

日期(YYYY-MM-DD,Asia/Taipei 日界)。

amount
number

當日實收現金(tour-scoped,整數 TWD)。

請求
curl -X GET "https://your-tenant.example.com/api/v1/reports/monthly?year=<year>&month=<month>" \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "year": 0,
    "month": 0,
    "totalOrders": 0,
    "paidOrders": 0,
    "cancelledOrders": 0,
    "totalRevenue": 0,
    "refundedAmount": 0,
    "netCash": 0,
    "newCustomers": 0,
    "byTrip": [
      {
        "tripId": "…",
        "tripTitle": "…",
        "orderCount": 0,
        "revenue": 0
      }
    ],
    "byProvider": [
      {
        "provider": "…",
        "orderCount": 0,
        "amount": 0
      }
    ],
    "dailyRevenue": [
      {
        "day": "…",
        "amount": 0
      }
    ]
  }
}

/suppliers

廠商目錄列表

GET/api/v1/suppliers
supplier.read模組:accounting

參數

status選填
enum
activeinactiveall

依狀態篩選(active 啟用 / inactive 停用 / all 全部,預設 active)

q選填
string

關鍵字搜尋(廠商名稱或類別)

回應欄位 · data[]

id
string

廠商 ID。

name
string

廠商名稱。

categoryHint
string | null

慣用類別提示(租戶自定,非硬枚舉)。

payeeAccountName
string | null

收款人戶名(批次轉帳檔欄 (1))。

payeeBankCode
string | null

收款銀行代號(批次轉帳檔欄 (3))。

payeeAccountNumber
string | null

收款帳號(批次轉帳檔欄 (2),遮罩回傳)。

status
SupplierStatus

狀態:active 啟用 / inactive 停用(停用不刪)。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/suppliers \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "name": "…",
      "categoryHint": "…",
      "payeeAccountName": "…",
      "payeeBankCode": "…",
      "payeeAccountNumber": "…",
      "status": "…",
      "createdAt": "2026-06-30T08:00:00.000Z",
      "updatedAt": "2026-06-30T08:00:00.000Z"
    }
  ]
}
POST/api/v1/suppliers
supplier.manage模組:accounting

參數

name必填
string· max 120 · min 1

廠商名稱(出款對象顯示名)

categoryHint選填
string· max 60

類別提示(如住宿、交通、餐飲),供分類與搜尋

payeeAccountName選填
string· max 65

收款戶名(須與銀行帳戶登記名一致)

payeeBankCode選填
string· 格式限定

銀行代號(3~7 碼數字,台銀通用四欄轉帳檔用)

payeeAccountNumber選填
string· 格式限定 · max 20

收款銀行帳號(純數字,write-only 寫入後僅回遮罩)

回應欄位 · data

ok
boolean

固定為 true:廠商已新增。

id
string

新建立廠商的 ID(sup_ 前綴)。

請求
curl -X POST https://your-tenant.example.com/api/v1/suppliers \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "<name>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "id": "…"
  }
}

單一廠商主檔

GET/api/v1/suppliers/{id}
supplier.read

參數

id路徑
string· min 1

廠商 id(路徑參數)

回應欄位 · data

id
string

廠商 ID。

name
string

廠商名稱。

categoryHint
string | null

慣用類別提示(租戶自定,非硬枚舉)。

payeeAccountName
string | null

收款人戶名(批次轉帳檔欄 (1))。

payeeBankCode
string | null

收款銀行代號(批次轉帳檔欄 (3))。

payeeAccountNumber
string | null

收款帳號(批次轉帳檔欄 (2),遮罩回傳)。

status
SupplierStatus

狀態:active 啟用 / inactive 停用(停用不刪)。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/suppliers/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "id": "…",
    "name": "…",
    "categoryHint": "…",
    "payeeAccountName": "…",
    "payeeBankCode": "…",
    "payeeAccountNumber": "…",
    "status": "…",
    "createdAt": "2026-06-30T08:00:00.000Z",
    "updatedAt": "2026-06-30T08:00:00.000Z"
  }
}
PATCH/api/v1/suppliers/{id}
supplier.manage模組:accounting

參數

name選填
string· max 120 · min 1

廠商名稱(出款對象顯示名)

categoryHint選填
string· max 60

類別提示(如住宿、交通、餐飲),供分類與搜尋

payeeAccountName選填
string· max 65

收款戶名(須與銀行帳戶登記名一致)

payeeBankCode選填
string· 格式限定

銀行代號(3~7 碼數字,台銀通用四欄轉帳檔用)

payeeAccountNumber選填
string· 格式限定 · max 20

收款銀行帳號(純數字,write-only 寫入後僅回遮罩)

id路徑
string· min 1

廠商 id(路徑參數)

回應欄位 · data

ok
boolean

固定為 true:廠商資料已更新。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/suppliers/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

/audit

list/filter the append-only tenant audit trail

GET/api/v1/audit/log
audit.read

參數

action選填
string

動作代碼篩選,例如 order.update(比對稽核事件的動作)

actor選填
string

操作者篩選,比對執行該動作的使用者 ID

entity選填
string

目標實體篩選,比對被操作對象的類型或 ID

from選填
string

起始時間(ISO 8601),僅回傳此時間之後的事件

to選填
string

結束時間(ISO 8601),僅回傳此時間之前的事件

limit選填
integer· max 1000

回傳筆數上限,最多 1000 筆

回應欄位 · data[]

id
string

稽核事件 ID。

actorUserId
string | null

操作者的使用者 ID;系統事件(webhook/排程等非人為列)為 null。

actorEmail
string | null

操作者 Email;系統事件或帳號已刪時為 null。

actorName
string | null

操作者顯示名;系統事件或帳號已刪時為 null。

action
string

動作代碼,例如 order.create、traveler.decrypt。

targetType
string

被操作對象的類型,例如 order、member。

targetId
string

被操作對象的 ID。

metadata
unknown

該事件的附帶內容(欄位隨動作而異的自由結構 JSON)。

ipAddress
string | null

發起請求的來源 IP;無法取得時為 null。

createdAt
Date

事件發生時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/audit/log \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "actorUserId": "…",
      "actorEmail": "…",
      "actorName": "…",
      "action": "…",
      "targetType": "…",
      "targetId": "…",
      "metadata": "…",
      "ipAddress": "…",
      "createdAt": "2026-06-30T08:00:00.000Z"
    }
  ]
}

audit KPI counts

GET/api/v1/audit/stats
audit.read

參數

actor選填
string

操作者使用者 ID,指定時將統計數據限縮至該操作者

回應欄位 · data

eventsThisMonth
number

本月(Asia/Taipei)稽核事件總數。

eventsToday
number

今日(Asia/Taipei)稽核事件總數。

writesThisMonth
number

本月寫入類事件數(排除 *.read 讀取事件)。

distinctActorsThisMonth
number

本月有動作紀錄的不重複操作者人數。

請求
curl -X GET https://your-tenant.example.com/api/v1/audit/stats \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "eventsThisMonth": 0,
    "eventsToday": 0,
    "writesThisMonth": 0,
    "distinctActorsThisMonth": 0
  }
}

/leaderboard

全公司業務業績排行

GET/api/v1/leaderboard
leaderboard.read

參數

period選填
enum
monthquarteryearall

業績統計區間:當月、當季、當年或全部,預設 month

回應欄位 · data[]

userId
string

業務的使用者 ID。

name
string

業務顯示姓名。

email
string

業務登入 Email。

role
string

業務角色代碼(admin/sales/op/accountant)。

orderCount
number

承作訂單總數(歸屬此業務、含各狀態的旅遊團訂單)。

paidCount
number

已成交訂單數(已付款或履約完成)。

cancelledCount
number

已取消訂單數。

revenue
number

業績額(TWD 整數):歸屬於該業務、未取消訂單的應收合計。

commissionTwd
number

估算佣金 = round(revenue × sales_commission_bps / 10000)(tenant_settings 費率)。

bonusTwd
number

月度第一名加碼 = round(revenue × monthly_top_bonus_bps / 10000),僅當期 rank 1 且 revenue > 0;其餘為 0。與 isMonthlyTop 同步。

isMonthlyTop
boolean

當期 rank 1(revenue > 0)=月度第一,享 bonus。

avgOrderTwd
number

客單均價 = round(revenue / orderCount);0 單為 0。

請求
curl -X GET https://your-tenant.example.com/api/v1/leaderboard \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "userId": "…",
      "name": "…",
      "email": "…",
      "role": "…",
      "orderCount": 0,
      "paidCount": 0,
      "cancelledCount": 0,
      "revenue": 0,
      "commissionTwd": 0,
      "bonusTwd": 0,
      "isMonthlyTop": true,
      "avgOrderTwd": 0
    }
  ]
}

待派發訂單 KPI

GET/api/v1/leaderboard/review-stats
leaderboard.read

回應欄位 · data

pendingCount
number

待派發(pending_review)訂單筆數。

pendingTotalTwd
number

待派發訂單的應收金額合計(新台幣)。

longestWaitHours
number

目前待派發訂單中,最長已等待的時數。

thisMonthAssigned
number

本月(Asia/Taipei)已完成派發的訂單數。

請求
curl -X GET https://your-tenant.example.com/api/v1/leaderboard/review-stats \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "pendingCount": 0,
    "pendingTotalTwd": 0,
    "longestWaitHours": 0,
    "thisMonthAssigned": 0
  }
}

/message-templates

list canned message templates

GET/api/v1/message-templates
message_template.read

參數

channel選填
enum
lineemail

依發送管道篩選範本(line 或 email)

回應欄位 · data[]

id
string

範本 ID。

key
string | null

穩定識別碼(NULL = 未指定)。

stage
"受理" | "審核不通過" | "未成團通知" | "中籤通知" | "行前說明" | "收尾款" | "訂餐調查" | "裝備調查" | "出團完成"

SOP 階段(受理 → 出團完成)。

channel
"email" | "line"

發送管道:line 或 email。

title
string

範本標題。

bodySingle
string

單人版內文(含 {{...}} 合併變數)。

bodyMulti
string | null

多人版變體;NULL = 只有單人版。

isActive
boolean

是否為該階段目前啟用的範本。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

updatedBy
string | null

最後更新者姓名(LEFT JOIN 同庫 user;未知 / 帳號已刪為 null)。

請求
curl -X GET https://your-tenant.example.com/api/v1/message-templates \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "key": "…",
      "stage": "受理",
      "channel": "email",
      "title": "…",
      "bodySingle": "…",
      "bodyMulti": "…",
      "isActive": true,
      "createdAt": "2026-06-30T08:00:00.000Z",
      "updatedAt": "2026-06-30T08:00:00.000Z",
      "updatedBy": "…"
    }
  ]
}
POST/api/v1/message-templates
message_template.manage

參數

key選填
string

範本識別碼,2–64 碼大寫英數 / _ / -(用於程式化引用,選填,自動轉大寫)

stage必填
enum

訊息對應的 SOP 階段

channel必填
enum

發送管道(line 或 email)

title必填
string· max 200 · min 1

範本標題(供後台辨識)

bodySingle必填
string· max 5000 · min 1

單人版訊息內文

bodyMulti選填
string· max 5000

多人版訊息內文(留空表示沿用單人版;選填)

isActive選填
boolean

是否啟用(停用後不出現在可選範本中)

回應欄位 · data

id
string

新建立的訊息範本 ID。

請求
curl -X POST https://your-tenant.example.com/api/v1/message-templates \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "stage": "<stage>",
    "channel": "<channel>",
    "title": "<title>",
    "bodySingle": "<bodySingle>"
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…"
  }
}

single canned message template detail.

GET/api/v1/message-templates/{id}
message_template.read

參數

id路徑
string· min 1

訊息範本 ID

回應欄位 · data

id
string

範本 ID。

key
string | null

穩定識別碼(NULL = 未指定)。

stage
"受理" | "審核不通過" | "未成團通知" | "中籤通知" | "行前說明" | "收尾款" | "訂餐調查" | "裝備調查" | "出團完成"

SOP 階段(受理 → 出團完成)。

channel
"email" | "line"

發送管道:line 或 email。

title
string

範本標題。

bodySingle
string

單人版內文(含 {{...}} 合併變數)。

bodyMulti
string | null

多人版變體;NULL = 只有單人版。

isActive
boolean

是否為該階段目前啟用的範本。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

updatedBy
string | null

最後更新者姓名(LEFT JOIN 同庫 user;未知 / 帳號已刪為 null)。

請求
curl -X GET https://your-tenant.example.com/api/v1/message-templates/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "id": "…",
    "key": "…",
    "stage": "受理",
    "channel": "email",
    "title": "…",
    "bodySingle": "…",
    "bodyMulti": "…",
    "isActive": true,
    "createdAt": "2026-06-30T08:00:00.000Z",
    "updatedAt": "2026-06-30T08:00:00.000Z",
    "updatedBy": "…"
  }
}
PATCH/api/v1/message-templates/{id}
message_template.manage

參數

id路徑
string· min 1

要更新的訊息範本 ID

key選填
string

範本識別碼,2–64 碼大寫英數 / _ / -(用於程式化引用,選填,自動轉大寫)

stage必填
enum

訊息對應的 SOP 階段

channel必填
enum

發送管道(line 或 email)

title必填
string· max 200 · min 1

範本標題(供後台辨識)

bodySingle必填
string· max 5000 · min 1

單人版訊息內文

bodyMulti選填
string· max 5000

多人版訊息內文(留空表示沿用單人版;選填)

isActive選填
boolean

是否啟用(停用後不出現在可選範本中)

回應欄位 · data

ok
boolean

是否成功更新訊息範本。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/message-templates/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "stage": "<stage>",
    "channel": "<channel>",
    "title": "<title>",
    "bodySingle": "<bodySingle>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}
DELETE/api/v1/message-templates/{id}
message_template.manage

參數

id路徑
string· min 1

訊息範本 ID

回應欄位 · data

ok
boolean

是否成功刪除訊息範本。

請求
curl -X DELETE https://your-tenant.example.com/api/v1/message-templates/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

enable / disable

POST/api/v1/message-templates/{id}/active
message_template.manage

參數

id路徑
string· min 1

要啟用 / 停用的訊息範本 ID

isActive必填
boolean

true 啟用、false 停用(軟刪除)此範本

回應欄位 · data

ok
boolean

是否成功切換訊息範本的啟用狀態。

請求
curl -X POST https://your-tenant.example.com/api/v1/message-templates/<id>/active \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "isActive": true
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

/roles

list all roles

GET/api/v1/roles
role.manage

參數

system選填
enum
truefalse

是否只列內建角色:true 僅內建、false 僅自訂,省略則全部

回應欄位 · data[]

id
string

角色 ID(內建角色為其代碼)。

name
string

角色代碼(小寫英數與底線,建立後不可改;即帳號綁定的角色值)。

label
string

角色顯示名稱。

isSystem
boolean

是否為系統內建角色(內建角色不可修改或刪除)。

permissionCount
number

該角色目前擁有的 (resource, action) 數量。

memberCount
number

持有此角色的使用者人數。

請求
curl -X GET https://your-tenant.example.com/api/v1/roles \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "name": "…",
      "label": "…",
      "isSystem": true,
      "permissionCount": 0,
      "memberCount": 0
    }
  ]
}
POST/api/v1/roles
role.manage

參數

name必填
string

角色代碼,小寫英數與底線、2–32 字且須以字母開頭,建立後不可改

label必填
string

角色顯示名稱,呈現於後台角色清單

permissions選填
array

此角色授予的權限清單,每筆為一組資源與動作

回應欄位 · data

id
string

新建立的角色 ID。

請求
curl -X POST https://your-tenant.example.com/api/v1/roles \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "<name>",
    "label": "<label>"
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…"
  }
}

one role + its full

GET/api/v1/roles/{id}
role.manage

參數

id路徑
string· min 1

角色 ID(內建角色為其代碼)

回應欄位 · data

id
string

角色 ID(內建角色為其代碼)。

name
string

角色代碼(小寫英數與底線,建立後不可改;即帳號綁定的角色值)。

label
string

角色顯示名稱。

isSystem
boolean

是否為系統內建角色(內建角色不可修改或刪除)。

permissions
object[]

此角色授予的完整 (resource, action) 權限清單。

resource
string

權限資源代碼,例如 order、member。

action
string

權限動作代碼,例如 read、update。

請求
curl -X GET https://your-tenant.example.com/api/v1/roles/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "id": "…",
    "name": "…",
    "label": "…",
    "isSystem": true,
    "permissions": [
      {
        "resource": "…",
        "action": "…"
      }
    ]
  }
}
PATCH/api/v1/roles/{id}
role.manage

參數

id路徑
string· min 1

欲更新的角色 ID

label必填
string

角色顯示名稱,呈現於後台角色清單

permissions選填
array

完整取代後的權限清單,會整批覆寫此角色現有權限

回應欄位 · data

ok
boolean

是否成功更新角色。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/roles/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "<label>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}
DELETE/api/v1/roles/{id}
role.manage

參數

id路徑
string· min 1

角色 ID(內建角色為其代碼)

回應欄位 · data

ok
boolean

是否成功刪除角色。

請求
curl -X DELETE https://your-tenant.example.com/api/v1/roles/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

the code-defined permission catalog: every legal

GET/api/v1/roles/catalog
role.manage

回應欄位 · data[]

resource
string

權限資源代碼,例如 order、member。

actions
string[]

此資源可授予的動作代碼清單,例如 read、update。

請求
curl -X GET https://your-tenant.example.com/api/v1/roles/catalog \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "resource": "…",
      "actions": [
        "…"
      ]
    }
  ]
}

/settings

the tenant_settings singleton

GET/api/v1/settings
role.manage

回應欄位 · data

id
string

設定列 ID(單例,恆為 'singleton')。

companyName
string | null

公司全名,顯示於發票、合約與對外信件抬頭;null = 未設定。

companyPhone
string | null

公司聯絡電話,顯示於對外文件;null = 未設定。

taxId
string | null

公司統一編號(8 位數字),用於開立發票;null = 未設定。

companyAddress
string | null

公司登記地址,顯示於對外文件;null = 未設定。

logoUrl
string | null

公司 Logo 圖片網址,用於後台與對外頁面品牌呈現;null = 未設定。

siteTagline
string | null

公開站標語(SEO/首頁);null = 未設定。

seoDefaultDescription
string | null

公開站預設 SEO meta description;null = 未設定。

ogImageUrl
string | null

社群分享預設 Open Graph 圖片網址;null = 未設定。

emailReplyTo
string | null

系統寄信時的回覆收件信箱;null = 未設定。

assignmentMode
string

S5: 'auto_round_robin' | 'auto_customer_choice' | 'manual_review'

defaultAssigneeUserId
string | null

S5: fallback assignee when round-robin finds no active sales, etc.

allowSalesClaim
boolean

order-assignment §6:業務自派搶單開關(per-tenant opt-in,預設 false)。

passportExpiryWarningDays
number

護照效期提醒天數(document-expiry §4.1;NOT NULL DEFAULT 180)。

groupCodePattern
string | null

團號 token 樣板(如 '{YY}{region}{airline?}{MMDD}{seq}')。NULL = 內建預設。

groupCodeSeqStyle
string

序號樣式:'alpha' | 'alpha_no_io' | 'numeric'(NOT NULL DEFAULT 'alpha')。

groupCodeSeqWidth
number

numeric 序號補零寬度(NOT NULL DEFAULT 2;alpha 樣式忽略)。

ecpayFeeBps
number

預估綠界手續費率(270 = 2.70%)。NOT NULL DEFAULT 270。

fongshouFeeBps
number

預估豐收款手續費率(50 = 0.50%)。NOT NULL DEFAULT 50。

profitTaxBps
number

預估發票 / 營所稅率(500 = 5.00%)。NOT NULL DEFAULT 500。

salesCommissionBps
number

業務抽成率(1000 = 10.00%)。NOT NULL DEFAULT 1000。

monthlyTopBonusBps
number

月度第一名加碼率(500 = 5.00%)。NOT NULL DEFAULT 500。

ecpayMerchantId
string | null

ECPay 特店 ID(明文,顯示用)。null = 未綁定租戶憑證(走 env 過渡)。

ecpaySecretsMask
string | null

ECPay HashKey/HashIV 的遮罩碼(`****` + 末 4)。DTO **只暴露 mask**, 整包 EncryptedField(含密文)永不出 repo —— 顯示用零 KMS 呼叫。

travelinvoiceMerchantId
string | null

代收轉付 travelinvoice 特店 ID(明文,顯示用)。null = 未綁定租戶憑證(fail-closed)。

travelinvoiceSecretsMask
string | null

travelinvoice HashKey/HashIV 的遮罩碼(`****` + 末 4)。DTO **只暴露 mask**, 整包 EncryptedField(含密文)永不出 repo —— 顯示用零 KMS 呼叫。

sendingDomain
string | null

自有寄件 domain 快照;server 派生(enableSendingDomain),非自由輸入。

resendDomainId
string | null

寄件服務商(Resend)的 domain 識別碼;null = 未設定自有寄件網域。

sendingDomainStatus
string | null

自有寄件網域的驗證狀態(如 pending/verified);null = 未設定。

senderLocalPart
string | null

寄件人 local-part,未填視為 'info'。

updatedAt
Date

設定最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/settings \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "id": "…",
    "companyName": "…",
    "companyPhone": "…",
    "taxId": "…",
    "companyAddress": "…",
    "logoUrl": "…",
    "siteTagline": "…",
    "seoDefaultDescription": "…",
    "ogImageUrl": "…",
    "emailReplyTo": "…",
    "assignmentMode": "…",
    "defaultAssigneeUserId": "…",
    "allowSalesClaim": true,
    "passportExpiryWarningDays": 0,
    "groupCodePattern": "…",
    "groupCodeSeqStyle": "…",
    "groupCodeSeqWidth": 0,
    "ecpayFeeBps": 0,
    "fongshouFeeBps": 0,
    "profitTaxBps": 0,
    "salesCommissionBps": 0,
    "monthlyTopBonusBps": 0,
    "ecpayMerchantId": "…",
    "ecpaySecretsMask": "…",
    "travelinvoiceMerchantId": "…",
    "travelinvoiceSecretsMask": "…",
    "sendingDomain": "…",
    "resendDomainId": "…",
    "sendingDomainStatus": "…",
    "senderLocalPart": "…",
    "updatedAt": "2026-06-30T08:00:00.000Z"
  }
}
PATCH/api/v1/settings
role.manage

參數

companyName選填
string· max 200

公司全名,顯示於發票、合約與對外信件抬頭;傳 null 或空字串清除

companyPhone選填
string· max 40

公司聯絡電話,顯示於對外文件;傳 null 或空字串清除

taxId選填
value

公司統一編號(8 位數字),用於開立發票;傳 null 或空字串清除

companyAddress選填
string· max 500

公司登記地址,顯示於對外文件;傳 null 或空字串清除

logoUrl選填
value

公司 Logo 圖片網址(http/https),用於後台與對外頁面品牌呈現;傳 null 或空字串清除

emailReplyTo選填
value

系統寄信時的回覆收件信箱,客戶回信會寄到此處;傳 null 或空字串清除

senderLocalPart選填
value

寄件人信箱的帳號部分(@ 前段),與寄件網域組成完整寄件地址;傳 null 或空字串清除

passportExpiryWarningDays選填
integer· max 3650 · min 1

護照到期前提早幾天提醒(1 至 3650 天),用於行前護照效期預警

回應欄位 · data

ok
boolean

是否成功更新租戶設定。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/settings \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

the staff pool eligible to be an

GET/api/v1/settings/assignable-staff
role.manage

回應欄位 · data[]

userId
string

員工的使用者 ID(作為指派對象)。

name
string

員工顯示姓名。

email
string

員工登入 Email。

role
string

員工角色代碼(sales/admin 等可指派角色)。

thisMonthAssigned
number

本月(Asia/Taipei)已指派給此員工的訂單數(供輪派負載參考)。

請求
curl -X GET https://your-tenant.example.com/api/v1/settings/assignable-staff \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "userId": "…",
      "name": "…",
      "email": "…",
      "role": "…",
      "thisMonthAssigned": 0
    }
  ]
}

S5 order-assignment mode + default

PATCH/api/v1/settings/assignment
role.manage

參數

assignmentMode必填
enum
auto_round_robinauto_customer_choiceauto_by_destinationmanual_review

訂單指派模式:auto_round_robin 輪流自動指派、auto_customer_choice 依客戶選擇指派、auto_by_destination 依目的地地區碼對應規則指派、manual_review 進待審由人工指派

defaultAssigneeUserId選填
string

預設承辦人員的使用者 ID,自動指派找不到對象時的兜底承辦人;空字串表示不設預設

allowSalesClaim選填
boolean

是否開放業務自派搶單(從待派發池自行搶單);未提供則不變更

回應欄位 · data

ok
boolean

是否成功更新訂單指派模式設定。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/settings/assignment \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "assignmentMode": "auto_round_robin"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}
PUT/api/v1/settings/ecpay-credentials
role.manage

參數

merchantId必填
string· max 20 · min 1

綠界 ECPay 特店編號(MerchantID),用於金流請款與簽章

hashKey必填
string· max 100 · min 1

綠界 ECPay HashKey,CheckMacValue 簽章用密鑰;寫入後即 KMS 加密儲存且永不回傳

hashIv必填
string· max 100 · min 1

綠界 ECPay HashIV,CheckMacValue 簽章用初始向量;寫入後即 KMS 加密儲存且永不回傳

回應欄位 · data

ok
boolean

是否成功儲存 ECPay 憑證(HashKey/HashIV 已 KMS 加密,永不回傳)。

請求
curl -X PUT https://your-tenant.example.com/api/v1/settings/ecpay-credentials \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "merchantId": "<merchantId>",
    "hashKey": "<hashKey>",
    "hashIv": "<hashIv>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}
DELETE/api/v1/settings/ecpay-credentials
role.manage

回應欄位 · data

ok
boolean

是否成功清除 ECPay 憑證。

請求
curl -X DELETE https://your-tenant.example.com/api/v1/settings/ecpay-credentials \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

公司營業費用類別目錄

GET/api/v1/settings/expense-categories
operating_expense.read模組:accounting

參數

activeOnly選填
boolean

是否只回傳啟用中的費用類別(true/false);省略則含停用

回應欄位 · data[]

id
string

費用類別 ID。

code
string

科目代碼(租戶內唯一穩定識別,如 rent / salary_admin / tax_vat)。

displayName
string

顯示名(如 房租 / 行政薪資 / 營業稅)。

kind
"opex" | "tax" | "platform_fee" | "special"

費用大類:opex 營業費用 / tax 稅 / platform_fee 平台手續費 / special 特殊損益(損益表據此 roll-up)。

isActive
boolean

是否啟用(停用不刪,既有費用列仍引用得到)。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/settings/expense-categories \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "code": "…",
      "displayName": "…",
      "kind": "opex",
      "isActive": true,
      "createdAt": "2026-06-30T08:00:00.000Z",
      "updatedAt": "2026-06-30T08:00:00.000Z"
    }
  ]
}
POST/api/v1/settings/expense-categories
operating_expense.manage模組:accounting

參數

code必填
string· 格式限定 · max 40 · min 1

費用類別代碼(小寫英數與底線),建立後不可變更,作為類別的穩定識別

displayName必填
string· max 100 · min 1

費用類別顯示名稱,呈現於後台費用登錄與報表

kind必填
enum

費用類別種類:opex 營業費用、tax 稅務、platform_fee 平台手續費、special 特殊,影響損益表歸類

回應欄位 · data

id
string

新建立的費用類別 ID。

請求
curl -X POST https://your-tenant.example.com/api/v1/settings/expense-categories \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "<code>",
    "displayName": "<displayName>",
    "kind": "<kind>"
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…"
  }
}

更新費用類別的顯示名 / kind +

PATCH/api/v1/settings/expense-categories/{id}
operating_expense.manage模組:accounting

參數

id路徑
string· min 1

費用類別 ID(路徑參數),指定要更新的類別

displayName必填
string· max 100 · min 1

費用類別顯示名稱,呈現於後台費用登錄與報表

kind必填
enum

費用類別種類:opex 營業費用、tax 稅務、platform_fee 平台手續費、special 特殊,影響損益表歸類

isActive必填
boolean

是否啟用此費用類別;false 為停用(停用而非刪除)

回應欄位 · data

ok
boolean

是否成功更新費用類別。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/settings/expense-categories/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "displayName": "<displayName>",
    "kind": "<kind>",
    "isActive": true
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

toggle a費用類別

PATCH/api/v1/settings/expense-categories/{id}/active
operating_expense.manage模組:accounting

參數

id路徑
string· min 1

費用類別 ID(路徑參數),指定要切換啟用狀態的類別

isActive必填
boolean

目標啟用狀態:true 啟用、false 停用(停用而非刪除)

回應欄位 · data

ok
boolean

是否成功切換費用類別的啟用狀態。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/settings/expense-categories/<id>/active \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "isActive": true
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

fee-category → final receiving

GET/api/v1/settings/fee-category-routes
receiving_account.manage模組:accounting

回應欄位 · data[]

id
string

路由設定 ID。

feeCategory
string

費用類型代碼(租戶自定唯一鍵,如 tour_fee/lodging/equipment)。

displayName
string

費用類型顯示名。

finalAccountId
string

此費用類型最終結算進的收款帳戶 ID。

finalAccountName
string | null

final 帳戶顯示名(JOIN receiving_accounts;帳戶被刪則 null,但 FK restrict 一般不會)。

finalAccountCode
string | null

final 帳戶代號。

isActive
boolean

此路由是否啟用。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/settings/fee-category-routes \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "feeCategory": "…",
      "displayName": "…",
      "finalAccountId": "…",
      "finalAccountName": "…",
      "finalAccountCode": "…",
      "isActive": true,
      "createdAt": "2026-06-30T08:00:00.000Z",
      "updatedAt": "2026-06-30T08:00:00.000Z"
    }
  ]
}
PUT/api/v1/settings/fee-category-routes
receiving_account.manage模組:accounting

參數

feeCategory必填
string· 格式限定 · max 40 · min 1

費用類型代碼(小寫英數與底線),此 upsert 的唯一鍵;決定該手續費類型最終結算到哪個帳戶

displayName必填
string· max 100 · min 1

費用類型路由的顯示名稱,呈現於對帳設定

finalAccountId必填
string· min 1

此費用類型最終結算進的收款帳戶 ID

isActive選填
boolean

是否啟用此費用類型路由;省略則維持預設啟用

回應欄位 · data

id
string

新建立或更新的費用類型路由 ID。

請求
curl -X PUT https://your-tenant.example.com/api/v1/settings/fee-category-routes \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "feeCategory": "<feeCategory>",
    "displayName": "<displayName>",
    "finalAccountId": "<finalAccountId>"
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…"
  }
}

toggle a fee-category

PATCH/api/v1/settings/fee-category-routes/{id}/active
receiving_account.manage模組:accounting

參數

id路徑
string· min 1

費用類型路由 ID(路徑參數,非 feeCategory 代碼),指定要切換啟用狀態的路由

isActive必填
boolean

目標啟用狀態:true 啟用、false 停用(停用而非刪除)

回應欄位 · data

ok
boolean

是否成功切換費用類型路由的啟用狀態。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/settings/fee-category-routes/<id>/active \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "isActive": true
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

internal/external-ledger profit estimate

PATCH/api/v1/settings/ledger-fees
role.manage模組:accounting

參數

ecpayFeeBps選填
value

綠界 ECPay 金流手續費率,單位 basis points(0..10000,10000=100%),用於內外帳淨利試算;留空不變更

fongshouFeeBps選填
value

豐收金流手續費率,單位 basis points(0..10000,10000=100%),用於內外帳淨利試算;留空不變更

profitTaxBps選填
value

淨利稅率,單位 basis points(0..10000,10000=100%),用於內外帳淨利試算;留空不變更

回應欄位 · data

ok
boolean

是否成功更新內外帳淨利試算的預估費率。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/settings/ledger-fees \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

the tenant's enabled plan modules

GET/api/v1/settings/modules
role.manage

回應欄位 · data

climbing
boolean

是否啟用登山團功能模組。

overseas
boolean

是否啟用海外/出國團功能模組。

lodging
boolean

是否啟用訂房子系統模組。

accounting
boolean

是否啟用進階會計子系統模組。

lottery
boolean

是否啟用抽籤子系統模組。

請求
curl -X GET https://your-tenant.example.com/api/v1/settings/modules \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "climbing": true,
    "overseas": true,
    "lodging": true,
    "accounting": true,
    "lottery": true
  }
}

the收款帳戶目錄

GET/api/v1/settings/receiving-accounts
receiving_account.manage模組:accounting

參數

activeOnly選填
boolean

是否只回傳啟用中的收款帳戶(true/false);省略則含停用

回應欄位 · data[]

id
string

收款帳戶 ID。

code
string

帳戶代碼(租戶內唯一穩定識別)。

displayName
string

帳戶顯示名。

kind
ReceivingAccountKind

帳戶類型:bank 銀行 / cash 現金 / gateway 金流閘道。

bankName
string | null

銀行名稱;現金/閘道帳戶為 null。

accountNo
string | null

銀行帳號;現金/閘道帳戶為 null。

canReceive
boolean

可收款(幾乎都 true)。

canRemit
boolean

可對外匯款(ATM / 匯出退款 / 補款匯出)。荒野只有永豐。

canChargeback
boolean

可刷退(退回原信用卡)。荒野只有綠界(gateway)。

isDeprecated
boolean

廢帳戶:仍可零星收款,但其收款需由他帳戶代墊歸集。荒野=RU 台銀 / 登山社。

isSettlementMaster
boolean

主結算帳戶:所有資金最終向它彙整。每租戶恰一個(partial unique index)。荒野=永豐。

currency
string

帳戶幣別(ISO 4217;既有帳戶皆 'TWD',外幣帳戶如 IDR / USD)。

isActive
boolean

此帳戶是否啟用。

displayOrder
number

後台清單排序序位(小者在前)。

usedCount
number

被多少 payment_transactions 引用(UI 鎖頭 / 「使用中 N」)。

createdAt
Date

建立時間。

updatedAt
Date

最後更新時間。

請求
curl -X GET https://your-tenant.example.com/api/v1/settings/receiving-accounts \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "id": "…",
      "code": "…",
      "displayName": "…",
      "kind": "…",
      "bankName": "…",
      "accountNo": "…",
      "canReceive": true,
      "canRemit": true,
      "canChargeback": true,
      "isDeprecated": true,
      "isSettlementMaster": true,
      "currency": "…",
      "isActive": true,
      "displayOrder": 0,
      "usedCount": 0,
      "createdAt": "2026-06-30T08:00:00.000Z",
      "updatedAt": "2026-06-30T08:00:00.000Z"
    }
  ]
}
POST/api/v1/settings/receiving-accounts
receiving_account.manage模組:accounting

參數

code必填
string· max 40 · min 1

收款帳戶代號,建立後不可變更,作為帳戶的穩定識別

displayName必填
string· max 100 · min 1

收款帳戶顯示名稱,呈現於收款與對帳介面

kind必填
enum
bankcashgateway

帳戶種類:bank 銀行帳戶、cash 現金、gateway 金流閘道

bankName選填
string· max 100

銀行名稱(bank 類別適用);空字串清除

accountNo選填
string· max 50

銀行帳號(bank 類別適用);空字串清除

currency選填
value

帳戶幣別,ISO 4217 三碼(如 TWD / JPY / IDR);空字串預設 TWD,非 TWD 即為外幣池

displayOrder選填
integer· max 9999 · min 0

排序權重(0..9999),數字越小越前面;預設 0

isActive選填
boolean

是否啟用此帳戶;省略維持預設

canReceive選填
boolean

是否可作為收款(進帳)帳戶

canRemit選填
boolean

是否可作為出款(匯出)帳戶

canChargeback選填
boolean

是否可作為退款 / 退刷帳戶

isDeprecated選填
boolean

是否標記為已淘汰(保留歷史紀錄但不再新用)

isSettlementMaster選填
boolean

是否為主結算帳戶;每租戶僅能有一個,月結互抵以此為彙整中心

回應欄位 · data

id
string

新建立的收款帳戶 ID。

請求
curl -X POST https://your-tenant.example.com/api/v1/settings/receiving-accounts \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "<code>",
    "displayName": "<displayName>",
    "kind": "bank"
  }'
回應
{
  "ok": true,
  "data": {
    "id": "…"
  }
}

update a收款帳戶

PATCH/api/v1/settings/receiving-accounts/{id}
receiving_account.manage模組:accounting

參數

id路徑
string· min 1

收款帳戶 ID(路徑參數),指定要更新的帳戶

displayName必填
string· max 100 · min 1

收款帳戶顯示名稱,呈現於收款與對帳介面

kind必填
enum
bankcashgateway

帳戶種類:bank 銀行帳戶、cash 現金、gateway 金流閘道

bankName選填
string· max 100

銀行名稱(bank 類別適用);空字串清除

accountNo選填
string· max 50

銀行帳號(bank 類別適用);空字串清除

currency選填
value

帳戶幣別,ISO 4217 三碼(如 TWD / JPY / IDR);空字串預設 TWD,非 TWD 即為外幣池

displayOrder必填
integer· max 9999 · min 0

排序權重(0..9999),數字越小越前面

isActive選填
boolean

是否啟用此帳戶;省略維持原值

canReceive選填
boolean

是否可作為收款(進帳)帳戶

canRemit選填
boolean

是否可作為出款(匯出)帳戶

canChargeback選填
boolean

是否可作為退款 / 退刷帳戶

isDeprecated選填
boolean

是否標記為已淘汰(保留歷史紀錄但不再新用)

isSettlementMaster選填
boolean

是否為主結算帳戶;每租戶僅能有一個,月結互抵以此為彙整中心

回應欄位 · data

ok
boolean

是否成功更新收款帳戶。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/settings/receiving-accounts/<id> \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "displayName": "<displayName>",
    "kind": "bank",
    "displayOrder": 0
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

the tenant's custom email sending-domain

GET/api/v1/settings/sending-domain
role.manage

回應欄位 · data

sendingDomain
string | null

自有寄件網域;未設定時為 null。

resendDomainId
string | null

寄件服務商(Resend)的網域識別碼;未設定時為 null。

sendingDomainStatus
string | null

網域驗證狀態(如 pending/verified);未設定時為 null。

senderLocalPart
string | null

寄件人信箱的帳號部分(@ 前段);未填視為 info。

records
object[]

待設定的 DNS 記錄清單(SPF/DKIM 等);Resend 不可達或未設定時為空陣列。

record
string

DNS 記錄用途分類(如 DKIM/SPF 等,來自 Resend)。

name
string

記錄主機名(需在網域 DNS 新增的 host)。

type
string

記錄類型(如 TXT/MX/CNAME)。

value
string

記錄值(需填入 DNS 的內容)。

ttl選填
string | undefined

存活時間(TTL);未指定時省略。

status選填
string | undefined

此筆記錄的驗證狀態(如 pending/verified);未指定時省略。

priority選填
number | undefined

MX 記錄優先權;非 MX 記錄省略。

請求
curl -X GET https://your-tenant.example.com/api/v1/settings/sending-domain \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "sendingDomain": "…",
    "resendDomainId": "…",
    "sendingDomainStatus": "…",
    "senderLocalPart": "…",
    "records": [
      {
        "record": "…",
        "name": "…",
        "type": "…",
        "value": "…",
        "ttl": "…",
        "status": "…",
        "priority": 0
      }
    ]
  }
}

tear down the tenant's custom

POST/api/v1/settings/sending-domain/disable
role.manage

回應欄位 · data

ok
boolean

是否成功停用自有寄件網域。

請求
curl -X POST https://your-tenant.example.com/api/v1/settings/sending-domain/disable \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

provision the tenant's custom

POST/api/v1/settings/sending-domain/enable
role.manage

回應欄位 · data

ok
boolean

是否成功啟用自有寄件網域。

domain
string

啟用的寄件網域(由綁定的站台網域派生)。

請求
curl -X POST https://your-tenant.example.com/api/v1/settings/sending-domain/enable \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "domain": "…"
  }
}

re-sync DNS verification status

POST/api/v1/settings/sending-domain/verify
role.manage

回應欄位 · data

ok
boolean

是否成功觸發驗證狀態同步。

status
string

從 Resend 同步回來的最新網域驗證狀態(如 pending/verified)。

請求
curl -X POST https://your-tenant.example.com/api/v1/settings/sending-domain/verify \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true,
    "status": "…"
  }
}

SEO defaults subset of tenant_settings

PATCH/api/v1/settings/seo
role.manage

參數

siteTagline選填
string· max 120

網站標語,顯示於公開站標題與品牌呈現;空字串清除

seoDefaultDescription選填
string· max 300

SEO 預設頁面描述(meta description),未個別設定的頁面套用此值;空字串清除

ogImageUrl選填
value

社群分享預設縮圖(Open Graph image)網址(http/https);空字串清除

回應欄位 · data

ok
boolean

是否成功更新公開站 SEO 設定。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/settings/seo \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{

  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

/staff

list every staffer in the tenant DB

GET/api/v1/staff
role.manage

回應欄位 · data[]

userId
string

員工的使用者 ID。

email
string

員工登入 Email(帳號識別)。

name
string

員工顯示姓名。

role
string

員工角色代碼(admin/sales/op/accountant)。

createdAt
Date

帳號建立時間。

banned
boolean

Account frozen via ban (離職 / 停權).

twoFactorEnabled
boolean

是否已完成 TOTP 兩步驟驗證註冊。

emailVerified
boolean

Email 是否已驗證(可視為「受邀者至少完成過一次登入」)。

pending
boolean

派生的「邀請待完成」狀態:帳號已建立,但受邀者尚未驗證 Email 也未註冊 2FA(未完成首次登入)。

請求
curl -X GET https://your-tenant.example.com/api/v1/staff \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": [
    {
      "userId": "…",
      "email": "…",
      "name": "…",
      "role": "…",
      "createdAt": "2026-06-30T08:00:00.000Z",
      "banned": true,
      "twoFactorEnabled": true,
      "emailVerified": true,
      "pending": true
    }
  ]
}

remove a staffer

DELETE/api/v1/staff/{userId}
role.manage

參數

userId路徑
string· min 1

欲移除員工身分的使用者 ID(將降為一般顧客)

回應欄位 · data

ok
boolean

是否成功移除員工身分(降為一般顧客)。

請求
curl -X DELETE https://your-tenant.example.com/api/v1/staff/<userId> \
  -H "Authorization: Bearer $CAIRN_TOKEN"
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

change a staffer's role

PATCH/api/v1/staff/{userId}/role
role.manage

參數

userId路徑
string· min 1

欲變更角色的員工使用者 ID

role必填
string

變更後的員工角色(admin/sales/op/accountant),決定權限範圍

回應欄位 · data

ok
boolean

是否成功變更員工角色。

請求
curl -X PATCH https://your-tenant.example.com/api/v1/staff/<userId>/role \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "role": "<role>"
  }'
回應
{
  "ok": true,
  "data": {
    "ok": true
  }
}

建立一個新員工帳號

POST/api/v1/staff/invite
role.manage

參數

email必填
string · email· max 120

受邀員工的登入 Email,作為帳號識別

name必填
string· max 100 · min 1

員工顯示姓名

role必填
string· min 1

指派的員工角色(admin/sales/op/accountant),決定權限範圍

回應欄位 · data

userId
string

新建立員工的使用者 ID。

tempPassword
string

一次性明文暫時密碼,僅此次回傳(請立即轉交並要求員工首次登入改密)。

email
string

新員工的登入 Email。

role
string

指派的員工角色(admin/sales/op/accountant)。

請求
curl -X POST https://your-tenant.example.com/api/v1/staff/invite \
  -H "Authorization: Bearer $CAIRN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "<email>",
    "name": "<name>",
    "role": "<role>"
  }'
回應
{
  "ok": true,
  "data": {
    "userId": "…",
    "tempPassword": "…",
    "email": "…",
    "role": "…"
  }
}

Command Palette

Search for a command to run...