> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dodopayments.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 座席ベースの価格設定とアドオンおよび支払いリンク

> Dodo Paymentsを使用して、座席ベースの価格設定のためのアドオンを作成し、カスタムアドオン数量を持つ支払いリンクを生成する方法を学びます。

このチュートリアルでは、Dodo Paymentsのアドオンを使用して座席ベースの価格設定を実装する方法を学びます。追加の座席用のアドオンを持つサブスクリプション製品を作成し、カスタムアドオン数量を持つ支払いリンクを生成する方法を示します。

<Note>
  このチュートリアルでは、Node.js/Expressアプリケーションのサンプル実装コードを紹介します。Next.js、React、Vueなどの具体的なフレームワークに合わせてこのコードを変更し、アプリケーションの要件に応じてユーザーインターフェイスをカスタマイズできます。
</Note>

このチュートリアルの終わりまでに、次のことができるようになります：

* 座席ベースの価格設定を持つサブスクリプション製品を作成する
* 追加の座席用のアドオンを設定する
* カスタムアドオン数量を持つ支払いリンクを生成する
* 動的な座席数を持つチェックアウトセッションを処理する

## 何を作成するか

座席ベースの価格モデルを作成しましょう：

* **基本プラン**: 5人のチームメンバーまで月額49ドル
* **座席アドオン**: 追加の座席1つにつき月額2ドル
* **支払いリンク**: カスタム座席数量での動的チェックアウト

<Info>
  始める前に、以下を確認してください：

  * Dodo Paymentsアカウント
  * TypeScript/Node.jsの基本的な知識
</Info>

## ステップ1: 座席アドオンを作成する

追加の座席を表すアドオンを作成する必要があります。このアドオンは基本のサブスクリプションに添付され、顧客が追加の座席を購入できるようにします。

<Frame>
  <img src="https://mintcdn.com/dodopayments/ajOhO6Du1yNsg0hy/images/cookbooks/seat-based/seat-based-addons-creation.png?fit=max&auto=format&n=ajOhO6Du1yNsg0hy&q=85&s=d2c17b4a9f2f9a1b19f537f0507656a4" alt="基本サブスクリプション製品の作成" style={{ maxHeight: '500px', width: 'auto' }} width="2348" height="1606" data-path="images/cookbooks/seat-based/seat-based-addons-creation.png" />
</Frame>

<Tip>
  **今回作成するもの**：1席あたり月額2ドルのアドオンで、任意の基本サブスクリプションに追加できます。
</Tip>

<Steps>
  <Step title="Navigate to Add-Ons">
    1. Dodo Paymentsのダッシュボードで**Products**セクションにとどまります
    2. **Add-Ons**タブをクリック
    3. **Create Add-On**をクリック

    これでアドオン作成フォームが開きます。
  </Step>

  <Step title="Enter add-on details">
    座席アドオンには次の値を入力します：

    **Add-On Name**：`Additional Team Seat`

    **Description**：`Add extra team members to your workspace with full access to all features`

    **Price**：→ `2.00` を入力

    **通貨**: 基本サブスクリプションの通貨と一致する必要があります

    **税カテゴリ**: 製品に適切なカテゴリを選択します。
  </Step>

  <Step title="Save your add-on">
    1. 設定を確認します：
       * 名称：Additional Team Seat
       * 価格：月額2.00ドル
    2. **Create Add-On**をクリック

    <Check>
      **アドオンが作成されました！** あなたの座席アドオンは、サブスクリプションに追加できるようになりました。
    </Check>
  </Step>
</Steps>

## ステップ2: 基本サブスクリプション製品を作成する

5人のチームメンバーを含む基本サブスクリプション製品を作成します。これが座席ベースの価格モデルの基盤となります。

<Frame>
  <img src="https://mintcdn.com/dodopayments/ajOhO6Du1yNsg0hy/images/cookbooks/seat-based/seat-based-subscription.png?fit=max&auto=format&n=ajOhO6Du1yNsg0hy&q=85&s=f17e96f3d106b88b6dc32a00be535620" alt="基本サブスクリプション製品の作成" style={{ maxHeight: '500px', width: 'auto' }} width="2118" height="1580" data-path="images/cookbooks/seat-based/seat-based-subscription.png" />
</Frame>

