Recur
Recur
Recur 文件中心
開發者指南
Customer Portal後端整合前端整合
開發者指南Customer Portal

前端整合

使用 Recur SDK Web Component 整合 Customer Portal 按鈕

前端整合

Recur SDK 提供 <recur-portal> Web Component,讓您可以快速在前端加入 Customer Portal 按鈕。

安裝 SDK

npm install recur-tw
// 在應用程式入口點引入
import 'recur-tw';
<script src="https://cdn.recur.tw/sdk/recur.umd.js"></script>

<recur-portal> 組件

使用方式一:直接提供 Portal URL

適合 Server-Side Rendering (SSR) 的應用,在後端取得 Portal URL 後直接傳入:

<recur-portal portal-url="https://portal.recur.tw/s/ps_xxxxx">
  管理訂閱
</recur-portal>
// Next.js Server Component 範例
import Recur from 'recur-tw/server';

const recur = new Recur({ secretKey: process.env.RECUR_SECRET_KEY! });

export default async function AccountPage() {
  const session = await recur.portal.sessions.create({
    customer: 'cus_xxxxx',
    returnUrl: 'https://your-site.com/account',
  });

  return (
    <recur-portal portal-url={session.url}>
      管理訂閱
    </recur-portal>
  );
}

使用方式二:透過 API 動態建立

適合 Client-Side Rendering (CSR) 的應用,點擊時呼叫您的後端 API 建立 Session:

<recur-portal
  api-endpoint="/api/portal/create"
  customer-id="cus_xxxxx">
  管理訂閱
</recur-portal>

使用 api-endpoint 模式時,組件會在點擊後 POST 到指定端點,期望回應 { url: "..." } 格式。

屬性說明

屬性必填說明
portal-url❌*直接提供 Portal URL
api-endpoint❌*後端 API 端點(用於動態建立 Session)
customer-id❌客戶 ID(傳送給 API)
return-url❌返回 URL(傳送給 API)
button-text❌按鈕文字(預設:插槽內容或「管理訂閱」)
button-style❌按鈕樣式:primary、outline、gradient、link
target❌設為 _blank 在新視窗開啟
disabled❌禁用按鈕

portal-url 和 api-endpoint 至少需要提供一個。

按鈕樣式

<!-- Primary(預設) -->
<recur-portal portal-url="..." button-style="primary">
  管理訂閱
</recur-portal>

<!-- Outline -->
<recur-portal portal-url="..." button-style="outline">
  管理訂閱
</recur-portal>

<!-- Gradient -->
<recur-portal portal-url="..." button-style="gradient">
  管理訂閱
</recur-portal>

<!-- Link -->
<recur-portal portal-url="..." button-style="link">
  管理訂閱
</recur-portal>

事件處理

portal-redirect

在導向 Portal 前觸發:

document.querySelector('recur-portal').addEventListener('portal-redirect', (event) => {
  console.log('Redirecting to:', event.detail.url);
  // 可用於追蹤分析
  analytics.track('portal_opened');
});

portal-error

發生錯誤時觸發:

document.querySelector('recur-portal').addEventListener('portal-error', (event) => {
  console.error('Portal error:', event.detail.message);
  // 顯示錯誤訊息給用戶
  alert('無法開啟訂閱管理頁面,請稍後再試');
});

React 整合

使用 Web Component

// components/PortalButton.tsx
'use client';

import { useEffect, useRef } from 'react';
import 'recur-tw';

interface PortalButtonProps {
  portalUrl?: string;
  apiEndpoint?: string;
  customerId?: string;
}

export function PortalButton({ portalUrl, apiEndpoint, customerId }: PortalButtonProps) {
  const ref = useRef<HTMLElement>(null);

  useEffect(() => {
    const element = ref.current;
    if (!element) return;

    const handleError = (e: Event) => {
      const { message } = (e as CustomEvent).detail;
      console.error('Portal error:', message);
    };

    element.addEventListener('portal-error', handleError);
    return () => element.removeEventListener('portal-error', handleError);
  }, []);

  return (
    <recur-portal
      ref={ref}
      portal-url={portalUrl}
      api-endpoint={apiEndpoint}
      customer-id={customerId}
    >
      管理訂閱
    </recur-portal>
  );
}

