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

# 动态定价结账与随意支付

> 使用单一产品创建具有可变定价的灵活结账链接。启用随意支付，让客户选择他们的价格或以编程方式设置动态金额。

**动态定价**允许您为产品提供可变定价，而无需创建多个产品条目。通过在单一产品上启用**随意支付 (PWYW)**，您可以设置最低和最高价格范围，然后在创建结账会话链接时传递动态金额。

这种方法非常适合您需要的情况：

* **可变定价**，无需管理多个产品
* **客户驱动定价**，让买家选择他们的金额
* **编程价格控制**，通过 API 动态设置金额
* **灵活的定价模型**，适用于数字产品、捐赠或实验性发布

<Warning>
  Pay What You Want 仅适用于**Single Payment**（一次性）产品，不能用于订阅产品。
</Warning>

## 工作原理

启用随意支付后，您可以：

1. **设置价格范围**：定义最低价格（必填），可选地设置最高价格
2. **传递动态金额**：在创建结账会话时，在产品购物车中包含 `amount` 字段
3. **让客户选择**：如果未提供金额，客户可以输入自己的价格（在您的范围内）

<Info>
  当您在产品购物车中传递 `amount` 时，该金额将用于结账。如果省略 `amount` 字段，客户可以在结账时自行选择价格（受最低/最高设置限制）。
</Info>

## 第一步：创建一个随意支付的产品

首先，在您的 Dodo Payments 仪表板中创建一个一次性产品，并启用随意支付定价。

<Steps>
  <Step title="Create a new product">
    在 Dodo Payments 仪表板中导航到 **Products** 并点击 **Add Product**。
  </Step>

  <Step title="Configure product details">
    填写所需的产品信息：

    * **Product Name**：产品的显示名称
    * **Product Description**：清楚描述客户所购买的内容
    * **Product Image**：上传图片（PNG/JPG/WebP，最多 3 MB）
    * **Tax Category**：选择适当的税务类别
  </Step>

  <Step title="Set pricing type">
    将 **Pricing Type** 选择为 **Single Payment**（一次性付款）。
  </Step>

  <Step title="Enable Pay What You Want">
    在 **Pricing** 部分启用 **Pay What You Want** 切换按钮。
  </Step>

  <Step title="Set minimum price">
    输入客户必须支付的**最低价格**。这是必填项，可确保您保持收入底线。

    **示例**：如果最低价格为 \$5.00，请输入 `5.00`（或 `500` 美分）。
  </Step>

  <Step title="Set maximum price (optional)">
    可选地设置**最高价格**，以限制客户支付的金额。
  </Step>

  <Step title="Set suggested price (optional)">
    可选地输入**建议价格**，以向客户展示，引导期望并可能提高平均订单价值。
  </Step>

  <Step title="Save the product">
    点击 **Add Product** 以保存。记下您的产品 ID（例如 `pdt_123abc456def`），以在结账会话中使用。
  </Step>
</Steps>

<Tip>
  您可以在仪表板的 **Products** → **View Details** 中找到产品 ID，或使用 [List Products API](/api-reference/products/get-products)。
</Tip>

## 第二步：创建具有动态定价的结账会话

一旦您的产品配置了 Pay What You Want，即可创建带动态金额的结账会话。产品购物车中的 `amount` 字段允许您为每个结账会话以编程方式设置价格。

### 理解金额字段

在创建结账会话时，您可以在每个产品购物车项中包含 `amount` 字段：

* **如果提供了 `amount`**：结账将使用该精确金额（必须在您的最低/最高范围内）
* **如果省略 `amount`**：客户可以在结账时输入自己的价格（在您的范围内）

<Warning>
  `amount` 字段仅适用于 Pay What You Want 产品。对于常规产品，该字段会被忽略。
</Warning>

### 代码示例

