> ## 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.

# Checkout Sessions

> Create secure, hosted checkout experiences that handle the complete payment flow for both one-time purchases and subscriptions with full customization control.

<CardGroup cols={2}>
  <Card title="Quick Start Guide" icon="rocket" href="#creating-your-first-checkout-session">
    Get your first checkout session running in under 5 minutes
  </Card>

  <Card title="API Reference & Live Testing" icon="code" href="/api-reference/checkout-sessions/create">
    Explore the full API documentation and interactively test Checkout Session requests and responses.
  </Card>

  <Card title="Preview Checkout" icon="eye" href="/api-reference/checkout-sessions/preview">
    Calculate pricing, taxes, and totals before creating a session.
  </Card>
</CardGroup>

<Info>
  **Session Validity**: Checkout sessions are valid for 24 hours by default. If you pass `confirm=true` in your request, the session will only be valid for 15 minutes.
</Info>

## Prerequisites

<Steps>
  <Step title="Dodo Payments Account">
    You'll need an active Dodo Payments merchant account with API access.
  </Step>

  <Step title="API Credentials">
    Generate your API credentials from the Dodo Payments dashboard:
  </Step>

  <Step title="Products Setup">
    Create your products in the Dodo Payments dashboard before implementing checkout sessions.
  </Step>
</Steps>

## Creating Your First Checkout Session

