API 參考
Portal Sessions API
Customer Portal Session 建立與管理 API
Portal Sessions API
Customer Portal 讓您的客戶可以自助管理訂閱,包括查看訂閱詳情、更新付款方式、取消訂閱等。
建立 Portal Session
建立一個短期有效的 Portal Session,用於將客戶導向 Customer Portal。
端點
POST /api/v1/portal/sessions認證
此端點需要 Secret Key 認證,僅限後端使用。Portal Session 包含敏感的客戶資訊,不應在前端建立。
# Authorization Header(推薦)
Authorization: Bearer sk_test_xxx
# 或專用 Header
X-Recur-Secret-Key: sk_test_xxx請求參數
| 參數 | 必填 | 類型 | 說明 |
|---|---|---|---|
customerId | ✅ | string | 客戶 ID |
returnUrl | ❌ | string | 客戶離開 Portal 後的返回 URL |
configurationId | ❌ | string | 指定 Portal 設定 ID |
locale | ❌ | string | 語言偏好(zh-TW 或 en) |
如果未提供 returnUrl,將使用 Portal 設定中的預設返回 URL。若都未設定,會返回錯誤。
回應格式
{
"id": "portal_session_xxxxx",
"object": "portal.session",
"url": "https://portal.recur.tw/s/ps_xxxxx",
"returnUrl": "https://your-site.com/account",
"customerId": "cus_xxxxx",
"status": "active",
"expiresAt": "2025-01-15T12:00:00.000Z",
"accessedAt": null,
"createdAt": "2025-01-15T11:00:00.000Z"
}回應欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
id | string | Portal Session ID |
object | string | 固定為 portal.session |
url | string | 導向客戶的 Portal URL |
returnUrl | string | 離開 Portal 後的返回 URL |
customerId | string | 客戶 ID |
status | string | Session 狀態(active、expired、revoked) |
expiresAt | string | Session 過期時間(ISO 8601) |
accessedAt | string | null | 最後存取時間 |
createdAt | string | 建立時間 |
程式碼範例
// 推薦:使用 Recur Server SDK
import Recur from 'recur-tw/server';
const recur = new Recur({
secretKey: process.env.RECUR_SECRET_KEY!,
});
// 建立 Portal Session
const session = await recur.portal.sessions.create({
customer: 'cus_xxxxx',
returnUrl: 'https://your-site.com/account',
});
// 導向客戶
redirect(session.url);// app/api/portal/create/route.ts
import { NextRequest, NextResponse } from 'next/server';
export async function POST(request: NextRequest) {
const { customerId } = await request.json();
const response = await fetch('https://api.recur.tw/v1/portal/sessions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.RECUR_SECRET_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
customerId,
returnUrl: `${process.env.NEXT_PUBLIC_URL}/account`,
}),
});
const data = await response.json();
if (!response.ok) {
return NextResponse.json({ error: data.error }, { status: response.status });
}
return NextResponse.json({ url: data.url });
}import requests
import os
def create_portal_session(customer_id: str) -> dict:
response = requests.post(
'https://api.recur.tw/v1/portal/sessions',
headers={
'Authorization': f'Bearer {os.environ["RECUR_SECRET_KEY"]}',
'Content-Type': 'application/json',
},
json={
'customerId': customer_id,
'returnUrl': f'{os.environ["APP_URL"]}/account',
}
)
response.raise_for_status()
return response.json()
# 使用
session = create_portal_session('cus_xxxxx')
print(f'Portal URL: {session["url"]}')curl -X POST "https://api.recur.tw/v1/portal/sessions" \
-H "Authorization: Bearer sk_test_xxx" \
-H "Content-Type: application/json" \
-d '{
"customerId": "cus_xxxxx",
"returnUrl": "https://your-site.com/account"
}'Session 生命週期
有效期限
- Portal Session 有效期為 1 小時
- 過期後 Session 狀態變為
expired - 每個客戶最多同時擁有 5 個 有效 Session
狀態說明
| 狀態 | 說明 |
|---|---|
active | Session 有效,可以存取 Portal |
expired | Session 已過期 |
revoked | Session 已被撤銷 |
錯誤處理
| HTTP 狀態 | 錯誤代碼 | 說明 |
|---|---|---|
| 400 | invalid_param | 請求參數無效 |
| 400 | missing_return_url | 未提供 returnUrl 且無預設值 |
| 401 | invalid_api_key | 需要 Secret Key 認證 |
| 404 | customer_not_found | 找不到指定的客戶 |
錯誤回應範例
{
"error": {
"type": "invalid_request_error",
"code": "customer_not_found",
"message": "Customer cus_xxxxx not found"
}
}使用案例
1. 帳戶設定頁面的「管理訂閱」按鈕
// app/account/page.tsx
'use client';
import { useState } from 'react';
export function ManageSubscriptionButton({ customerId }: { customerId: string }) {
const [loading, setLoading] = useState(false);
const handleClick = async () => {
setLoading(true);
try {
const response = await fetch('/api/portal/create', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ customerId }),
});
const { url, error } = await response.json();
if (error) {
alert('發生錯誤:' + error.message);
return;
}
window.location.href = url;
} finally {
setLoading(false);
}
};
return (
<button onClick={handleClick} disabled={loading}>
{loading ? '載入中...' : '管理訂閱'}
</button>
);
}2. 使用 Recur SDK Web Component
<!-- 方式一:直接提供 Portal URL(server-rendered) -->
<recur-portal portal-url="https://portal.recur.tw/s/ps_xxxxx">
管理訂閱
</recur-portal>
<!-- 方式二:透過 API 動態建立 Session -->
<recur-portal
api-endpoint="/api/portal/create"
customer-id="cus_xxxxx">
管理訂閱
</recur-portal>安全性考量
重要安全提醒
- Portal Session URL 包含敏感存取權杖,請勿記錄或暴露
- 務必驗證用戶身份後再建立對應客戶的 Portal Session
- 使用 HTTPS 確保傳輸安全
下一步
- Customer Portal 整合指南 - 完整整合教學
- Webhook 事件 - 監聽訂閱變更事件
- Subscriptions API - 查詢訂閱狀態