---
title: 基本結帳範例
description: 實作最簡單的訂閱結帳流程
---

# 基本結帳範例

這個範例展示如何快速整合 Recur SDK（0.4.4+）來建立基本的訂閱結帳流程。

  **提示**：`customerEmail` 和 `customerName` 都是選填。如果未預填，用戶會在結帳頁面輸入（Email 在結帳時為必填，用於寄送收據）。

## 完整範例程式碼

```javascript
// 1. 初始化 SDK
const recur = RecurCheckout.init({
  publishableKey: 'pk_test_xxx', // 您的 Publishable Key
});

// 2. 建立結帳按鈕並綁定事件
const checkoutButton = document.getElementById('checkout-button');

checkoutButton.addEventListener('click', async () => {
  try {
    // 3. 開啟結帳視窗
    await recur.checkout({
      productId: 'prod_xxx',             // 產品 ID（或使用 productSlug）
      customerEmail: 'user@example.com', // 選填：預填 Email
      customerName: '使用者名稱',         // 選填：預填姓名
      externalId: 'user_123',            // 選填：連結您系統的用戶
      mode: 'modal',
      onSuccess: (result) => {
        console.log('Checkout session 建立成功:', result);
      },
      onPaymentComplete: (result) => {
        console.log('付款完成:', result);
        window.location.href = '/subscription/success';
      },
      onPaymentFailed: (error) => {
        // 可選：自訂付款失敗處理
        // 回傳 undefined 使用 SDK 預設行為（顯示錯誤訊息並允許重試）
        console.log('付款失敗:', error.details?.failure_code);

        // 或自訂處理邏輯
        if (error.details?.failure_code === 'INSUFFICIENT_FUNDS') {
          return {
            action: 'custom',
            customTitle: '餘額不足',
            customMessage: '請使用其他付款方式或聯繫客服',
          };
        }
      },
      onError: (error) => {
        console.error('結帳錯誤:', error);
        alert('結帳時發生錯誤，請稍後再試');
      },
      onClose: () => {
        console.log('使用者關閉結帳視窗');
      },
    });
  } catch (error) {
    console.error('開啟結帳視窗時發生錯誤:', error);
  }
});
```

```tsx
import { RecurCheckout } from 'recur-tw';
import { useState, useCallback } from 'react';

export function SubscriptionButton({ productId }: { productId: string }) {
  const [isLoading, setIsLoading] = useState(false);

  const handleSubscribe = useCallback(async () => {
    setIsLoading(true);

    const recur = RecurCheckout.init({
      publishableKey: process.env.NEXT_PUBLIC_RECUR_PUBLISHABLE_KEY!,
    });

    try {
      await recur.checkout({
        productId,                         // 產品 ID（或使用 productSlug）
        customerEmail: 'user@example.com', // 選填：預填 Email
        customerName: '使用者名稱',         // 選填：預填姓名
        mode: 'modal',
        onPaymentComplete: (result) => {
          console.log('付款完成:', result);
          window.location.href = '/subscription/success';
        },
        onPaymentFailed: (error) => {
          // 可選：自訂付款失敗處理
          console.log('付款失敗:', error.details?.failure_code);
          // 回傳 undefined 使用預設行為
        },
        onError: (error) => {
          console.error('結帳錯誤:', error);
          alert('結帳時發生錯誤，請稍後再試');
          setIsLoading(false);
        },
        onClose: () => {
          setIsLoading(false);
        },
      });
    } catch (error) {
      console.error('開啟結帳視窗時發生錯誤:', error);
      setIsLoading(false);
    }
  }, [productId]);

  return (
    <button
      onClick={handleSubscribe}
      disabled={isLoading}
      className="subscribe-button"
    >
      {isLoading ? '處理中...' : '立即訂閱'}
    </button>
  );
}
```

## HTML 結構