<Steps>
  <Step title="Navigate to Products">
    1. Dodo Paymentsダッシュボードにログイン
    2. 左側のサイドバーで**Products**をクリック
    3. **Create Product**ボタンをクリック
    4. 製品タイプとして**Subscription**を選択

    基本サブスクリプションの設定を行うフォームが表示されるはずです。
  </Step>

  <Step title="Fill in the subscription details">
    ここで基本プランの詳細を入力します：

    **Product Name**：`Motion`

    **Description**：`Where your team's documentation lives.`

    **Recurring Price**：→ `49.00` を入力

    **Billing Cycle**：→ `Monthly` を選択

    **Currency**：希望する通貨を選択（例：`USD`）
  </Step>
</Steps>

## ステップ3: アドオンをサブスクリプションに接続する

座席アドオンを基本サブスクリプションに関連付ける必要があります。これにより、顧客はチェックアウト中に追加の座席を購入できます。

<Steps>
  <Step title="Attach the seat add-on">
    <Frame>
      <img src="https://mintcdn.com/dodopayments/ajOhO6Du1yNsg0hy/images/cookbooks/seat-based/seat-based-addons.png?fit=max&auto=format&n=ajOhO6Du1yNsg0hy&q=85&s=ea4ce0d437201c92590eea6c31a14e80" alt="サブスクリプションへのアドオンの追加" style={{ maxHeight: '500px', width: 'auto' }} width="2338" height="1196" data-path="images/cookbooks/seat-based/seat-based-addons.png" />
    </Frame>

    1. **アドオン**セクションまでスクロールします
    2. **アドオンを追加**をクリックします
    3. ドロップダウンから座席アドオンを選択します
    4. サブスクリプション設定に表示されていることを確認します
  </Step>

  <Step title="Save subscription changes">
    1. サブスクリプション設定を確認します：
       * 基本プラン：5席で月額49ドル
       * アドオン：追加席1席あたり月額2ドル
       * 無料トライアル：14日間
    2. **Save Changes**をクリック

    <Check>
      **席数ベースの価格設定が構成されました！** 顧客は基本プランを購入し、必要に応じて追加席を追加できます。
    </Check>
  </Step>
</Steps>

## ステップ4: カスタムアドオン数量で支払いリンクを生成する

次に、カスタムアドオン数量で支払いリンクを生成するExpress.jsアプリケーションを作成します。これが座席ベースの価格設定の真の力です - 追加の座席の数に応じて動的にチェックアウトセッションを作成できます。