<CodeGroup>
  ```typescript TypeScript theme={null}
  import DodoPayments from 'dodopayments';

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

  async function createDynamicPricingCheckout(
    productId: string,
    amountInCents: number,
    returnUrl: string
  ) {
    try {
      const session = await client.checkoutSessions.create({
        product_cart: [
          {
            product_id: productId,
            quantity: 1,
            // Dynamic amount in cents (e.g., 1500 = $15.00)
            amount: amountInCents
          }
        ],
        return_url: returnUrl,
        // Optional: Pre-fill customer information
        customer: {
          email: 'customer@example.com',
          name: 'John Doe'
        },
        // Optional: Add metadata for tracking
        metadata: {
          order_id: 'order_123',
          pricing_tier: 'custom'
        }
      });

      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: Create checkout with $25.00 (2500 cents)
  const session = await createDynamicPricingCheckout(
    'prod_123abc456def',
    2500, // $25.00 in cents
    'https://yoursite.com/checkout/success'
  );

  // Example: Create checkout with $10.00 (1000 cents)
  const session2 = await createDynamicPricingCheckout(
    'prod_123abc456def',
    1000, // $10.00 in cents
    'https://yoursite.com/checkout/success'
  );
  ```

  ```python Python theme={null}
  import os
  from dodopayments import DodoPayments

  # Initialize the Dodo Payments client
  client = DodoPayments(
      bearer_token=os.environ.get("DODO_PAYMENTS_API_KEY"),
  )

  def create_dynamic_pricing_checkout(
      product_id: str,
      amount_in_cents: int,
      return_url: str
  ):
      """
      Create a checkout session with dynamic pricing.
      
      Args:
          product_id: The product ID with Pay What You Want enabled
          amount_in_cents: The amount in cents (e.g., 2500 for $25.00)
          return_url: URL to redirect after payment completion
      
      Returns:
          Session object with checkout_url and session_id
      """
      try:
          session = client.checkout_sessions.create(
              product_cart=[
                  {
                      "product_id": product_id,
                      "quantity": 1,
                      # Dynamic amount in cents (e.g., 1500 = $15.00)
                      "amount": amount_in_cents
                  }
              ],
              return_url=return_url,
              # Optional: Pre-fill customer information
              customer={
                  "email": "customer@example.com",
                  "name": "John Doe"
              },
              # Optional: Add metadata for tracking
              metadata={
                  "order_id": "order_123",
                  "pricing_tier": "custom"
              }
          )
          
          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: Create checkout with $25.00 (2500 cents)
  session = create_dynamic_pricing_checkout(
      "prod_123abc456def",
      2500,  # $25.00 in cents
      "https://yoursite.com/checkout/success"
  )

  # Example: Create checkout with $10.00 (1000 cents)
  session2 = create_dynamic_pricing_checkout(
      "prod_123abc456def",
      1000,  # $10.00 in cents
      "https://yoursite.com/checkout/success"
  )
  ```
</CodeGroup>

<Note>
  **金额格式**：`amount` 字段必须使用该货币的最小单位。对于 USD，这意味着美分（例如 \$25.00 = `2500`）。对于其他货币，则使用最小计量单位（例如 INR 的 paise）。
</Note>

## 第三步：让客户选择他们的价格

如果您希望客户在结账时自行选择价格，只需在产品购物车中省略 `amount` 字段。结账页面会显示一个输入框，让客户输入任何在您最低和最高范围之间的金额。

<CodeGroup>
  ```typescript TypeScript theme={null}
  async function createCustomerChoiceCheckout(
    productId: string,
    returnUrl: string
  ) {
    try {
      const session = await client.checkoutSessions.create({
        product_cart: [
          {
            product_id: productId,
            quantity: 1
            // No amount field - customer will choose their price
          }
        ],
        return_url: returnUrl,
        customer: {
          email: 'customer@example.com',
          name: 'John Doe'
        }
      });

      return session;
    } catch (error) {
      console.error('Failed to create checkout session:', error);
      throw error;
    }
  }
  ```

  ```python Python theme={null}
  def create_customer_choice_checkout(
      product_id: str,
      return_url: str
  ):
      """
      Create a checkout session where customers choose their own price.
      """
      try:
          session = client.checkout_sessions.create(
              product_cart=[
                  {
                      "product_id": product_id,
                      "quantity": 1
                      # No amount field - customer will choose their price
                  }
              ],
              return_url=return_url,
              customer={
                  "email": "customer@example.com",
                  "name": "John Doe"
              }
          )
          
          return session
      except Exception as error:
          print(f"Failed to create checkout session: {error}")
          raise error
  ```
</CodeGroup>

## 常见用例

### 用例 1：基于用户类型的分层定价

为不同客户群体提供不同价格，使用相同的产品：

```typescript theme={null}
// Student discount: $10.00
const studentSession = await createDynamicPricingCheckout(
  'prod_123abc456def',
  1000, // $10.00
  'https://yoursite.com/success'
);

// Regular price: $25.00
const regularSession = await createDynamicPricingCheckout(
  'prod_123abc456def',
  2500, // $25.00
  'https://yoursite.com/success'
);

// Premium price: $50.00
const premiumSession = await createDynamicPricingCheckout(
  'prod_123abc456def',
  5000, // $50.00
  'https://yoursite.com/success'
);
```

### 用例 2：基于数量的动态定价

根据购买数量调整价格：

```typescript theme={null}
async function createQuantityBasedCheckout(
  productId: string,
  quantity: number
) {
  // Base price: $20.00 per unit
  // Discount: 10% for 2+ items, 20% for 5+ items
  const basePrice = 2000; // $20.00 in cents
  let discount = 0;
  
  if (quantity >= 5) {
    discount = 0.20; // 20% off
  } else if (quantity >= 2) {
    discount = 0.10; // 10% off
  }
  
  const totalAmount = Math.round(basePrice * quantity * (1 - discount));
  
  const session = await client.checkoutSessions.create({
    product_cart: [
      {
        product_id: productId,
        quantity: quantity,
        amount: totalAmount
      }
    ],
    return_url: 'https://yoursite.com/success'
  });
  
  return session;
}
```