```html
<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Recur SDK - 基本結帳範例</title>
</head>
<body>
  <div class="container">
    <h1>訂閱我們的服務</h1>
    <p>選擇您想要的訂閱方案</p>

    <div class="plan-card">
      <h2>專業方案</h2>
      <p class="price">NT$ 999 / 月</p>
      <ul>
        <li>功能 A</li>
        <li>功能 B</li>
        <li>功能 C</li>
      </ul>
      <button id="checkout-button">立即訂閱</button>
    </div>
  </div>

  <!-- 載入 Recur SDK -->
  <script src="https://unpkg.com/recur-tw@latest/dist/recur.umd.js"></script>
  <!-- 你的應用程式腳本 -->
  <script src="app.js"></script>
</body>
</html>
```

## 步驟說明

### 1. 安裝 SDK

```bash
npm install recur-tw
# 或
yarn add recur-tw
# 或
pnpm add recur-tw
```

```html
<script src="https://unpkg.com/recur-tw@latest/dist/recur.umd.js"></script>
```

### 2. 取得必要的資訊

你需要以下資訊：

- **Publishable Key**：在 [Recur 儀表板](https://app.recur.tw) → 設定 → 開發者 → API 金鑰
- **Product ID**：在儀表板的「商品管理」中建立並取得

### 3. 初始化 SDK

使用你的 Publishable Key 初始化 SDK：

```javascript
const recur = RecurCheckout.init({
  publishableKey: 'pk_test_xxx',
});
```

### 4. 開啟結帳視窗

呼叫 `recur.checkout()` 並傳入參數：

| 參數 | 必填 | 說明 |
|------|------|------|
| `productId` | ✅* | 產品 ID（與 productSlug 二擇一） |
| `productSlug` | ✅* | 產品 Slug（與 productId 二擇一） |
| `customerEmail` | ❌ | 預填客戶 Email（結帳時必填） |
| `customerName` | ❌ | 預填客戶姓名 |
| `externalId` | ❌ | 外部客戶 ID |
| `mode` | ❌ | `'modal'` 或 `'iframe'` |

### 回調函數

| 回調 | 說明 |
|------|------|
| `onSuccess` | Checkout session 建立成功時呼叫 |
| `onPaymentComplete` | 付款成功完成時呼叫 |
| `onPaymentFailed` | 付款失敗時呼叫（可自訂處理邏輯） |
| `onError` | 結帳流程發生錯誤時呼叫 |
| `onClose` | 使用者關閉結帳視窗時呼叫 |

**`onPaymentFailed` vs `onError`**：`onPaymentFailed` 專門處理「用戶送出付款後」的失敗（如卡片被拒絕），而 `onError` 處理其他錯誤（如網路問題、API 錯誤）。詳見[錯誤處理指南](/guides/checkout/error-handling)。

## 重點提醒

**測試模式**：開發時請使用測試環境的 API Key（`pk_test_xxx`），避免產生實際交易。

**安全性**：Publishable Key 可以在前端使用，但 Secret Key 必須保持在後端。

## 常見問題

### Q: customerEmail 和 customerName 是必填嗎？

A: 兩者在建立 checkout session 時都是**選填**的。如果未預填，用戶會在結帳頁面輸入。但 Email 在結帳時是必填的（用於寄送收據）。

### Q: 如何處理使用者取消訂閱？

A: 使用 `onClose` 回調函數來處理使用者關閉結帳視窗的情況。

### Q: 可以自訂結帳視窗的樣式嗎？

A: 可以！請參考 [自訂樣式範例](/guides/examples/custom-styling)。

### Q: 如何驗證訂閱是否成功？

A: 建議在後端透過 Webhook 來驗證訂閱狀態，詳見 [Webhook 處理範例](/guides/examples/webhook-handling)。

### Q: 如何自訂付款失敗的處理方式？

A: 使用 `onPaymentFailed` 回調函數可以根據不同的失敗原因自訂處理邏輯。詳見[錯誤處理指南](/guides/checkout/error-handling)。

## 下一步

- [錯誤處理](/guides/checkout/error-handling) - 深入了解付款錯誤處理
- [自訂樣式](/guides/examples/custom-styling) - 學習如何自訂樣式
- [Webhook 通知](/guides/webhooks) - 設定即時付款通知
- [API 參考](/api-reference) - 查看完整的 API 文件