<Steps>
  <Step title="Set up your project">
    新しいNode.jsプロジェクトを作成し、必要な依存関係をインストールします：

    ```bash theme={null}
    mkdir seat-based-pricing
    cd seat-based-pricing
    npm init -y
    npm install dodopayments express dotenv
    npm install -D @types/node @types/express typescript ts-node
    ```

    `tsconfig.json` ファイルを作成：

    ```json theme={null}
    {
      "compilerOptions": {
        "target": "ES2020",
        "module": "commonjs",
        "outDir": "./dist",
        "rootDir": "./src",
        "strict": true,
        "esModuleInterop": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true
      }
    }
    ```
  </Step>

  <Step title="Create your environment file">
    Dodo PaymentsのAPIキーを含む `.env` ファイルを作成：

    ```bash theme={null}
    DODO_PAYMENTS_API_KEY=your_actual_dodo_api_key_here
    ```

    <Warning>
      APIキーをバージョン管理にコミットしないでください。`.env` を `.gitignore` ファイルに追加します。
    </Warning>
  </Step>

  <Step title="Implement the checkout session creation">
    以下のコードを含む `src/server.ts` ファイルを作成：

    <CodeGroup>
      ```typescript server.ts expandable theme={null}
      // Add this new endpoint for dynamic seat quantities
      import 'dotenv/config';
      import DodoPayments from 'dodopayments';
      import express, { Request, Response } from 'express';

      const app = express();

      // Initialize the Dodo Payments client
      const client = new DodoPayments({
        bearerToken: process.env.DODO_PAYMENTS_API_KEY,
        environment: 'test_mode'
      });

      async function createCheckoutSession(seatCount: number) {
        try {
          const session = await client.checkoutSessions.create({
            // Products to sell - use IDs from your Dodo Payments dashboard
            product_cart: [
              {
                product_id: 'pdt_7Rl9OWT2Mz4wwUTKz74iZ', // Replace with your actual product ID
                quantity: 1,
                addons: [
                  {
                    addon_id: 'adn_eKQbNakKrivDpaxmI8wKI', // Replace with your actual addon ID
                    quantity: seatCount
                  }
                ]
              }
            ],
            
            // Pre-fill customer information to reduce friction
            customer: {
              email: 'steve@example.com',
              name: 'Steve Irwin',
            },
            // Where to redirect after successful payment
            return_url: 'https://example.com/checkout/success',
          });

          // Redirect your customer to this URL to complete payment
          console.log('Checkout URL:', session.checkout_url);
          console.log('Session ID:', session.session_id);
          
          return session;
          
        } catch (error) {
          console.error('Failed to create checkout session:', error);
          throw error;
        }
      }

      // Example usage in an Express.js route
      app.post('/create-checkout/:seatCount', async (req: Request, res: Response) => {
        try {
          const seatCount = parseInt(req.params.seatCount);
          const session = await createCheckoutSession(seatCount);
          res.json({ checkout_url: session.checkout_url });
        } catch (error) {
          res.status(500).json({ error: 'Failed to create checkout session' });
        }
      });

      // Add this line after your other middleware
      app.use(express.static('public'));

      // Add this route to serve the demo page
      app.get('/', (req, res) => {
        res.sendFile(__dirname + '/../public/index.html');
      });

      app.listen(3000, () => {
        console.log('Server is running on port 3000');
      });
      ```
    </CodeGroup>
  </Step>

  <Step title="Add a simple web interface">
    テストを簡略化するための `public/index.html` ファイルを作成：

    <CodeGroup>
      ```html index.html expandable theme={null}
      <!DOCTYPE html>
      <html>
      <head>
          <title>Seat-Based Pricing Demo</title>
          <style>
              body { font-family: Arial, sans-serif; max-width: 600px; margin: 50px auto; padding: 20px; }
              .form-group { margin: 20px 0; }
              label { display: block; margin-bottom: 5px; font-weight: bold; }
              input { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; }
              button { background: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; }
              button:hover { background: #0056b3; }
              .result { margin-top: 20px; padding: 15px; background: #f8f9fa; border-radius: 4px; }
          </style>
      </head>
      <body>
          <h1>Seat-Based Pricing Demo</h1>
          <p>Generate checkout links with custom seat quantities:</p>
          
          <div class="form-group">
              <label for="seatCount">Number of Additional Seats:</label>
              <input type="number" id="seatCount" value="3" min="0" max="50">
          </div>
          
          <button onclick="createCheckout()">Generate Checkout Link</button>
          
          <div id="result" class="result" style="display: none;">
              <h3>Checkout Link Generated!</h3>
              <p><strong>Seat Count:</strong> <span id="seatCountDisplay"></span></p>
              <p><strong>Total Cost:</strong> $<span id="totalCost"></span>/month</p>
              <p><strong>Checkout URL:</strong></p>
              <a id="checkoutUrl" href="#" target="_blank">Click here to checkout</a>
          </div>

          <script>
              async function createCheckout() {
                  const seatCount = document.getElementById('seatCount').value;
                  
                  try {
                      const response = await fetch(`/create-checkout/${seatCount}`, {
                          method: 'POST'
                      });
                      
                      const data = await response.json();
                      
                      if (response.ok) {
                          document.getElementById('seatCountDisplay').textContent = seatCount;
                          document.getElementById('totalCost').textContent = data.total_cost;
                          document.getElementById('checkoutUrl').href = data.checkout_url;
                          document.getElementById('result').style.display = 'block';
                      } else {
                          alert('Error: ' + data.error);
                      }
                  } catch (error) {
                      alert('Error creating checkout session');
                  }
              }
          </script>
      </body>
      </html>
      ```
    </CodeGroup>

    <Check>
      **Webインターフェイスが作成されました！** これで異なる座席数をテストするシンプルなUIが完成しました。
    </Check>
  </Step>

  <Step title="Serve static files">
    HTMLファイルを提供するために、`src/server.ts` に次を追加：

    ```typescript theme={null}
    // Add this line after your other middleware
    app.use(express.static('public'));

    // Add this route to serve the demo page
    app.get('/', (req, res) => {
      res.sendFile(__dirname + '/../public/index.html');
    });
    ```

    <Check>
      **静的ファイルが設定されました！** `http://localhost:3000` を開いてデモインターフェイスを確認してください。
    </Check>
  </Step>
</Steps>