使用自訂按鈕

如果您想使用自己的 UI 元件,可以直接呼叫 SDK 方法:

'use client';

import { useState } from 'react';
import Recur from 'recur-tw';

export function CustomPortalButton({ customerId }: { customerId: string }) {
  const [loading, setLoading] = useState(false);

  const handleClick = async () => {
    setLoading(true);

    try {
      const recur = Recur.init({ publishableKey: 'pk_xxx' });

      const session = await recur.createPortalSession('/api/portal/create', {
        customerId,
      });

      window.location.href = session.url;
    } catch (error) {
      console.error('Failed to open portal:', error);
    } finally {
      setLoading(false);
    }
  };

  return (
    <button
      onClick={handleClick}
      disabled={loading}
      className="btn btn-primary"
    >
      {loading ? '載入中...' : '管理訂閱'}
    </button>
  );
}

Vue 整合

<template>
  <recur-portal
    :portal-url="portalUrl"
    @portal-redirect="onRedirect"
    @portal-error="onError"
  >
    管理訂閱
  </recur-portal>
</template>

<script setup lang="ts">
import 'recur-tw';

defineProps<{
  portalUrl: string;
}>();

const onRedirect = (event: CustomEvent) => {
  console.log('Redirecting to:', event.detail.url);
};

const onError = (event: CustomEvent) => {
  console.error('Portal error:', event.detail.message);
};
</script>

後端 API 範例

當使用 api-endpoint 模式時,您需要建立對應的後端 API:

// app/api/portal/create/route.ts
import { NextRequest, NextResponse } from 'next/server';
import Recur from 'recur-tw/server';
import { auth } from '@/lib/auth';

const recur = new Recur({
  secretKey: process.env.RECUR_SECRET_KEY!,
});

export async function POST(request: NextRequest) {
  // 驗證用戶
  const session = await auth();
  if (!session?.user) {
    return NextResponse.json({ error: { message: 'Unauthorized' } }, { status: 401 });
  }

  // 從請求中取得參數(可選)
  const body = await request.json().catch(() => ({}));

  // 建立 Portal Session
  const portalSession = await recur.portal.sessions.create({
    customer: session.user.recurCustomerId,
    returnUrl: body.returnUrl || `${process.env.NEXT_PUBLIC_URL}/account`,
  });

  // 返回 URL(組件期望的格式)
  return NextResponse.json({
    url: portalSession.url,
  });
}

TypeScript 支援

// 宣告 Web Component 類型
declare global {
  namespace JSX {
    interface IntrinsicElements {
      'recur-portal': React.DetailedHTMLProps<
        React.HTMLAttributes<HTMLElement> & {
          'portal-url'?: string;
          'api-endpoint'?: string;
          'customer-id'?: string;
          'return-url'?: string;
          'button-text'?: string;
          'button-style'?: 'primary' | 'outline' | 'gradient' | 'link';
          'target'?: string;
          'disabled'?: boolean;
        },
        HTMLElement
      >;
    }
  }
}

下一步

  • 後端整合 - Server SDK 詳細說明
  • Portal API 參考 - 完整 API 文件
  • Webhook 整合 - 接收訂閱變更通知

後端整合

使用 Recur Server SDK 整合 Customer Portal

Webhooks 概覽

使用 Webhooks 即時接收訂閱和付款事件通知

On this page

前端整合安裝 SDK<recur-portal> 組件使用方式一:直接提供 Portal URL使用方式二:透過 API 動態建立屬性說明按鈕樣式事件處理portal-redirectportal-errorReact 整合使用 Web Component使用自訂按鈕Vue 整合後端 API 範例TypeScript 支援下一步