# 號卡平台渠道 API

版本：0.24.0 · 2026-10-04

API 基礎網址：`https://api.roguemobile.hk/v1`

[線上 API 文件](https://api.roguemobile.hk/docs/?lang=zh-Hant)

## 帳戶與 API Key

平台提供渠道帳戶（即渠道代碼）和固定 API Key。每次請求在標頭中同時傳入這兩個值，無需登入、取得臨時 token 或更新權杖。

```http
X-Partner-Id: YOUR_CHANNEL_CODE
X-API-Key: YOUR_API_KEY
Content-Type: application/json
```

先用餘額查詢測試接入：

```bash
curl 'https://api.roguemobile.hk/v1/balance' \
  -H 'X-Partner-Id: YOUR_CHANNEL_CODE' \
  -H 'X-API-Key: YOUR_API_KEY'
```

請將佔位值替換為自己的憑證。Key 不會定時到期；重置後舊值立即失效。渠道代碼變更後須更新 `X-Partner-Id`。憑證由渠道伺服器透過 HTTPS 發送，不放在公開網頁或 URL 中，也不要同時發送 `Authorization` 標頭。

本文路徑均相對於 `/v1`，不要重複加上 `/v1`。JSON 請求使用 `Content-Type: application/json`；正常回應使用 `data` 和 `meta`，HTTP 錯誤回應使用 `error` 和 `meta`。`/ledger/export` 成功時返回 CSV。文件語言切換不改變 API 欄位、狀態值或錯誤碼；程式應依錯誤碼判斷，不依賴可讀 `message` 的文字或語言。

選填欄位可省略；只有結構定義明確允許時才可傳 `null`。例如 `txid: null` 或 `change_type: null` 返回 HTTP 400，不會自動產生交易號或選擇即日續費。查詢參數須符合文件列出的格式及可選值；同一個單值參數重複傳入、無效日期或錯誤的布林值返回 400，不會忽略錯誤條件而擴大查詢範圍。

## 最小接入流程

| 步驟 | 呼叫 | 渠道需要做的事 |
| --- | --- | --- |
| 開卡時選擇套餐和城市 | `GET /regional-catalog?orderable=true` | 保存選中的 `catalog_entry_id`，一個值對應套餐和地址 |
| 提交業務 | 選擇下方四類業務之一的 POST 範例 | 至少一條明細，不設固定條數上限；建議提供渠道內唯一的 `txid` |
| 取得結果 | `GET /jobs/{id}` 或回呼 | 保存返回的 `data.job.id`；依逐卡最終狀態判斷成功或失敗 |

續費、重新啟用沿用已有線路，不需要再次查套餐目錄。每次辦理前也無需先查餘額、校驗地址或同步卡片：平台會檢查歸屬、價格和整批餘額。未登記識別資料的舊卡可能需要先同步一次。HTTP 202 只表示已受理，並非已完成。

可以先只對接查單。需要自動通知時，再一次性登記 HTTPS 回呼地址並取得獨立的 Webhook Secret，每筆業務不用重傳回呼地址。異常恢復介面僅在異常時使用。

範例號碼和目錄 ID 是佔位值，須替換為真實資料。ICCID 必須已歸屬本渠道；收費業務還需設定售價及足夠預存餘額，手動 WFC 免費。金額均為 USD 字串。

## 套餐、地址和唯一碼

每個唯一碼對應一個「套餐＋城市＋州＋郵編＋詳細地址」組合。渠道頁面可先選套餐，再從該套餐的目錄記錄中選擇城市及地址，最後提交所選記錄的 `catalog_entry_id`；使用者不需要手動輸入唯一碼。同一地址搭配不同套餐，對應不同目錄記錄。

`GET /regional-catalog` 返回已設定的套餐與地址目錄，可按 `zip`、`state`、`area_code`、`product_code`、`orderable=true` 等條件篩選，使用 `page`、`per_page` 翻頁。

`orderable=true` 僅返回可下單記錄；`orderable=false` 或省略此參數時，返回符合其他條件的全部記錄。明細包含：

| 欄位 | 含義 |
| --- | --- |
| id / catalog_entry_id | 地區套餐目錄唯一編號 |
| revision | 目錄版本；提交 `catalog_revision` 時，平台才會校驗是否與所選版本一致 |
| product_code | 平台產品編號，僅用於產品分類、篩選 |
| plan_code / plan_id | 業務介面使用的套餐代碼、套餐 ID |
| plan_name | 套餐展示名稱 |
| service_address | 街道、城市、州和 ZIP |
| prices | 本渠道按業務的報價；null 表示未設定 |
| zip_region | 城市和參考區號、歷史開卡區號資訊，只讀 |
| orderable | 目前設定是否支援辦理；提交時仍須再次驗證 |

`GET /regional-catalog/{id}` 讀取完整記錄。開卡時傳 `catalog_entry_id` 可自動匹配套餐和地址，也可同時傳 `catalog_revision` 校驗版本。目錄版本過期，或該明細的套餐、地址與目錄衝突時，該明細記為 `failed`；其餘有效明細繼續同批辦理。無效的批次結構仍會拒絕整個請求。

`GET /zip-regions` 與 `GET /zip-regions/{zip}` 單獨查詢城市、州和區號資料。區號不影響套餐唯一碼，不保證號碼供應。

## 開卡

`POST /jobs/activations`

```json
{
  "txid": "channel-activation-001",
  "items": [
    {
      "esn": "89000000000000000001",
      "catalog_entry_id": "CATALOG_ENTRY_ID"
    }
  ]
}
```

傳入選中的目錄唯一碼，平台自動補齊套餐、街道、城市、州和 ZIP。這種方式不需要再傳 plan_code、defaults、customer 或 mode。需要拒絕選擇後已變更的目錄時，可另外傳 catalog_revision。批次開卡只需在 items 中增加明細。區號供參考，不能保證指定區號。

## 續費

`POST /jobs/renewals`

```json
{
  "txid": "channel-renewal-001",
  "change_type": "ONEXPIRY",
  "items": [
    {
      "mdn": "2025550100"
    }
  ]
}
```

正常續費每條明細需提供一個線路標識，並建議提供 `txid`。使用 `change_type` 選擇以下兩種方式：

| 方式 | change_type | 週期與扣款時間 |
| --- | --- | --- |
| 即日續費（預設） | IMMEDIATE | 從辦理當日重新開始一個套餐週期，並提供新的資源量；確認成功後立即扣款 |
| 到期續費 | ONEXPIRY | 保留目前週期，在原到期日追加一個週期；可提前提交，確認成功後立即扣款 |

**到期續費可以現在辦理，成功後到期日即獲延長。它不會等到到期日才發送請求或扣款。** 例如 9 月 29 日辦理、原到期日為 10 月 15 日：即日續費的典型新到期日約為 10 月 29 日；到期續費約為 11 月 15 日。實際到期日以返回結果為準；渠道仍按已設定的該筆報價結算。

上面的範例明確選擇到期續費；省略 change_type 使用 IMMEDIATE，即日續費。已有訂單保留提交時記錄的方式。即日續費範例：

```json
{
  "txid": "channel-renewal-immediate-001",
  "change_type": "IMMEDIATE",
  "items": [
    {
      "mdn": "2025550100"
    }
  ]
}
```

無需傳辦理日期，不支援 schedule_date、months 等排程或月數欄位。續三個月時，明確使用 ONEXPIRY 並分別提交三次：確認第一筆成功及到期資訊後再提交第二筆，再確認後提交第三筆。沒有返回到期日欄位時，不自行推算或併發補續。

預設 plan_change=false，續費原套餐。需換套餐續費時，傳 plan_change=true 和從目錄獲取的 plan_id；目標套餐必須開放且設定渠道價格。不要將獨立換套餐介面與換套餐續費混淆。

## 重新啟用

`POST /jobs/reactivations`

```json
{
  "txid": "channel-reactivation-001",
  "items": [
    {
      "mdn": "2025550100"
    }
  ]
}
```

恢復原線路，按原套餐續費價收費；不能傳新套餐。缺少 mdn 時可只傳已登記的 ICCID 或 enrollment_id。是否可恢復取決於線路實際狀態，介面受理不等於成功。

地址可省略，指線路的街道、城市、州和 ZIP。這套補齊規則也適用於手動 WFC：

| 優先順序 | 地址來源 | 具體含義 |
| --- | --- | --- |
| 1 | 本次請求明確提供的欄位 | items[].customer 覆蓋 defaults；ZIP 再以 items[].zip 為優先 |
| 2 | 本地號卡已登記的服務地址 | 使用該卡成功開卡時保存或後續同步取得的完整有效地址 |
| 3 | 同卡最近成功開卡的地址快照 | 本地號卡地址缺失或無效時，查找同一 ICCID 最近一次成功開卡的地址；不使用失敗訂單地址 |
| 4 | 線路目前登記的 WFC／服務地址 | 本地兩處均無有效地址時，將未填欄位交由線路目前記錄補齊 |

地區套餐目錄是開卡時可選的套餐與地址資料；不會僅按城市或 ZIP 從目錄任選一條地址。使用目錄成功開卡後，當時的地址會保存到該卡及訂單；後續修改目錄不改寫原開卡地址快照。建單時確定的地址隨本次請求保存，排隊及手動重試沿用原參數。

只傳 ZIP 不會強制要求重傳完整地址；明確覆蓋的 ZIP 應與街道、城市及州一致。是否符合 WFC 資格以實際結果為準。這些是線路服務地址，不是渠道公司或帳單收件地址。可選姓名、電子郵件及 address_two 的空字串按未填處理；必填的開卡地址仍須完整有效。

檢查 items[].result.wifi_calling。WFC 失敗不會撤銷已成功的重新啟用，主業務仍按成功結算。

## 手動開啟 Wi-Fi Calling

`POST /jobs/wifi-calling`

```json
{"txid":"channel-wfc-001","items":[{"mdn":"2025550100"}]}
```

使用已登記的 mdn、esn 或 enrollment_id；feature_action 預設 Active，目前只支援開啟。地址補齊方式與重新啟用相同。不單獨收費、不扣渠道餘額，也不產生扣款流水；仍建立逐卡業務記錄並提供任務結果及簽名回呼。

補開是否成功以本次 WFC 任務結果為準；原重新啟用任務中的 wifi_calling 結果保留當時記錄，不會改寫歷史結果。

## 查詢結果

- `GET /jobs/{id}`：按返回的任務 ID 或 txid 查詢。
- `GET /jobs?txid=...`：按批次交易號或逐卡交易號查詢。
- `GET /jobs?status=running`：返回本渠道的任務列表；預設每頁 100 條，page、per_page 可分頁，依據 pagination.has_more 繼續讀取。
- `GET /jobs/{id}/items?status=failed`：查詢任務的失敗明細；返回該批全部匹配明細，不分頁。

使用逐卡 txid 查詢時，只返回該卡明細，match=item_txid；批次 txid 或任務 ID 返回整批。一次查詢任務即可讀取 items，不必逐卡發送查詢。

指定任務 ID 或 txid 查詢處理中任務時，會補取一次原批次結果；已確認完成的任務直接返回，不額外查詢。排隊中尚未發送的任務不會因查單而開始辦理。任務列表顯示已同步快照；補查失敗或已有查詢正在進行時，可能仍返回待確認狀態，請留意 last_error 並稍後查詢。

JSON 成功回應統一為 data 和 meta。業務結果 data 內有 job 和 items；job.id 是此介面可查詢的任務編號，items[].id 是重試使用的明細編號。

| 層級 | 狀態 | 含義 |
| --- | --- | --- |
| job | queued | 排隊；paused=true 時需儲值恢復 |
| job | running | 處理中或結果待確認 |
| job | succeeded | 全部成功 |
| job | failed | 全部失敗 |
| job | partial | 全部處理結束，部分成功、部分失敗 |
| item | pending / processing | 未完成，不扣款 |
| item | succeeded | 成功，按該明細報價扣款 |
| item | failed | 失敗，不扣款 |

job.billing.amount 是已建立的逐卡報價合計；無法報價的本地失敗明細金額為 0，表示沒有有效報價，不代表免費業務。手動 WFC 為明確免費的例外。charged_amount 是已扣金額。items[].billing.price 是該條報價。result 保留已核實的業務結果，包括返回的號碼、Enrollment ID、到期日等；只展示實際返回的欄位，不保證每個介面都有到期日。`finished_at` 是處理完成時間，不是服務到期日。

結果若明確返回格式無效的手機號碼，或續費、重新啟用、WFC 返回與原號碼不符的號碼，該明細保持待核實且不扣款，並補查原任務。可選號碼欄位未返回不等同於號碼衝突；不會因此重新提交辦理。

單條業務的明細 txid 與批次 txid 相同；多條業務的明細 txid 為「批次 txid_卡號後八位」，返回的逐卡交易號最長為 73 位。若同批卡號後八位重複，請拆分提交。

## 業務通用規則

- 一次請求對應一個任務，每批至少一條 items，不設固定條數上限，按每張卡記錄結果和計費。
- 建議每筆請求提供 txid，渠道內唯一，1–64 位字母、數字、點、底線、冒號或連字符。相同 txid 再提交返回 409，使用原 txid 查詢結果。
- 預設非同步處理，mode 可省略或傳 async。未完成返回 HTTP 202；若全部明細在本地校驗時已失敗，也會直接返回 HTTP 200。mode=sync 嘗試立即辦理，整批已有最終結果返回 200，否則返回 202。200 不代表業務成功，202 也只表示已受理；請讀取逐卡最終狀態。
- 每條 items 使用 esn（ICCID）、mdn（10 位美國手機號碼）或 enrollment_id。開卡支援 esn、mdn；續費、重新啟用及手動 WFC 支援三種標識。多個標識同傳必須能在本渠道登記記錄中對應同一張卡。未登記手機號碼的舊卡可先呼叫 /cards/{iccid}/sync。
- 辦理使用平台已登記的號卡、套餐、地址及渠道報價，不在提交前逐卡查詢線路或再次查詢套餐目錄。查詢與資料同步介面可按需單獨呼叫，不是辦理前置步驟。
- 逐卡本地地址、套餐或報價校驗失敗，只記錄該卡錯誤，其餘明細繼續同批提交。身份、歸屬、重複卡號、共同參數或可辦理明細總額不足等整體錯誤仍拒絕請求。
- 整批按提交時的渠道售價檢查餘額，不凍結。發送前再次檢查餘額；不足時暫停，儲值後 resume。成功明細才扣款，失敗不扣，部分成功只扣成功部分。
- 每張卡的未完成業務互斥；同一渠道的前序扣費任務結果未明時，後續扣費任務排隊，避免在不凍結資金的前提下超額辦理。免費 WFC 與其他卡的收費業務互不阻塞；同一卡片仍須等待前序業務完成。
- 套餐的開卡、續費、重新啟用按渠道價格單結算。已採用統一價格單的渠道不重複扣卡板或 eSIM 銷售費用。
- 區號只是參考，不能傳 area_code 指定號碼。具體號碼和區號以實際辦理結果為準。

## 異常恢復

辦理中的內部重試不需要渠道再次提交；等待同一任務的最終結果即可。平台不因內部重試次數增加而另建訂單或重複扣款。

服務重啟時，確認尚未發送的任務自動恢復排隊；可能已送出或缺乏發送階段記錄的任務只查詢原任務。渠道無需另建 txid。

**明確失敗先保留失敗結果並進入異常待解決，不自動重試。** 渠道透過查單或已設定的回呼取得 status=failed、錯誤原因及 retryable；失敗不扣款。retryable=true 只代表可以主動重試，不代表必須重試。地址、套餐、報價等錯誤同樣保留在異常待解決；其他有效明細照常處理。待解決是營運處理標記，API 業務狀態仍是 failed，不會改成 pending。

未建立任務就被拒絕的請求，直接返回 HTTP 錯誤；已認證渠道的業務參數等拒絕也會記錄到異常。沒有任務就沒有逐卡回呼，可依 meta.request_id 與錯誤碼排查。修正已失敗任務的參數時，使用新 txid 建立新請求；需要保留原參數再辦時，才主動呼叫 retry。

以下三個操作可省略請求體，或傳空 JSON 物件 `{}`，不需要重傳原業務參數。有請求體時須使用 `Content-Type: application/json`；非空物件或格式錯誤返回 400，超過 200,000 字節返回 413，非 JSON 類型返回 415。

`POST /jobs/{id}/recheck`：只查詢原任務，不重新提交辦理請求。首次確認成功時正常記帳，重複查詢不重複扣款。已受理的任務優先等待最終回呼；五分鐘仍無最終結果時補查原批次。結果不明、回呼不完整或衝突時可提前補查。累計嘗試達 20 次後（含首次發送），attention_required=true，仍每五分鐘補查，不會自動重辦。

`POST /jobs/{id}/resume`：儲值後恢復餘額不足而暫停的任務，繼續使用原報價。若餘額仍不足，返回 HTTP 402，任務保持暫停。

`POST /jobs/{id}/items/{itemId}/retry`：僅允許 result.retryable=true 且有原任務及明細編號的失敗明細，不要求 attempt_count 必返。核實問題後，即使同批其他明細仍在處理，也可主動提出重試；重試排隊等待前序處理完成，沿用原參數與報價。成功、處理中和結果不明的明細不允許重試。重試仍校驗本地歸屬、線路狀態、餘額及原套餐；修改業務參數需要新建任務。此介面的 HTTP 200 只表示已安排重試，須繼續查詢任務或等待回呼確認結果。

HTTP 409 重複 txid：查原單。提交請求網路超時：查原 txid，不換編號重複辦理。HTTP 402：餘額不足。HTTP 401：檢查渠道帳戶、API Key 及是否已重置金鑰。HTTP 429：遵循 Retry-After 等待。錯誤的 error.details.business_code 是具體業務原因；排障提供 meta.request_id、txid 和任務 ID，不提供密鑰。

## 回呼

後台登記渠道回呼 HTTPS 地址；也可在辦理時傳 webhook_url 覆蓋本任務地址。回呼在結果核實與記帳後發出，不因重複通知再次扣款。未設定回呼時通過任務查詢獲取結果。

通知寫入後即觸發投遞，已到投遞時間的通知會連續發送，不設每秒或每輪固定筆數限制。失敗通知才按下列間隔等待重送；實際送達時間取決於接收端與網路。

已驗簽、能關聯本次辦理的逐卡最終結果直接更新訂單，不要求再查一次才能確認。未確認的結果只有批次匯總、缺少關聯資訊、內容衝突或無法區分手動重試的新舊結果時，才補查原任務；缺少回呼時亦保留補查。已確認終態後再收到相反結果，保留原結算並記錄異常待核實，不自動改成成功、失敗或再次扣款。事件建立時間不能代替未返回的處理完成時間或服務到期日。

事件類型：activation.item.succeeded、activation.item.failed、activation.job.completed；續費將前綴替換為 renewal，重新啟用替換為 reactivation，手動開啟 WFC 替換為 wifi_calling。

請求頭：

- X-RM-Event：與 JSON type 一致。
- X-RM-Delivery-Id：本次投遞編號，重投時改變；事件去重使用 JSON id。
- X-RM-Signature：sha256=<十六進制簽名>。

使用渠道 Webhook Secret 對未經 JSON 解析或重新序列化的原始請求體計算 HMAC-SHA256。簽名不拼接時間戳。驗簽通過後按 id 持久化去重並返回 HTTP 2xx。重複的有效事件也返回 2xx。首次投遞失敗後，平台最多自動重試 5 次，間隔為 30、60、120、240、480 秒，指數退避上限為 15 分鐘；包括首次在內最多投遞 6 次。管理員可在後台重新投遞原事件。重投只補發通知，不重新辦理業務或扣款。事件可能重複或亂序，最終狀態以任務查詢為準。

回呼不發送 X-Partner-Id 或 X-API-Key，created_at 表示事件建立時間；接收端使用上述獨立簽名驗證。

```json
{
  "id": "evt_example",
  "created_at": "2026-10-02T12:00:00Z",
  "type": "activation.item.succeeded",
  "data": {
    "job_id": "ord_example",
    "item_id": "item_example",
    "job_txid": "channel-activation-001",
    "txid": "channel-activation-001",
    "esn": "89000000000000000001",
    "status": "succeeded",
    "mdn": "2025550100"
  }
}
```

參見資料包 webhook-verify.mjs。Node.js 22+ 可運行 node --test webhook-verify.test.mjs 驗證示例。

## 查詢、庫存和帳單介面

| 方法 | 路徑 | 用途 |
| --- | --- | --- |
| GET | /status | 服務狀態，不需認證 |
| GET | /customers?esn=... | 查詢本渠道線路資料；esn、mdn、enrollment_id 只能選一個查詢鍵 |
| GET | /mdns/{mdn} | 按手機號碼查詢線路 |
| GET | /mdns/{mdn}/usage | 查詢用量，預設 summary=true；明細用 from、to，最近 90 天內 |
| GET | /esns/{esn}/status | 查詢卡狀態 |
| POST | /addresses/validate | 校驗真實地址與 WFC 地址資格；不會開啟 Wi-Fi Calling |
| GET | /cards | 本渠道號碼庫存，分頁 |
| POST | /cards/{iccid}/sync | 同步已歸屬卡的線路、套餐和地址資料，不扣費 |
| GET | /cards/{iccid}/esim | 讀取已登記的 eSIM 安裝資料，不生成新安裝碼 |
| GET | /balance | 查詢可用餘額 |
| GET | /ledger | 儲值、消耗及餘額流水，分頁 |
| GET | /ledger/summary | 同篩選條件的流水匯總 |
| GET | /ledger/export | 導出同條件 CSV |
| GET | /plans | 按 ZIP 查目前可售套餐及渠道報價 |
| GET | /regional-catalog | 套餐、地址、唯一碼和區號目錄 |
| GET | /regional-catalog/{id} | 讀取一條地區套餐目錄 |
| GET | /zip-regions | 郵編、城市、州與參考區號 |
| GET | /zip-regions/{zip} | 讀取一條地區記錄 |

線路、手機號碼、用量查詢及帶 enrollment_id 的地址校驗，若識別資料對應本渠道多張卡，返回 HTTP 409，`error.details.business_code=AMBIGUOUS_IDENTIFIER`；請先核實歸屬記錄。

`POST /cards/{iccid}/sync` 須使用 `Content-Type: application/json` 並傳空物件 `{}`，只讀取並同步已登記線路資料；不能用它提交新號碼或修改套餐。非空請求物件返回 HTTP 400。

帳單 `from`、`to` 使用 `America/New_York`，與華盛頓特區對帳使用相同當地日期，包含起止日期當天並自動處理夏令時間。依實際入帳或扣款時間統計；時間欄位仍可用 UTC ISO 格式表示同一時刻。`summary` 涵蓋全部篩選結果，不受分頁影響，金額均為 USD 字串。

請求上限為每渠道每分鐘 120 次，已認證任務 GET 查詢不計入該額度。JSON 請求體不超過 200,000 字節。服務擁堵時任務會排隊。

目前開放開卡、續費、重新啟用、免費手動開啟 Wi-Fi Calling 及上述查詢、帳戶能力。獨立停機、加購、獨立換套餐、手動關閉 WFC 暫未開放。正式環境成功的收費業務會實際消耗渠道餘額；介面不包含自動儲值或線上收款。

## 進階選項與相容接入

下列選項不是日常辦理的必要步驟。

- 自訂地址：不用目錄唯一碼時，改傳介面 plan_code 和完整地址，見下方範例。`GET /plans?zip=36104` 可取得套餐代碼、ID 及渠道價格。plan_code 不是 Plan 65 等展示名稱，也不是 product_code。cost 為相容欄位，目前為 null；結算請讀取 price、prices 或訂單 billing。
- defaults 設定批次地址；items[].customer 覆蓋客戶或地址欄位，items[].zip 覆蓋 ZIP。姓名及 email 可選。carrier 僅支援 TMB；enrollment_type 預設 HANDOVER（卡已在使用者手中），SHIPMENT 表示待寄送。開卡不接受 address_two，套房或樓層資訊放在 address。/addresses/validate 可用於自訂地址資格校驗，使用目錄時不是必經步驟。
- mode=sync 嘗試立即辦理，只有處理完成才返回 200，排隊或結果待確認仍返回 202，不能保證同步完成。
- 請求體未傳 txid 時，可用 Idempotency-Key 或 txid 請求標頭；均未提供則生成。建議在 JSON 傳 txid，遇到提交結果不明時才能按原交易號查詢。
- 已使用 token 的渠道可保留 `POST /auth`，傳 `partner_id`、`api_key`，再使用 `Authorization: Bearer <token>`，有效期 30 分鐘。相容認證介面每 IP 每分鐘最多 20 次。固定 Key 新接入無需呼叫；兩者使用相同的新版請求、結果和回呼格式。
- 舊版 `Authorization: Bearer <API Key>` 保留原請求、結果及回呼格式。從舊版遷移時須同步修改這三種格式，不能只改標頭。固定 Key 新接入須同時傳帳戶和 Key，不傳 `Authorization`。

自訂地址開卡範例：

```json
{
  "txid": "channel-activation-002",
  "defaults": {
    "enrollment_type": "HANDOVER",
    "address": "1 Example Street",
    "city": "Montgomery",
    "state": "AL",
    "zip": "36104"
  },
  "items": [
    {
      "esn": "89000000000000000001",
      "plan_code": "PLAN_CODE_FROM_CATALOG"
    },
    {
      "esn": "89000000000000000002",
      "plan_code": "PLAN_CODE_FROM_CATALOG"
    }
  ]
}
```

`cost` 是保留的相容欄位，目前為 null，不代表零成本或售價。`GET /plans` 的 `price` 是單週期續費價，未設定時為 null；其他業務報價讀取 `prices`，已建立訂單讀取 `billing`。缺省的 attempt_count 不阻止普通終態確認；只有明確較舊的次數才作為舊結果證據。對明確尚未受理、且可安全重試的暫時性服務拒絕，平台可在等待後使用原交易識別恢復發送。這不是對已失敗業務的自動重辦，渠道應繼續查詢原 `txid`。網路斷線、無法解析的成功回應或其他不明結果，平台只查原任務，不再次發送業務。