## ステップ5: 実装をテストする

座席ベースの価格設定の実装が正しく機能するかどうかをテストしましょう。

<Steps>
  <Step title="Start your server">
    1. 正しいAPIキーが入った `.env` ファイルを用意
    2. 実際のDodo Paymentsダッシュボードの値で製品IDとアドオンIDをコード内に更新
    3. サーバーを起動：

    ```bash theme={null}
    npm run dev
    ```

    <Check>
      サーバーが正常に起動し、「Server running on `http://localhost:3000`」が表示されるはずです。
    </Check>
  </Step>

  <Step title="Test the web interface">
    <Frame>
      <img src="https://mintcdn.com/dodopayments/ajOhO6Du1yNsg0hy/images/cookbooks/seat-based/seat-based-billing-ui.png?fit=max&auto=format&n=ajOhO6Du1yNsg0hy&q=85&s=37d166d8e76b0bfbb4959bc9a3eff1f8" alt="基本サブスクリプション製品の作成" style={{ maxHeight: '500px', width: 'auto' }} width="1806" height="1416" data-path="images/cookbooks/seat-based/seat-based-billing-ui.png" />
    </Frame>

    1. ブラウザで `http://localhost:3000` にアクセス
    2. 座席ベースの価格デモインターフェイスが表示されるはずです
    3. 異なる座席数（0、3、10など）を試す
    4. 各座席数で「Generate Checkout Link」をクリック
    5. チェックアウトURLが正しく生成されていることを確認
  </Step>

  <Step title="Test a checkout session">
    1. 追加席3席でチェックアウトリンクを生成
    2. チェックアウトURLをクリックしてDodo Paymentsのチェックアウトを開く
    3. チェックアウトに以下が表示されていることを確認：
       * 基本プラン：月額49ドル
       * 追加席：3 × 2ドル = 月額6ドル
    4. テスト購入を完了

    <Check>
      チェックアウトには正しい価格内訳が表示され、購入を完了できるはずです。
    </Check>
  </Step>

  <Step title="Listen for webhooks and update your DB">
    サブスクリプションや席数の変更をデータベースと同期するには、Dodo PaymentsからのWebhookイベントを監視する必要があります。Webhookは顧客がチェックアウトを完了したり、サブスクリプションを更新したり、席数を変更したときにバックエンドに通知します。

    Webhookエンドポイントを設定し、イベントを処理する手順については、公式のDodo Payments Webhookガイドを参照してください：

    <Card title="Dodo Payments Webhooks Documentation" icon="bell" href="/developer-resources/webhooks">
      サブスクリプションと席数管理のためにWebhookイベントを安全に受信および処理する方法を学びます。
    </Card>
  </Step>
</Steps>

## トラブルシューティング

一般的な問題とその解決策：

<AccordionGroup>
  <Accordion title="Checkout creation failing">
    **考えられる原因：**

    * 無効な製品IDまたはアドオンID
    * APIキーに十分な権限がない
    * アドオンがサブスクリプションに正しく関連付けられていない
    * ネットワーク接続の問題

    **解決策：**

    1. Dodo Paymentsダッシュボードに製品とアドオンIDが存在することを確認
    2. アドオンがサブスクリプションに正しく添付されていることを確認
    3. APIキーにチェックアウトセッション作成の権限があることを確認
    4. 単純なGETリクエストでAPI接続性をテスト
  </Accordion>
</AccordionGroup>

## おめでとうございます！座席ベースの価格設定を実装しました

Dodo Paymentsを使用して座席ベースの価格設定システムを成功裏に作成しました！達成したことは次のとおりです：

<CardGroup cols={2}>
  <Card title="Base Subscription">
    5席含むサブスクリプション製品を月額49ドルで作成しました
  </Card>

  <Card title="Seat Add-ons">
    追加席用のアドオンを1席あたり月額2ドルで構成しました
  </Card>

  <Card title="Checkout">
    カスタム座席数でチェックアウトセッションを生成するAPIを構築しました
  </Card>

  <Card title="Web Interface">
    異なる座席数をテストするためのシンプルなWebインターフェイスを作成しました
  </Card>
</CardGroup>

<Info>
  この例は席数ベースの価格設定の最小限の実装のみを示しています。本番環境では、堅牢なエラーハンドリング、認証、データ検証、セキュリティ対策を追加し、アプリケーションの要件に合わせてロジックを調整してください。
</Info>