### 用例 3：基于时间或促销的定价

在特定时期内应用促销定价：

```typescript theme={null}
async function createPromotionalCheckout(productId: string) {
  const isPromoActive = checkIfPromotionActive(); // Your logic
  const regularPrice = 3000; // $30.00
  const promoPrice = 2000; // $20.00
  
  const amount = isPromoActive ? promoPrice : regularPrice;
  
  const session = await client.checkoutSessions.create({
    product_cart: [
      {
        product_id: productId,
        quantity: 1,
        amount: amount
      }
    ],
    return_url: 'https://yoursite.com/success',
    metadata: {
      pricing_type: isPromoActive ? 'promotional' : 'regular'
    }
  });
  
  return session;
}
```

## 最佳实践

<CardGroup cols={2}>
  <Card title="Set Reasonable Bounds" icon="sliders">
    选择一个既能覆盖成本又让客户可接受的最低价格。使用建议价格来引导客户期望。
  </Card>

  <Card title="Validate Amounts" icon="shield-check">
    在创建结账会话前，请始终验证动态金额是否在产品的最低和最高范围内。
  </Card>

  <Card title="Track Pricing Decisions" icon="chart-line">
    使用 metadata 跟踪选择特定金额的原因（例如 `pricing_tier`、`discount_code`、`user_segment`）。
  </Card>

  <Card title="Handle Edge Cases" icon="exclamation-triangle">
    确保您的应用能优雅地处理金额超出最高或低于最低的情况。
  </Card>
</CardGroup>

## 验证和错误处理

始终根据您产品的最低和最高设置验证金额：

<CodeGroup>
  ```typescript TypeScript theme={null}
  async function createValidatedCheckout(
    productId: string,
    amountInCents: number,
    minAmount: number,
    maxAmount: number | null
  ) {
    // Validate minimum
    if (amountInCents < minAmount) {
      throw new Error(
        `Amount ${amountInCents} is below minimum ${minAmount}`
      );
    }
    
    // Validate maximum (if set)
    if (maxAmount !== null && amountInCents > maxAmount) {
      throw new Error(
        `Amount ${amountInCents} exceeds maximum ${maxAmount}`
      );
    }
    
    // Create checkout session
    return await client.checkoutSessions.create({
      product_cart: [
        {
          product_id: productId,
          quantity: 1,
          amount: amountInCents
        }
      ],
      return_url: 'https://yoursite.com/success'
    });
  }
  ```

  ```python Python theme={null}
  def create_validated_checkout(
      product_id: str,
      amount_in_cents: int,
      min_amount: int,
      max_amount: int | None
  ):
      """
      Create a checkout session with amount validation.
      """
      # Validate minimum
      if amount_in_cents < min_amount:
          raise ValueError(
              f"Amount {amount_in_cents} is below minimum {min_amount}"
          )
      
      # Validate maximum (if set)
      if max_amount is not None and amount_in_cents > max_amount:
          raise ValueError(
              f"Amount {amount_in_cents} exceeds maximum {max_amount}"
          )
      
      # Create checkout session
      return client.checkout_sessions.create(
          product_cart=[
              {
                  "product_id": product_id,
                  "quantity": 1,
                  "amount": amount_in_cents
              }
          ],
          return_url="https://yoursite.com/success"
      )
  ```
</CodeGroup>

## API 参考

<CardGroup cols={2}>
  <Card title="Pay What You Want Feature" icon="dollar-sign" href="/features/pay-what-you-want">
    了解有关 Pay What You Want 定价模型及其功能的更多信息。
  </Card>

  <Card title="Checkout Sessions Guide" icon="cart-shopping" href="/developer-resources/checkout-session">
    探索更高级的结账会话功能和自定义选项。
  </Card>
</CardGroup>

## 故障排除

<AccordionGroup>
  <Accordion title="Amount is being ignored">
    如果 `amount` 字段被忽略，请确认：

    * 该产品在仪表板中已启用 **Pay What You Want**
    * 该产品是**Single Payment**（一次性）产品，而非订阅
    * 金额格式正确（使用货币的最小单位，例如 USD 的美分）
  </Accordion>

  <Accordion title="Amount exceeds maximum or is below minimum">
    如果金额违反产品的价格范围，API 会拒绝结账会话。在创建会话前务必验证金额，或通过省略 `amount` 字段，让客户自行选择价格。
  </Accordion>

  <Accordion title="Customer can't enter their own price">
    如果客户无法看到价格输入字段，请确保在产品购物车中省略了 `amount` 字段。当提供该字段时，结账会使用该精确金额。
  </Accordion>
</AccordionGroup>
