动态定价允许您为产品提供可变定价,而无需创建多个产品条目。通过在单一产品上启用随意支付 (PWYW),您可以设置最低和最高价格范围,然后在创建结账会话链接时传递动态金额。
这种方法非常适合您需要的情况:
- 可变定价,无需管理多个产品
- 客户驱动定价,让买家选择他们的金额
- 编程价格控制,通过 API 动态设置金额
- 灵活的定价模型,适用于数字产品、捐赠或实验性发布
Pay What You Want 仅适用于Single Payment(一次性)产品,不能用于订阅产品。
工作原理
启用随意支付后,您可以:
- 设置价格范围:定义最低价格(必填),可选地设置最高价格
- 传递动态金额:在创建结账会话时,在产品购物车中包含
amount 字段
- 让客户选择:如果未提供金额,客户可以输入自己的价格(在您的范围内)
当您在产品购物车中传递 amount 时,该金额将用于结账。如果省略 amount 字段,客户可以在结账时自行选择价格(受最低/最高设置限制)。
第一步:创建一个随意支付的产品
首先,在您的 Dodo Payments 仪表板中创建一个一次性产品,并启用随意支付定价。
Create a new product
在 Dodo Payments 仪表板中导航到 Products 并点击 Add Product。
Configure product details
填写所需的产品信息:
- Product Name:产品的显示名称
- Product Description:清楚描述客户所购买的内容
- Product Image:上传图片(PNG/JPG/WebP,最多 3 MB)
- Tax Category:选择适当的税务类别
Set pricing type
将 Pricing Type 选择为 Single Payment(一次性付款)。
Enable Pay What You Want
在 Pricing 部分启用 Pay What You Want 切换按钮。
Set minimum price
输入客户必须支付的最低价格。这是必填项,可确保您保持收入底线。示例:如果最低价格为 $5.00,请输入 5.00(或 500 美分)。
Set maximum price (optional)
可选地设置最高价格,以限制客户支付的金额。
Set suggested price (optional)
可选地输入建议价格,以向客户展示,引导期望并可能提高平均订单价值。
Save the product
点击 Add Product 以保存。记下您的产品 ID(例如 pdt_123abc456def),以在结账会话中使用。
第二步:创建具有动态定价的结账会话
一旦您的产品配置了 Pay What You Want,即可创建带动态金额的结账会话。产品购物车中的 amount 字段允许您为每个结账会话以编程方式设置价格。
理解金额字段
在创建结账会话时,您可以在每个产品购物车项中包含 amount 字段:
- 如果提供了
amount:结账将使用该精确金额(必须在您的最低/最高范围内)
- 如果省略
amount:客户可以在结账时输入自己的价格(在您的范围内)
amount 字段仅适用于 Pay What You Want 产品。对于常规产品,该字段会被忽略。
代码示例
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'
);
金额格式:amount 字段必须使用该货币的最小单位。对于 USD,这意味着美分(例如 $25.00 = 2500)。对于其他货币,则使用最小计量单位(例如 INR 的 paise)。
第三步:让客户选择他们的价格
如果您希望客户在结账时自行选择价格,只需在产品购物车中省略 amount 字段。结账页面会显示一个输入框,让客户输入任何在您最低和最高范围之间的金额。
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;
}
}
常见用例
用例 1:基于用户类型的分层定价
为不同客户群体提供不同价格,使用相同的产品:
// 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:基于数量的动态定价
根据购买数量调整价格:
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:基于时间或促销的定价
在特定时期内应用促销定价:
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;
}
最佳实践
Set Reasonable Bounds
选择一个既能覆盖成本又让客户可接受的最低价格。使用建议价格来引导客户期望。
Validate Amounts
在创建结账会话前,请始终验证动态金额是否在产品的最低和最高范围内。
Track Pricing Decisions
使用 metadata 跟踪选择特定金额的原因(例如 pricing_tier、discount_code、user_segment)。
Handle Edge Cases
确保您的应用能优雅地处理金额超出最高或低于最低的情况。
验证和错误处理
始终根据您产品的最低和最高设置验证金额:
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'
});
}
API 参考
故障排除
如果 amount 字段被忽略,请确认:
- 该产品在仪表板中已启用 Pay What You Want
- 该产品是Single Payment(一次性)产品,而非订阅
- 金额格式正确(使用货币的最小单位,例如 USD 的美分)
Amount exceeds maximum or is below minimum
如果金额违反产品的价格范围,API 会拒绝结账会话。在创建会话前务必验证金额,或通过省略 amount 字段,让客户自行选择价格。
Customer can't enter their own price
如果客户无法看到价格输入字段,请确保在产品购物车中省略了 amount 字段。当提供该字段时,结账会使用该精确金额。