<Tabs>
  <Tab title="Node.js SDK">
    ```javascript expandable theme={null}
    import DodoPayments from 'dodopayments';

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

    async function createCheckoutSession() {
      try {
        const session = await client.checkoutSessions.create({
          // Products to sell - use IDs from your Dodo Payments dashboard
          product_cart: [
            {
              product_id: 'prod_123', // Replace with your actual product ID
              quantity: 1
            }
          ],
          
          // Pre-fill customer information to reduce friction
          customer: {
            email: 'customer@example.com',
            name: 'John Doe',
            phone_number: '+1234567890'
          },
          
          // Billing address for tax calculation and compliance
          billing_address: {
            street: '123 Main St',
            city: 'San Francisco',
            state: 'CA',
            country: 'US', // Required: ISO 3166-1 alpha-2 country code
            zipcode: '94102'
          },
          
          // Where to redirect after successful payment
          return_url: 'https://yoursite.com/checkout/success',
          
          // Custom data for your internal tracking
          metadata: {
            order_id: 'order_123',
            source: 'web_app'
          }
        });

        // 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', async (req, res) => {
      try {
        const session = await createCheckoutSession();
        res.json({ checkout_url: session.checkout_url });
      } catch (error) {
        res.status(500).json({ error: 'Failed to create checkout session' });
      }
    });
    ```
  </Tab>

  <Tab title="Python SDK">
    ```python expandable theme={null}
    import os
    from dodopayments import DodoPayments

    # Initialize the Dodo Payments client
    client = DodoPayments(
        bearer_token=os.environ.get("DODO_PAYMENTS_API_KEY"),  # This is the default and can be omitted
        environment="test_mode",  # defaults to "live_mode"
    )

    def create_checkout_session():
        """
        Create a checkout session for a single product with customer data pre-filled.
        Returns the session object containing checkout_url for customer redirection.
        """
        try:
            session = client.checkout_sessions.create(
                # Products to sell - use IDs from your Dodo Payments dashboard
                product_cart=[
                    {
                        "product_id": "prod_123",  # Replace with your actual product ID
                        "quantity": 1
                    }
                ],
                
                # Pre-fill customer information to reduce checkout friction
                customer={
                    "email": "customer@example.com",
                    "name": "John Doe",
                    "phone_number": "+1234567890"
                },
                
                # Billing address for tax calculation and compliance
                billing_address={
                    "street": "123 Main St",
                    "city": "San Francisco", 
                    "state": "CA",
                    "country": "US",  # Required: ISO 3166-1 alpha-2 country code
                    "zipcode": "94102"
                },
                
                # Where to redirect after successful payment
                return_url="https://yoursite.com/checkout/success",
                
                # Custom data for your internal tracking
                metadata={
                    "order_id": "order_123",
                    "source": "web_app"
                }
            )
            
            # Redirect your customer to this URL to complete payment
            print(f"Checkout URL: {session.checkout_url}")
            print(f"Session ID: {session.session_id}")
            
            return session
            
        except Exception as error:
            print(f"Failed to create checkout session: {error}")
            raise error

    # Example usage in a Flask route
    from flask import Flask, jsonify, request

    app = Flask(__name__)

    @app.route('/create-checkout', methods=['POST'])
    def create_checkout():
        try:
            session = create_checkout_session()
            return jsonify({"checkout_url": session.checkout_url})
        except Exception as error:
            return jsonify({"error": "Failed to create checkout session"}), 500
    ```
  </Tab>

  <Tab title="REST API">
    ```javascript expandable theme={null}
    // Direct API call using fetch - useful for any JavaScript environment
    async function createCheckoutSession() {
      try {
        const response = await fetch('https://test.dodopayments.com/checkouts', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${process.env.DODO_PAYMENTS_API_KEY}`
          },
          body: JSON.stringify({
            // Products to sell - use IDs from your Dodo Payments dashboard
            product_cart: [
              {
                product_id: 'prod_123', // Replace with your actual product ID
                quantity: 1
              }
            ],
            
            // Pre-fill customer information to reduce checkout friction
            customer: {
              email: 'customer@example.com',
              name: 'John Doe',
              phone_number: '+1234567890'
            },
            
            // Billing address for tax calculation and compliance
            billing_address: {
              street: '123 Main St',
              city: 'San Francisco',
              state: 'CA', 
              country: 'US', // Required: ISO 3166-1 alpha-2 country code
              zipcode: '94102'
            },
            
            // Where to redirect after successful payment
            return_url: 'https://yoursite.com/checkout/success',
            
            // Custom data for your internal tracking
            metadata: {
              order_id: 'order_123',
              source: 'web_app'
            }
          })
        });

        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }

        const session = await response.json();
        
        // 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: Redirect user to checkout
    createCheckoutSession().then(session => {
      window.location.href = session.checkout_url;
    });
    ```
  </Tab>
</Tabs>

### API Response

All methods above return the same response structure:

```json theme={null}
{
  "session_id": "cks_Gi6KGJ2zFJo9rq9Ukifwa",
  "checkout_url": "https://test.checkout.dodopayments.com/session/cks_Gi6KGJ2zFJo9rq9Ukifwa"
}
```

<Steps>
  <Step title="Get the checkout URL">
    Extract the `checkout_url` from the API response.
  </Step>

  <Step title="Redirect your customer">
    Direct your customer to the checkout URL to complete their purchase.

    ```javascript theme={null}
    // Redirect immediately
    window.location.href = session.checkout_url;

    // Or open in new window
    window.open(session.checkout_url, '_blank');
    ```

    <Tip>
      **Alternative Integration Options**: Instead of redirecting, you can embed the checkout directly in your page using [Overlay Checkout](/developer-resources/overlay-checkout) (modal overlay) or [Inline Checkout](/developer-resources/inline-checkout) (fully embedded). Both options use the same checkout session URL.
    </Tip>
  </Step>

  <Step title="Handle the return">
    After payment, customers are redirected to your `return_url` with query parameters including payment/subscription ID, status, customer email, and any license keys. See the [`return_url` parameter docs](#request-body) for the full list.
  </Step>
</Steps>

## Request Body

<CardGroup cols={2}>
  <Card title="Required Fields" icon="asterisk">
    Essential fields needed for every checkout session
  </Card>

  <Card title="Optional Fields" icon="gear">
    Additional configuration to customize your checkout experience
  </Card>
</CardGroup>

### Required Fields

<ParamField body="product_cart" type="array" required>
  Array of products to include in the checkout session. Each product must have a valid `product_id` from your Dodo Payments dashboard.

  <Tip>
    **Mixed Checkout**: You can combine one-time payment products and subscription products in the same checkout session. This enables powerful use cases like setup fees with subscriptions, hardware bundles with SaaS, and more.
  </Tip>

  <Expandable title="Product Cart Item Properties">
    <ParamField body="product_id" type="string" required>
      The unique identifier of the product from your Dodo Payments dashboard.

      **Example:** `"prod_123abc456def"`
    </ParamField>

    <ParamField body="quantity" type="integer" required>
      Quantity of the product.

      **Example:** `1` for single item, `3` for multiple quantities
    </ParamField>

    <ParamField body="addons" type="array">
      Array of addons to attach to the product. Only valid if the product is a subscription.

      <Expandable title="Addon item properties">
        <ParamField body="addon_id" type="string" required />

        <ParamField body="quantity" type="integer" required />
      </Expandable>
    </ParamField>

    <ParamField body="amount" type="integer">
      Amount the customer pays if pay\_what\_you\_want is enabled. If disabled, this field will be ignored.

      **格式**：以货币的最低面额表示（例如，美元为美分）。例如，要收费 \$1.00，请传递 `100`。
    </ParamField>

    <ParamField body="credit_entitlements" type="array">
      覆盖已附加到此产品的信用权利的每次结账会话。使用此功能为这个单一会话授予不同数量的信用，如促销礼包提供 1,000 个 API 信用，而不是产品默认的 500 个，而无需创建单独的产品。

      <Info>
        每个 `credit_entitlement_id` 必须已经附加在产品中。此字段仅覆盖在会话完成时授予的 `credits_amount`，产品级的信用权利设置（到期、结转等）仍然适用。
      </Info>

      <Expandable title="Credit entitlement override properties">
        <ParamField body="credit_entitlement_id" type="string" required>
          要覆盖的信用权利的 ID。必须已附加在产品中。
        </ParamField>

        <ParamField body="credits_amount" type="string" required>
          为此结账会话授予的信用数量，覆盖产品级别的 `credits_amount`。必须大于零。
        </ParamField>
      </Expandable>
    </ParamField>
  </Expandable>
</ParamField>

<Tip>
  **查找您的产品 ID**：您可以在您的 Dodo Payments 仪表板中进入产品 → 查看详情，或使用 [列出产品 API](/api-reference/products/get-products)找到产品 ID。
</Tip>

### 可选字段

配置这些字段以自定义结账体验，并将业务逻辑添加到您的支付流程中。

<AccordionGroup>
  <Accordion title="Customer Information">
    <ParamField body="customer" type="object">
      客户信息。您可以通过他们的 ID 附加一个现有客户，或在结账期间创建一个新的客户记录。

      <Tabs>
        <Tab title="Attach Existing Customer">
          使用客户的 ID 将现有客户附加到结账会话。

          <Expandable title="Existing Customer Properties">
            <ParamField body="customer_id" type="string" required>
              现有客户的唯一标识符。使用此功能将结账会话附加到现有客户，而不是创建新客户。
            </ParamField>
          </Expandable>
        </Tab>

        <Tab title="New Customer">
          在结账期间创建新的客户记录。

          <Expandable title="New Customer Properties">
            <ParamField body="email" type="string" required>
              客户的电子邮件地址。在创建新客户时需要提供。
            </ParamField>

            <ParamField body="name" type="string">
              客户的全名应在收据和发票上显示。

              **示例**：`"John Doe"` 或 `"Jane Smith"`
            </ParamField>

            <ParamField body="phone_number" type="string">
              客户的电话号码采用国际格式。某些支付方式和防欺诈需要提供。

              **格式**：包括国家代码，例如，美国号码为 `"+1234567890"`
            </ParamField>
          </Expandable>
        </Tab>
      </Tabs>
    </ParamField>

    <ParamField body="billing_address" type="object">
      准确计算税收、防欺诈和法规遵循的帐单地址信息。

      <Info>
        当 `confirm` 设置为 `true` 时，所有帐单地址字段都将是会话成功创建所必需的。
      </Info>

      <Expandable title="Billing address object properties">
        <ParamField body="street" type="string">
          完整的街道地址，包括门牌号码、街道名称和公寓/单元号（如果适用）。

          **示例**：`"123 Main St, Apt 4B"` 或 `"456 Oak Avenue"`
        </ParamField>

        <ParamField body="city" type="string">
          城市或市辖区名称。

          **示例**：`"San Francisco"`、`"New York"`、`"London"`
        </ParamField>

        <ParamField body="state" type="string">
          州、省或地区名称。使用全名或标准缩写。

          **示例**：`"California"` 或 `"CA"`、`"Ontario"` 或 `"ON"`
        </ParamField>

        <ParamField body="country" type="string" required>
          两位字母 ISO 国家代码（ISO 3166-1 alpha-2）。提供帐单地址时，此字段始终是必需的。

          **示例**：`"US"`（美国）、`"CA"`（加拿大）、`"GB"`（英国）、`"DE"`（德国）

          <Card title="Country Code Reference" icon="globe" href="/api-reference/misc/supported-countries">
            查看支持国家及其 ISO 代码的完整列表
          </Card>
        </ParamField>

        <ParamField body="zipcode" type="string">
          根据国家要求，邮政编码、ZIP 代码或等效编码。

          **示例**：`"94102"`（美国）、`"M5V 3A8"`（加拿大）、`"SW1A 1AA"`（英国）
        </ParamField>
      </Expandable>
    </ParamField>
  </Accordion>

  <Accordion title="Payment Configuration">
    <ParamField body="allowed_payment_method_types" type="array">
      控制在结账时可用给客户的支付方式。这有助于优化特定市场或业务需求。

      **可用选项**：`credit`, `debit`, `upi_collect`, `apple_pay`, `google_pay`, `amazon_pay`, `klarna`, `affirm`, `afterpay_clearpay`, `cashapp`, `multibanco`, `bancontact_card`, `eps`, `ideal`, `przelewy24`, `paypal`, `sunbit`

      <Warning>
        **关键**：始终包含 `credit` 和 `debit` 作为备用选项，以防首选支付方式不可用时防止结账失败。
      </Warning>

      **示例**：

      ```json expandable theme={null}
      ["apple_pay", "google_pay", "credit", "debit"]
      ```
    </ParamField>

    <ParamField body="billing_currency" type="string">
      使用固定的计费货币覆盖默认的货币选择。使用 ISO 4217 货币代码。

      **支持货币**：`USD`、`EUR`、`GBP`、`CAD`、`AUD`、`INR` 等

      **示例**：`"USD"` 表示美元，`"EUR"` 表示欧元

      <Note>
        此字段仅在启用自适应定价时有效。如果禁用了自适应定价，则将使用产品的默认货币。
      </Note>
    </ParamField>

    <ParamField body="show_saved_payment_methods" type="boolean" default="false">
      显示返回客户之前保存的支付方式，以改善结账速度和用户体验。
    </ParamField>
  </Accordion>

  <Accordion title="Session Management">
    <ParamField body="return_url" type="string">
      付款完成后重定向客户的 URL。Dodo Payments 会在重定向时将以下查询参数附加到您的 URL：

      | 参数                | 类型       | 条件                          |
      | ----------------- | -------- | --------------------------- |
      | `payment_id`      | `string` | 一次性支付始终存在                   |
      | `subscription_id` | `string` | 订阅付款始终存在                    |
      | `status`          | `string` | 始终存在                        |
      | `license_key`     | `string` | 当产品启用许可证密钥时存在。若为多个密钥，则用逗号分隔 |
      | `email`           | `string` | 当客户有保存的电子邮件记录时存在            |

      **重定向 URL 示例：**

      ```text theme={null}
      # One-time payment with license key
      https://yoursite.com/return?payment_id=pay_xxx&status=succeeded&license_key=LK-001&email=customer%40example.com

      # Subscription payment with multiple license keys
      https://yoursite.com/return?subscription_id=sub_xxx&status=active&license_key=LK-001,LK-002&email=customer%40example.com

      # Payment without license keys
      https://yoursite.com/return?payment_id=pay_xxx&status=succeeded&email=customer%40example.com
      ```

      <Tip>
        使用 `license_key` 和 `email` 查询参数，在返回页面上直接显示许可证密钥或立即发送确认，而无需额外的 API 调用。
      </Tip>
    </ParamField>

    <ParamField body="cancel_url" type="string">
      客户点击返回按钮或取消结账会话时的重定向 URL。如果未提供，则不显示返回按钮。

      <Tip>
        设置 `cancel_url`，给客户一个清晰的方式返回您的网站而无需完成购买。这改善了结账体验，减少了摩擦。
      </Tip>
    </ParamField>

    <ParamField body="confirm" type="boolean" default="false">
      如果为 true，则立即确定所有会话详情。如果需要的数据缺失，API 将抛出错误。
    </ParamField>

    <ParamField body="discount_codes" type="array">
      将一个或多个叠加优惠码应用于结账会话。优惠码按照 **数组顺序** 应用（第一个代码减少基础价格，第二个代码减少已折扣的价格，以此类推），每个会话最多可应用 **20** 个优惠码。

      ```typescript theme={null}
      discount_codes: ['WELCOME10', 'BLACKFRIDAY20']
      ```

      <Info>
        下面的单一 `discount_code` 字段已 **弃用**，但仍然完全支持——现有集成可以继续无需更改地工作。它不能与同一请求中的 `discount_codes` 结合使用。请在方便时迁移到 `discount_codes` 以利用堆叠优势。
      </Info>
    </ParamField>

    <ParamField body="discount_code" type="string" deprecated>
      **已弃用** — 新集成优先使用 `discount_codes`。此字段仍可用于向后兼容，但不能与同一请求中的 `discount_codes` 结合使用。
    </ParamField>

    <ParamField body="metadata" type="object">
      自定义键值对以存储有关会话的附加信息。
    </ParamField>

    <ParamField body="force_3ds" type="boolean">
      覆盖此会话的商家默认 3DS 行为。
    </ParamField>

    <ParamField body="minimal_address" type="boolean" default="false">
      启用最小地址收集模式。启用后，结账仅收集：

      * **国家**：始终确定税的必要条件
      * **ZIP/邮政编码**：仅适用于需要销售税、增值税或消费税计算的地区

      通过消除不必要的表单字段，这显著减少了结账过程中的摩擦。

      <Tip>
        启用最小地址以更快地完成结账。对于需要完整计费详细信息的业务，仍然可以进行完整的地址收集。
      </Tip>
    </ParamField>
  </Accordion>

  <Accordion title="UI Customization & Features">
    <ParamField body="customization" type="object">
      自定义结账界面的外观和行为。

      <Expandable title="Customization object properties">
        <ParamField body="theme" type="string" default="system">
          结账界面的主题。选项：`light`、`dark` 或 `system`。
        </ParamField>

        <ParamField body="show_order_details" type="boolean" default="true">
          在结账界面中显示订单详情部分。
        </ParamField>

        <ParamField body="show_on_demand_tag" type="boolean" default="true">
          对于可应用的产品显示“按需”标签。
        </ParamField>

        <ParamField body="force_language" type="string">
          强制结账界面以特定语言呈现。默认情况下，结账会自动检测客户的浏览器语言。

          **支持的语言代码：**
          `ar`（阿拉伯语）、`ca`（加泰罗尼亚语）、`de`（德语）、`en`（英语）、`es`（西班牙语）、`fr`（法语）、`he`（希伯来语）、`id`（印尼语）、`it`（意大利语）、`ja`（日本语）、`ko`（韩语）、`ms`（马来语）、`nl`（荷兰语）、`pl`（波兰语）、`pt`（葡萄牙语）、`ro`（罗马尼亚语）、`ru`（俄语）、`sv`（瑞典语）、`th`（泰语）、`tr`（土耳其语）、`zh`（汉语）

          **示例**：`"es"` 表示西班牙语，`"ja"` 表示日语
        </ParamField>
      </Expandable>
    </ParamField>

    <ParamField body="feature_flags" type="object">
      为结账会话配置特定功能和行为。

      <Expandable title="Feature flags object properties">
        <ParamField body="allow_currency_selection" type="boolean" default="true">
          允许客户在结账时选择他们的首选货币。
        </ParamField>

        <ParamField body="allow_discount_code" type="boolean" default="true">
          在结账界面中显示优惠码输入字段。
        </ParamField>

        <ParamField body="allow_editing_addons" type="boolean" default="false">
          允许客户在结账时为订阅产品添加或移除附加项。仅适用于订阅产品。
        </ParamField>

        <ParamField body="allow_phone_number_collection" type="boolean" default="true">
          在结账时收集客户的电话号码。
        </ParamField>

        <ParamField body="allow_tax_id" type="boolean" default="true">
          允许客户输入税务识别号。
        </ParamField>

        <ParamField body="always_create_new_customer" type="boolean" default="false">
          强制创建新客户记录而不是更新现有记录。
        </ParamField>

        <ParamField body="allow_customer_editing_email" type="boolean">
          允许客户在结账时编辑他们的电子邮件地址。
        </ParamField>

        <ParamField body="allow_customer_editing_name" type="boolean">
          允许客户在结账时编辑他们的名字。
        </ParamField>

        <ParamField body="allow_customer_editing_street" type="boolean">
          允许客户在结账时编辑街道地址。
        </ParamField>

        <ParamField body="allow_customer_editing_city" type="boolean">
          允许客户在结账时编辑城市。
        </ParamField>

        <ParamField body="allow_customer_editing_state" type="boolean">
          允许客户在结账时编辑州/省。
        </ParamField>

        <ParamField body="allow_customer_editing_country" type="boolean">
          允许客户在结账时编辑国家。
        </ParamField>

        <ParamField body="allow_customer_editing_zipcode" type="boolean">
          允许客户在结账时编辑邮政编码。
        </ParamField>

        <ParamField body="redirect_immediately" type="boolean" default="false">
          跳过默认支付成功页面，在支付完成后立即将客户重定向至您的 `return_url`。

          <Tip>
            当您有一个提供更好用户体验的自定义成功页面时使用，或用于移动应用程序和嵌入式结账流程。
          </Tip>
        </ParamField>
      </Expandable>
    </ParamField>
  </Accordion>

  <Accordion title="Custom Fields">
    <ParamField body="custom_fields" type="array">
      在结账时使用自定义表单字段收集来自客户的额外信息。您可以在每个结账会话中定义最多 5 个自定义字段。客户的响应包含在 webhook 负载中，并可通过 API 获取。

      <Expandable title="Custom field object properties">
        <ParamField body="key" type="string" required>
          此字段的唯一标识符。用于 webhook 负载和 API 响应中的键。

          **示例**：`"company_name"`, `"referral_source"`, `"team_size"`
        </ParamField>

        <ParamField body="label" type="string" required>
          在结账表单上向客户显示的标签。

          **示例**：`"Company Name"`, `"How did you hear about us?"`, `"Team Size"`
        </ParamField>

        <ParamField body="field_type" type="string" required>
          字段类型决定输入验证规则。

          **可用类型**：

          * `text` - 单行文本输入
          * `number` - 数字输入
          * `email` - 带验证的电子邮件地址
          * `url` - 带验证的URL
          * `date` - 日期选择器
          * `dropdown` - 从预定义选项中选择
          * `boolean` - 是/否切换
        </ParamField>

        <ParamField body="required" type="boolean" default="false">
          此字段是否必须在结账完成前填写。
        </ParamField>

        <ParamField body="placeholder" type="string">
          在输入字段中显示的占位符文本。
        </ParamField>

        <ParamField body="options" type="array">
          `dropdown` 字段类型的选项列表。当 `field_type` 为 `dropdown` 时需要，其他类型忽略。

          **示例**：`["Google", "Twitter", "Friend referral", "Other"]`
        </ParamField>
      </Expandable>
    </ParamField>

    <Info>
      客户对自定义字段的响应包含在：

      * **Webhooks**：`payment.succeeded`, `subscription.active`, 和其他相关事件负载中包含 `custom_field_responses` 数组
      * **API 响应**：支付和订阅对象包含 `custom_field_responses`
    </Info>
  </Accordion>

  <Accordion title="Subscription Configuration">
    <ParamField body="subscription_data" type="object">
      包含订阅产品的结账会话的附加配置。

      <Expandable title="Subscription data object properties">
        <ParamField body="trial_period_days" type="integer">
          第一次收费前的试用期天数。必须在0到10000天之间。
        </ParamField>

        <ParamField body="on_demand" type="object">
          按需订阅配置用于基于使用量或计量计费。

          <Expandable title="On-demand object properties">
            <ParamField body="mandate_only" type="boolean" required>
              如果设为 true，不进行任何收费，仅授权付款方式详情以备将来使用。
            </ParamField>

            <ParamField body="product_price" type="integer">
              首次向客户收费的产品价格。如果未指定，将使用存储的产品价格。

              **格式**：以货币的最低单位表示（例如，美分为USD的单位）。例如，收取 \$1.00，请传递 `100`。
            </ParamField>

            <ParamField body="product_currency" type="string">
              产品价格的可选货币。如果未指定，则默认为产品的货币。
            </ParamField>

            <ParamField body="product_description" type="string">
              账单和订单项的可选产品描述覆盖。如果未指定，则使用存储的产品描述。
            </ParamField>

            <ParamField body="adaptive_currency_fees_inclusive" type="boolean">
              是否应将适应性货币费用包括在产品价格中（true）或增加到产品价格之上（false）。如果未启用适应性定价，将被忽略。
            </ParamField>
          </Expandable>
        </ParamField>
      </Expandable>
    </ParamField>
  </Accordion>
</AccordionGroup>

## 使用示例

以下是展示不同业务场景下结账会话配置的10个综合示例：

### 1. 简单单产品结账

```javascript expandable theme={null}
const session = await client.checkoutSessions.create({
  product_cart: [
    {
      product_id: 'prod_ebook_guide',
      quantity: 1
    }
  ],
  customer: {
    email: 'customer@example.com',
    name: 'John Doe'
  },
  return_url: 'https://yoursite.com/success'
});
```

### 2. 多件商品购物车

```javascript expandable theme={null}
const session = await client.checkoutSessions.create({
  product_cart: [
    {
      product_id: 'prod_laptop',
      quantity: 1
    },
    {
      product_id: 'prod_mouse',
      quantity: 2
    },
    {
      product_id: 'prod_warranty',
      quantity: 1
    }
  ],
  customer: {
    email: 'customer@example.com',
    name: 'John Doe',
    phone_number: '+1234567890'
  },
  billing_address: {
    street: '123 Tech Street',
    city: 'San Francisco',
    state: 'CA',
    country: 'US',
    zipcode: '94102'
  },
  return_url: 'https://electronics-store.com/order-confirmation'
});
```

### 3. 带试用期的订阅

```javascript expandable theme={null}
const session = await client.checkoutSessions.create({
  product_cart: [
    {
      product_id: 'prod_monthly_plan',
      quantity: 1
    }
  ],
  subscription_data: {
    trial_period_days: 14
  },
  customer: {
    email: 'user@startup.com',
    name: 'Jane Smith'
  },
  return_url: 'https://saas-app.com/onboarding',
  metadata: {
    plan_type: 'professional',
    referral_source: 'google_ads'
  }
});
```

### 4. 预确认结账

<Note>
  当 `confirm` 设为 `true` 时，客户将被直接带到结账页面，跳过任何确认步骤。
</Note>

```javascript expandable theme={null}
const session = await client.checkoutSessions.create({
  product_cart: [
    {
      product_id: 'prod_premium_course',
      quantity: 1
    }
  ],
  customer: {
    email: 'student@university.edu',
    name: 'Alex Johnson',
    phone_number: '+1555123456'
  },
  billing_address: {
    street: '456 University Ave',
    city: 'Boston',
    state: 'MA',
    country: 'US',
    zipcode: '02134'
  },
  confirm: true,
  return_url: 'https://learning-platform.com/course-access',
  metadata: {
    course_category: 'programming',
    enrollment_date: '2024-01-15'
  }
});
```

### 5. 带货币覆盖的结账

<Note>
  `billing_currency` 覆盖仅在您的账户设置中启用适应性货币时生效。如果适应性货币被禁用，则此参数将无效。
</Note>

```javascript expandable theme={null}
const session = await client.checkoutSessions.create({
  product_cart: [
    {
      product_id: 'prod_consulting_service',
      quantity: 1
    }
  ],
  customer: {
    email: 'client@company.co.uk',
    name: 'Oliver Williams'
  },
  billing_address: {
    street: '789 Business Park',
    city: 'London',
    state: 'England',
    country: 'GB',
    zipcode: 'SW1A 1AA'
  },
  billing_currency: 'GBP',
  feature_flags: {
    allow_currency_selection: true,
    allow_tax_id: true
  },
  return_url: 'https://consulting-firm.com/service-confirmation'
});
```

### 6. 为回头客保存的付款方式

```javascript expandable theme={null}
const session = await client.checkoutSessions.create({
  product_cart: [
    {
      product_id: 'prod_monthly_subscription',
      quantity: 1
    }
  ],
  customer: {
    email: 'returning.customer@example.com',
    name: 'Robert Johnson',
    phone_number: '+1555987654'
  },
  show_saved_payment_methods: true,
  feature_flags: {
    allow_phone_number_collection: true,
    always_create_new_customer: false
  },
  return_url: 'https://subscription-service.com/welcome-back',
  metadata: {
    customer_tier: 'premium',
    account_age: 'returning'
  }
});
```

### 7. B2B 结账带税号收集

```javascript expandable theme={null}
const session = await client.checkoutSessions.create({
  product_cart: [
    {
      product_id: 'prod_enterprise_license',
      quantity: 5
    }
  ],
  customer: {
    email: 'procurement@enterprise.com',
    name: 'Sarah Davis',
    phone_number: '+1800555000'
  },
  billing_address: {
    street: '1000 Corporate Blvd',
    city: 'New York',
    state: 'NY',
    country: 'US',
    zipcode: '10001'
  },
  feature_flags: {
    allow_tax_id: true,
    allow_phone_number_collection: true,
    always_create_new_customer: false
  },
  return_url: 'https://enterprise-software.com/license-delivery',
  metadata: {
    customer_type: 'enterprise',
    contract_id: 'ENT-2024-001',
    sales_rep: 'john.sales@company.com'
  }
});
```

### 8. 带叠加折扣代码的暗色主题结账

```javascript expandable theme={null}
const session = await client.checkoutSessions.create({
  product_cart: [
    {
      product_id: 'prod_gaming_chair',
      quantity: 1
    }
  ],
  discount_codes: ['BLACKFRIDAY2024'],
  customization: {
    theme: 'dark',
    show_order_details: true,
    show_on_demand_tag: false
  },
  feature_flags: {
    allow_discount_code: true
  },
  customer: {
    email: 'gamer@example.com',
    name: 'Mike Chen'
  },
  return_url: 'https://gaming-store.com/order-complete'
});
```

### 9. 区域支付方法（适用于印度的 UPI）

有关 UPI 配置和测试的详细信息，请参阅 <a href="/features/payment-methods/india">印度支付方法</a> 页面。

```javascript expandable theme={null}
const session = await client.checkoutSessions.create({
  product_cart: [
    {
      product_id: 'prod_online_course_hindi',
      quantity: 1
    }
  ],
  allowed_payment_method_types: [
    'upi_collect',
    'credit',
    'debit'
  ],
  customer: {
    email: 'student@example.in',
    name: 'Priya Sharma',
    phone_number: '+919876543210'
  },
  billing_address: {
    street: 'MG Road',
    city: 'Bangalore',
    state: 'Karnataka',
    country: 'IN',
    zipcode: '560001'
  },
  billing_currency: 'INR',
  return_url: 'https://education-platform.in/course-access',
  metadata: {
    region: 'south_india',
    language: 'hindi'
  }
});
```

### 10. BNPL（先买后付）结账

有关 BNPL 配置和测试的详细信息，请参阅 <a href="/features/payment-methods/bnpl">先买后付（BNPL）</a> 页面。

```javascript expandable theme={null}
const session = await client.checkoutSessions.create({
  product_cart: [
    {
      product_id: 'prod_luxury_watch',
      quantity: 1
    }
  ],
  allowed_payment_method_types: [
    'klarna',
    'afterpay_clearpay',
    'credit',
    'debit'
  ],
  customer: {
    email: 'fashion.lover@example.com',
    name: 'Emma Thompson',
    phone_number: '+1234567890'
  },
  billing_address: {
    street: '555 Fashion Ave',
    city: 'Los Angeles',
    state: 'CA',
    country: 'US',
    zipcode: '90210'
  },
  feature_flags: {
    allow_phone_number_collection: true
  },
  return_url: 'https://luxury-store.com/purchase-confirmation',
  metadata: {
    product_category: 'luxury',
    price_range: 'high_value'
  }
});
```

### 11. 使用现有支付方式进行即时结账

使用客户的保存支付方式创建一个立即处理的结账会话，跳过支付方式收集：

```javascript expandable theme={null}
const session = await client.checkoutSessions.create({
  product_cart: [
    {
      product_id: 'prod_premium_plan',
      quantity: 1
    }
  ],
  customer: {
    customer_id: 'cus_123'  // Required when using payment_method_id
  },
  payment_method_id: 'pm_abc123',  // Use customer's saved payment method
  confirm: true,  // Required when using payment_method_id
  return_url: 'https://yourapp.com/success'
});
```

<Warning>
  当使用 `payment_method_id` 时，`confirm` 必须设为 `true`，且必须提供现有的 `customer_id`。支付方式将根据支付的货币进行合格性验证。
</Warning>

<Info>
  支付方式必须属于客户，并与支付货币兼容。这使得回头客可以进行单击购买。
</Info>

### 12. 简短链接用于更清晰的支付 URL

生成带有自定义后缀的简短、可分享的支付链接：

```javascript expandable theme={null}
const session = await client.checkoutSessions.create({
  product_cart: [
    {
      product_id: 'prod_monthly_subscription',
      quantity: 1
    }
  ],
  short_link: true,  // Generate a shortened payment link
  return_url: 'https://yourapp.com/success',
  customer: {
    email: 'customer@example.com',
    name: 'John Doe'
  }
});

