Recur
Recur
Recur 文件中心
API 參考Subscriptions APIPortal Sessions API
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"
}

回應欄位說明

欄位類型說明
idstringPortal Session ID
objectstring固定為 portal.session
urlstring導向客戶的 Portal URL
returnUrlstring離開 Portal 後的返回 URL
customerIdstring客戶 ID
statusstringSession 狀態(active、expired、revoked)
expiresAtstringSession 過期時間(ISO 8601)
accessedAtstring | null最後存取時間
createdAtstring建立時間

程式碼範例

// 推薦:使用 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

狀態說明

狀態說明
activeSession 有效,可以存取 Portal
expiredSession 已過期
revokedSession 已被撤銷

錯誤處理

HTTP 狀態錯誤代碼說明
400invalid_param請求參數無效
400missing_return_url未提供 returnUrl 且無預設值
401invalid_api_key需要 Secret Key 認證
404customer_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 - 查詢訂閱狀態

Subscriptions API

訂閱狀態查詢與管理 API

快速開始

5 分鐘內完成 Recur 整合

On this page

Portal Sessions API建立 Portal Session端點認證請求參數回應格式回應欄位說明程式碼範例Session 生命週期有效期限狀態說明錯誤處理錯誤回應範例使用案例1. 帳戶設定頁面的「管理訂閱」按鈕2. 使用 Recur SDK Web Component安全性考量下一步