npm package: @recur-tw/cli
Description: CLI for Recur - Taiwan's subscription payment platform
Author: Recur
Latest version: 0.2.0

# @recur-tw/cli

Recur 訂閱金流平台的命令列工具。管理產品、客戶、訂閱、訂單等資源，同時支援人類使用與 AI Agent 整合。

## 安裝

```bash
npm install -g @recur-tw/cli
```

或使用 npx 直接執行：

```bash
npx @recur-tw/cli products list
```

## 快速開始

### 1. 設定 API Key

前往 [Recur Dashboard](https://app.recur.tw) 取得 Secret Key（`sk_test_*` 或 `sk_live_*`），然後執行：

```bash
recur login
```

API Key 會安全存儲在 `~/.recur/credentials.json`（檔案權限 `0600`）。

也可以透過環境變數設定：

```bash
export RECUR_SECRET_KEY=sk_test_xxx
```

### 2. 開始使用

```bash
# 列出所有產品
recur products list

# 查看訂閱狀態
recur subscriptions list --status active

# 查看客戶資料
recur customers list --email user@example.com
```

## 指令一覽

```
recur <資源> <動作> [選項]
```

### 全域選項

| 選項 | 說明 |
|------|------|
| `--key <sk_*>` | 指定 API Secret Key |
| `--profile <name>` | 使用指定的 profile |
| `--base-url <url>` | API 位址覆寫 |
| `--output <format>` | 輸出格式：`json`、`table`（預設）、`csv`、`ndjson` |
| `--fields <fields>` | 逗號分隔的欄位篩選 |
| `--dry-run` | 僅本地驗證，不發送 API 請求 |
| `--json <payload>` | 直接傳入 JSON 作為 API request body |

### 驗證管理

```bash
recur login                       # 互動式設定 API Key（輸入時遮蔽顯示）
recur whoami                      # 顯示目前 profile 與 masked key
recur profiles                    # 列出所有 profile
recur use <profile>               # 切換 profile
recur logout [profile]            # 移除 profile
```

#### 多環境管理

```bash
# 儲存 sandbox profile
recur --key sk_test_xxx login --name sandbox

# 儲存 production profile
recur --key sk_live_xxx login --name production

# 切換環境
recur use production
recur products list  # 使用 production key

# 或單次指定
recur --profile sandbox products list
```

### 產品 (Products)

```bash
recur products list                                    # 列出所有產品
recur products list --status archived                  # 列出已封存產品
recur products get <id>                                # 以 ID 查詢
recur products get <slug>                              # 以 slug 查詢
recur products create --name "方案" --price 299 --interval monthly --type SUBSCRIPTION
recur products create --json '{"name":"方案","price":299,"interval":"monthly"}'
recur products update <id> --name "新名稱"
recur products archive <id>
```

### 客戶 (Customers)

```bash
recur customers list                                   # 列出所有客戶
recur customers list --email user@example.com          # 以 email 篩選
recur customers list --starting-after <id> --limit 50  # 游標分頁
recur customers list --page-all                        # 自動分頁（輸出 NDJSON）
recur customers get <id>                               # 查詢客戶詳情
recur customers update <id> --name "新名稱"
```

### 訂閱 (Subscriptions)

```bash
recur subscriptions list                               # 列出所有訂閱
recur subscriptions list --status active               # 篩選狀態
recur subscriptions list --customer-id <id>            # 以客戶篩選
recur subscriptions list --page-all                    # 自動分頁
recur subscriptions get <id>                           # 查詢訂閱詳情
recur subscriptions cancel <id>                        # 期末取消
recur subscriptions cancel <id> --immediately          # 立即取消
```

### 訂單 (Orders)

```bash
recur orders list                                      # 列出所有訂單
recur orders list --status paid                        # 篩選狀態
recur orders list --customer-id <id>                   # 以客戶篩選
recur orders get <id>                                  # 查詢訂單詳情
```

### 帳單 (Invoices)

```bash
recur invoices list                                    # 列出所有帳單
recur invoices list --subscription-id <id>             # 以訂閱篩選
recur invoices list --customer-id <id>                 # 以客戶篩選
recur invoices list --status paid                      # 篩選狀態
recur invoices get <id>                                # 查詢帳單詳情
```

### Webhook

```bash
recur webhooks list                                    # 列出所有 webhook
recur webhooks create --url https://example.com/hook   # 建立 webhook
recur webhooks create --json '{"url":"...","events":["checkout.completed"]}'
recur webhooks test <id>                               # 發送測試事件
recur webhooks test <id> --event subscription.canceled # 指定事件類型
recur webhooks delete <id>                             # 刪除 webhook
recur webhooks listen http://localhost:3000/api/webhooks  # 即時轉發到本地
```

### 本地 Webhook 開發（`webhooks listen`）

`recur webhooks listen` 讓你在本地開發時即時接收 webhook 事件，不需要公開 URL。

```bash
# 基本用法：轉發所有事件到本地伺服器
recur webhooks listen http://localhost:3000/api/webhooks

# 只轉發特定事件類型
recur webhooks listen http://localhost:3000/api/webhooks --events checkout.completed,order.paid
```

#### 運作原理

1. CLI 透過 SSE 連線到 Recur 的 relay 服務
2. 收到一個專屬的 signing secret（`whsec_*`）
3. 當 Recur 平台觸發 webhook 事件時，relay 即時推送到 CLI
4. CLI 將事件 POST 到你指定的本地 URL，附帶以下 headers：
   - `X-Recur-Signature` — HMAC-SHA256 簽名（用 signing secret 驗證）
   - `X-Recur-Event-Type` — 事件類型
   - `X-Recur-Event-Id` — 事件 ID
   - `X-Recur-Timestamp` — 事件時間戳

#### 輸出範例

```
  Ready! Listening for webhook events...

  Signing secret: whsec_abc123def456...
  Forwarding to:  http://localhost:3000/api/webhooks
  Environment:    sandbox

12:03:45  ->  checkout.completed [evt_abc123]  200 (23ms)
12:03:46  ->  subscription.activated [evt_def456]  200 (18ms)
12:05:12  ->  invoice.paid [evt_ghi789]  500 Internal Server Error (45ms)
```

#### 選項

| 選項 | 說明 |
|------|------|
| `--events <types>` | 逗號分隔的事件類型篩選（CLI 端過濾） |
| `--relay-url <url>` | 覆寫 relay 服務 URL（開發用） |

#### 注意事項

- 需要 Secret Key（`sk_test_*` 或 `sk_live_*`）
- 斷線時自動重連（最多 10 次連續失敗後退出）
- `Ctrl+C` 優雅關閉
- Signing secret 每次連線都會重新產生

### Checkout Sessions

```bash
recur checkouts create --product-id <id> --customer-email user@example.com
recur checkouts create --json '{"productId":"<id>","successUrl":"https://..."}'
recur checkouts get <id>                               # 查詢 session 狀態
```

## 輸出格式

### Table（預設，適合人類閱讀）

```bash
$ recur products list --fields name,price,type

name             price  type
───────────────  ─────  ────────────
大師方案 - 月繳  799    SUBSCRIPTION
超級方案 - 月繳  499    SUBSCRIPTION

2 results
```

### JSON（適合程式解析與 AI Agent）

```bash
$ recur products list --output json

[
  { "id": "k672i1kd6zgrw5b6w39xwpx3", "name": "大師方案", "price": 799 },
  ...
]
```

搭配 `jq` 使用：

```bash
recur products list --output json | jq '.[].name'
recur subscriptions list --output json | jq '[.[] | select(.status == "ACTIVE")]'
```

### NDJSON（適合串流處理）

```bash
# --page-all 自動輸出 NDJSON（一行一筆）
recur customers list --page-all --fields id,email
```

### CSV（適合匯出與試算表）

```bash
$ recur customers list --output csv --fields email,name > customers.csv
```

### 欄位篩選

用 `--fields` 減少輸出量，適合腳本和 AI Agent 控制 context window：

```bash
recur products list --fields id,name,price
recur customers list --fields email,name --output json
```

## MCP Server（AI Agent 整合）

`recur mcp` 啟動一個本地 MCP（Model Context Protocol）server，讓 AI 助理直接操作 Recur API。

### Claude Desktop

在 `claude_desktop_config.json` 中加入：

```json
{
  "mcpServers": {
    "recur": {
      "command": "npx",
      "args": ["@recur-tw/cli", "mcp"],
      "env": { "RECUR_SECRET_KEY": "sk_test_xxx" }
    }
  }
}
```

### Claude Code

在專案根目錄的 `.mcp.json` 中加入：

```json
{
  "mcpServers": {
    "recur": {
      "command": "npx",
      "args": ["@recur-tw/cli", "mcp"],
      "env": { "RECUR_SECRET_KEY": "sk_test_xxx" }
    }
  }
}
```

### 提供的 Tools（22 個）

| 類別 | Tools | 類型 |
|------|-------|------|
| Schema | `get_schema` | 唯讀 |
| Products | `list_products`, `get_product`, `create_product`, `update_product`, `archive_product` | 讀寫 |
| Customers | `list_customers`, `get_customer`, `update_customer` | 讀寫 |
| Subscriptions | `list_subscriptions`, `get_subscription`, `cancel_subscription` | 讀寫 |
| Orders | `list_orders`, `get_order` | 唯讀 |
| Invoices | `list_invoices`, `get_invoice` | 唯讀 |
| Webhooks | `list_webhooks`, `create_webhook`, `test_webhook`, `delete_webhook` | 讀寫 |
| Checkouts | `create_checkout`, `get_checkout` | 寫入 |

所有 tools 帶有 MCP Tool Annotations（`readOnlyHint`、`destructiveHint`），讓 agent 能判斷操作風險。

## Agent-Optimized 設計

此 CLI 遵循 [Agent-Optimized CLI](https://justin.poehnelt.com/posts/rewrite-your-cli-for-ai-agents/) 設計原則：

### Schema 自省

Agent 可以透過 `recur schema` 動態查詢 API 規格，不需要讀文件：

```bash
# 列出所有可用資源
recur schema

# 查看特定資源的所有動作
recur schema products

# 查看特定動作的完整參數定義
recur schema products.create
```

輸出包含 `method`、`path`、`params`、`bodySchema`、`responseFields`、`supportsDryRun` 等結構化資訊。

### Raw JSON Payload

`--json` 讓 Agent 直接傳入 API body，不需要逐一對應 flag：

```bash
recur products create --json '{"name":"Pro Plan","price":599,"interval":"monthly","type":"SUBSCRIPTION"}'
```

### Dry Run

所有寫入操作支援 `--dry-run`，讓 Agent 先驗證再執行：

```bash
recur products create --dry-run --json '{"name":"Test","price":299}'
# [dry-run] Would create product:
# { "name": "Test", "price": 299 }
```

### Input 驗證（防止 AI 幻覺）

CLI 內建多層輸入驗證，防止 Agent 送出錯誤或惡意輸入：

- 路徑穿越偵測（`../`、`/`、`\`）
- Query injection 阻擋（`?`、`#`、`%`）
- 控制字元與不可見 Unicode 過濾
- API 回應 sanitization（ANSI escape、零寬字元）

## 驗證方式

API Key 的解析優先順序：

1. `--key` 參數（最高優先）
2. `RECUR_SECRET_KEY` 環境變數
3. `~/.recur/credentials.json` 中的 active profile

### API Key 類型

| 類型 | 格式 | 用途 |
|------|------|------|
| Secret Key (Sandbox) | `sk_test_*` | 測試環境，完整權限 |
| Secret Key (Production) | `sk_live_*` | 正式環境，完整權限 |

CLI 僅接受 Secret Key。Publishable Key（`pk_*`）僅供前端 SDK 使用。

### 安全性

- Login 輸入 key 時以 `*` 遮蔽顯示
- API Key 以 `0600` 權限存儲在 `~/.recur/credentials.json`
- CLI 不直接連接資料庫，所有操作經由 API server 驗證
- 每個 API Key 綁定一個 Organization，資料完全隔離
- Key 以 SHA-256 hash 存儲在 server 端
- API 回應自動 sanitize 以防止 prompt injection

## 程式化使用

`@recur-tw/cli` 也提供 library API，可在 Node.js 中直接使用：

```typescript
import { RecurClient, resolveSecretKey, resolveBaseUrl } from '@recur-tw/cli'

const client = new RecurClient({
  baseUrl: resolveBaseUrl({}),
  secretKey: resolveSecretKey({}),
})

const products = await client.get('/v1/products')
```

## 系統需求

- Node.js >= 22
- 作業系統：macOS、Linux、Windows

## 授權

MIT

## 相關連結

- [Recur 官網](https://recur.tw)
- [API 文件](https://recur.tw/docs/api)
- [SDK (recur-tw)](https://www.npmjs.com/package/recur-tw)
- [Dashboard](https://app.recur.tw)