// The checkout_url will be a shortened, cleaner link
console.log(session.checkout_url);  // e.g., https://checkout.dodopayments.com/buy/abc123
```

<Tip>
  简短链接非常适合 SMS、电子邮件或社交媒体分享。它们比长 URL 更容易记住，并且为客户建立更多信任。
</Tip>

### 13. 跳过付款成功页面并立即重定向

在支付完成后立即重定向客户，跳过默认成功页面：

```javascript expandable theme={null}
const session = await client.checkoutSessions.create({
  product_cart: [
    {
      product_id: 'prod_digital_product',
      quantity: 1
    }
  ],
  feature_flags: {
    redirect_immediately: true  // Skip success page, redirect immediately
  },
  return_url: 'https://yourapp.com/success',
  customer: {
    email: 'customer@example.com',
    name: 'Jane Smith'
  }
});
```

<Tip>
  当您有一个提供更好用户体验的自定义成功页面时，使用 `redirect_immediately: true`。这尤其适用于移动应用程序和嵌入式结账流程。
</Tip>

<Note>
  当启用 `redirect_immediately` 时，客户将在支付完成后立即重定向到您的 `return_url`，完全跳过默认成功页面。
</Note>

### 14. 强制语言

强制结账页面显示特定语言，覆盖客户的浏览器语言检测：

```javascript expandable theme={null}
const session = await client.checkoutSessions.create({
  product_cart: [
    {
      product_id: 'prod_subscription',
      quantity: 1
    }
  ],
  customization: {
    force_language: 'ja'  // Force Japanese language
  },
  customer: {
    email: 'customer@example.jp',
    name: 'Tanaka Yuki'
  },
  return_url: 'https://yourapp.com/success'
});
```

<Tip>
  当您知道客户的首选语言（例如，从他们的账户设置中）或面向特定区域市场时，使用 `force_language`。
</Tip>

**支持的语言：** 阿拉伯语 (`ar`), 加泰罗尼亚语 (`ca`), 中文 (`zh`), 荷兰语 (`nl`), 英语 (`en`), 法语 (`fr`), 德语 (`de`), 希伯来语 (`he`), 印度尼西亚语 (`id`), 意大利语 (`it`), 日语 (`ja`), 韩语 (`ko`), 马来语 (`ms`), 波兰语 (`pl`), 葡萄牙语 (`pt`), 罗马尼亚语 (`ro`), 俄语 (`ru`), 西班牙语 (`es`), 瑞典语 (`sv`), 泰语 (`th`), 土耳其语 (`tr`)

### 15. 收集自定义字段

在结账时使用自定义字段收集来自客户的额外信息：

```javascript expandable theme={null}
const session = await client.checkoutSessions.create({
  product_cart: [
    {
      product_id: 'prod_saas_plan',
      quantity: 1
    }
  ],
  custom_fields: [
    {
      key: 'company_name',
      label: 'Company Name',
      field_type: 'text',
      required: true,
      placeholder: 'Acme Inc.'
    },
    {
      key: 'team_size',
      label: 'Team Size',
      field_type: 'dropdown',
      required: true,
      options: ['1-10', '11-50', '51-200', '201-500', '500+']
    },
    {
      key: 'referral_source',
      label: 'How did you hear about us?',
      field_type: 'dropdown',
      required: false,
      options: ['Google', 'Twitter', 'Friend referral', 'Blog post', 'Other']
    },
    {
      key: 'website',
      label: 'Company Website',
      field_type: 'url',
      required: false,
      placeholder: 'https://example.com'
    }
  ],
  customer: {
    email: 'buyer@company.com',
    name: 'Jane Doe'
  },
  return_url: 'https://yourapp.com/success'
});
```

<Info>
  自定义字段响应会自动包含在 webhook 负载（`payment.succeeded`, `subscription.active`，等）中，并可通过 API 获取。使用它们来丰富您的 CRM，触发上手流程，或自定义客户体验。
</Info>

**可用字段类型：** `text`, `number`, `email`, `url`, `date`, `dropdown`, `boolean`

## 预览结账会话

在创建结账会话之前，您可以预览包括税费、折扣和总计在内的定价明细。这对于在客户进行结账之前显示准确的定价是有用的。

<Tabs>
  <Tab title="Node.js SDK">
    ```javascript theme={null}
    const preview = await client.checkoutSessions.preview({
      product_cart: [
        { product_id: 'prod_123', quantity: 1 }
      ],
      billing_address: {
        country: 'US',
        state: 'CA',
        zipcode: '94102'
      },
      discount_codes: ['SAVE20']
    });

    console.log('Subtotal:', preview.subtotal);
    console.log('Tax:', preview.tax);
    console.log('Discount:', preview.discount);
    console.log('Total:', preview.total);
    ```
  </Tab>

  <Tab title="Python SDK">
    ```python theme={null}
    preview = client.checkout_sessions.preview(
        product_cart=[
            {"product_id": "prod_123", "quantity": 1}
        ],
        billing_address={
            "country": "US",
            "state": "CA",
            "zipcode": "94102"
        },
        discount_codes=["SAVE20"]
    )

    print(f"Subtotal: {preview.subtotal}")
    print(f"Tax: {preview.tax}")
    print(f"Discount: {preview.discount}")
    print(f"Total: {preview.total}")
    ```
  </Tab>
</Tabs>

<Card title="Preview API Reference" icon="code" href="/api-reference/checkout-sessions/preview">
  查看完整的预览端点文档。
</Card>

## 从动态链接迁移到结账会话

### 关键区别

以前，在使用动态链接创建支付链接时，您需要提供客户的完整账单地址。

使用结账会话，这已不再必要。您可以直接传递您拥有的任何信息，其余的我们会处理。例如：

* 如果您只知道客户的账单国家，只需提供该信息即可。
* 结账流程将自动收集缺失的详细信息，然后才将客户移动到付款页面。
* 另一方面，如果您已经拥有所有必需信息，并希望直接跳到付款页面，可以传递完整的数据集并在请求正文中包含 `confirm=true`。

### 迁移过程

从动态链接迁移到结账会话很简单：

<Steps>
  <Step title="Update your integration">
    更新您的集成以使用新的 API 或 SDK 方法。
  </Step>

  <Step title="Adjust request payload">
    根据 Checkout Sessions 格式调整请求负载。
  </Step>

  <Step title="That's it!">
    是的。您的端不需要任何额外处理或特殊迁移步骤。
  </Step>
</Steps>

## 相关 API 参考

<CardGroup cols={2}>
  <Card title="Create Checkout Session" icon="code" href="/api-reference/checkout-sessions/create">
    创建结账会话的完整 API 参考，包含所有可用参数和选项
  </Card>

  <Card title="Preview Checkout Session" icon="eye" href="/api-reference/checkout-sessions/preview">
    在创建会议之前预览定价、税收和总计的 API 参考
  </Card>
</CardGroup>
