定价是你做的最不被重视但影响最大的决策。想想:
基础功能免费,高级功能付费。适合用户基数大、获客成本高的市场。
免费边界怎么划:限功能(Notion 限制协作人数)、限用量(PostHog 限事件数)、限时间(7 天试用)、限导出(Figma 限制导出格式)。
按功能层级或座位数收费。最常见的 SaaS 定价模式。
# 典型三层定价
Starter: $19/月 · 5 用户 · 基础功能
Pro: $49/月 · 25 用户 · 高级功能 + API
Enterprise: $199/月 · 无限用户 · SSO + 优先支持
# 座位制(Per Seat)
$10/用户/月 — Slack、Linear、Notion 模式
# 随团队增长自动增收
定价锚点技巧:你真正想卖的是中间档。用高价位第三档做锚点,让中间档看起来"合理"。
按实际使用量收费。适合 API/基础设施类产品。
# 典型按量计费
AWS S3: $0.023/GB/月 存储
OpenAI API: 按 token 计费
PostHog: 按事件数计费
Resend: 按邮件数计费
# 混合模式:底费 + 超量
Base: $29/月含 10,000 次调用
超过部分: $0.002/次
传统软件模式:一次性购买 + 可选年度维护/更新费。适合桌面工具、WordPress 插件等。
当前趋势:SaaS 化。除了一些特殊场景(如自托管要求),按月/年订阅已经成为主流。
| 产品类型 | 推荐模型 | 原因 | 代表产品 |
|---|---|---|---|
| 协作工具 | 座位制 | 随团队扩张增收 | Slack, Linear, Notion |
| API/基础设施 | 按量计费 | 用量直接反映价值 | Stripe, OpenAI, AWS |
| 效率工具 | 分层订阅 | 个人 vs 团队需求差异大 | Figma, Canva |
| 开发者工具 | 免费 + 按量 | 开发者爱免费,企业愿付费 | PostHog, Vercel, Supabase |
| 内容/知识 | 订阅制 | 持续内容 = 持续价值 | Substack, Patreon |
| 桌面/插件 | 买断 + 年费 | 用户习惯一次性付款 | Tailwind UI, WP 插件 |
选择支付平台是 SaaS 基础设施的关键决策。核心区别:你持有商户账户 vs 平台是商户。
| 维度 | Stripe | LemonSqueezy | Paddle |
|---|---|---|---|
| 角色 | 支付处理商 | MoR(代收代付商) | MoR(代收代付商) |
| 手续费 | 2.9% + $0.30(美国) 3.4% + $0.50(亚太) |
5% + $0.50 | 5% + $0.50 |
| Billing 附加费 | 0.7% Billing volume | 含在手续费中 | 含在手续费中 |
| 税务合规 | 需自行处理(Stripe Tax 额外 0.5%) | ✅ 全包(MoR 代缴) | ✅ 全包(MoR 代缴) |
| 到账货币 | 你的银行账户货币 | USD(可提现到多币种) | USD/EUR/GBP |
| 自定义程度 | ⭐⭐⭐⭐⭐ 完全自定义 | ⭐⭐⭐ 中等 | ⭐⭐⭐ 中等 |
| 结账体验 | 自定义或 Stripe Checkout | 嵌入式结账/链接 | Paddle Checkout |
| 许可证密钥 | 需自建或第三方 | ✅ 内置 | 需自建 |
| 数字商品 | 支持但需配置 | ✅ 原生支持 | ✅ 支持 |
| 适合场景 | 需要完全控制、大体量 | 独立开发者、数字商品 | 全球化 SaaS、不想管税务 |
数据来源:Stripe Pricing (2026-05)、LemonSqueezy Pricing (2026-05)、Paddle Pricing (2026-05)。Stripe 亚太区费率来自 Stripe 新加坡定价页。
Product = 你的产品/服务
Price = 定价方案(可以有多个)
// 创建产品和价格
const product = await stripe.products.create({
name: 'Pro Plan',
});
const price = await stripe.prices.create({
product: product.id,
unit_amount: 4900, // $49.00 (cents)
currency: 'usd',
recurring: {
interval: 'month',
},
});
订阅 = 客户对某个价格的持续付费
// 创建订阅
const subscription = await stripe.subscriptions.create({
customer: customer.id,
items: [{
price: price.id,
quantity: 1,
}],
trial_period_days: 14,
payment_behavior: 'default_incomplete',
expand: ['latest_invoice.payment_intent'],
});
// 后端:创建 Checkout Session
app.post('/api/create-checkout', async (req, res) => {
const session = await stripe.checkout.sessions.create({
mode: 'subscription',
payment_method_types: ['card'],
line_items: [{
price: 'price_1Abc...', // 你的 Price ID
quantity: 1,
}],
success_url: 'https://yourapp.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url: 'https://yourapp.com/pricing',
customer_email: req.user.email,
metadata: {
userId: req.user.id,
},
});
res.json({ url: session.url });
});
// 前端:跳转到 Stripe Checkout
const response = await fetch('/api/create-checkout', { method: 'POST' });
const { url } = await response.json();
window.location.href = url;
// Stripe Webhook — 必须处理的关键事件
app.post('/api/webhooks/stripe', express.raw({ type: 'application/json' }),
async (req, res) => {
const sig = req.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(
req.body, sig, process.env.STRIPE_WEBHOOK_SECRET
);
} catch (err) {
return res.status(400).send(`Webhook Error: ${err.message}`);
}
switch (event.type) {
case 'checkout.session.completed':
// 新订阅创建成功
const session = event.data.object;
await db.users.update(session.metadata.userId, {
plan: 'pro',
stripeCustomerId: session.customer,
stripeSubscriptionId: session.subscription,
});
break;
case 'customer.subscription.updated':
// 订阅变更(升降级)
const subscription = event.data.object;
await handleSubscriptionChange(subscription);
break;
case 'customer.subscription.deleted':
// 订阅取消
const deletedSub = event.data.object;
await db.users.updateByStripeSub(deletedSub.id, {
plan: 'free',
});
break;
case 'invoice.payment_failed':
// 支付失败 — 触发催收流程
const invoice = event.data.object;
await dunningService.handleFailedPayment(invoice);
break;
default:
console.log(`Unhandled event type: ${event.type}`);
}
res.json({ received: true });
}
);
// 创建计量价格
const meteredPrice = await stripe.prices.create({
product: product.id,
currency: 'usd',
recurring: {
interval: 'month',
usage_type: 'metered', // 按量计费
},
billing_scheme: 'per_unit',
unit_amount: 2, // $0.002/次
});
// 上报使用量
await stripe.subscriptionItems.createUsageRecord(
subscriptionItem.id,
{
quantity: 1500, // 本次用量
timestamp: Math.floor(Date.now() / 1000),
}
);
LemonSqueezy 是专门为数字产品/SaaS 设计的 MoR 平台,由独立开发者打造,2023 年被 Stripe 收购但仍独立运营。
作为 MoR,自动处理全球 200+ 国家的 VAT/GST/销售税。你不用注册任何国家的税务号。
内置 License Key 管理——自动生成、激活、停用。卖软件/插件的开发者必备。
安全签名的下载链接、限速、防盗链。卖电子书/模板/软件包直接用。
// LemonSqueezy Webhook
app.post('/webhooks/lemonsqueezy', async (req, res) => {
const signature = req.headers['x-signature'];
// 验证签名
const isValid = verifySignature(req.body, signature, LS_WEBHOOK_SECRET);
if (!isValid) return res.status(401).send('Invalid signature');
const { meta, data } = req.body;
switch (meta.event_name) {
case 'subscription_created':
await db.users.update(data.attributes.user_email, {
plan: 'pro',
lsSubscriptionId: data.id,
});
break;
case 'subscription_cancelled':
await db.users.updateByLsSub(data.id, { plan: 'free' });
break;
case 'license_key_created':
// 自动发许可证邮件
await sendLicenseEmail(data.attributes);
break;
}
res.status(200).send('OK');
});
| 项目 | Stripe | LemonSqueezy |
|---|---|---|
| 支付手续费 | $290 + $30 = $320 (3.4%+$0.50, 假设100笔) | $500 + $50 = $550 (5%+$0.50) |
| Billing 费 | $70 (0.7% volume) | 包含 |
| 税务处理 | 自处理 or Stripe Tax $50 (0.5%) | 包含 |
| 总费用 | $390-$440 | $550 |
| 到账 | $9,560-$9,610 | $9,450 |
计算基于:月收入 $10,000,100 笔交易,亚太区 Stripe 费率。2026-05 数据。
-- 订阅计费核心表
CREATE TABLE users (
id UUID PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
plan TEXT NOT NULL DEFAULT 'free', -- free/pro/enterprise
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE subscriptions (
id UUID PRIMARY KEY,
user_id UUID REFERENCES users(id),
provider TEXT NOT NULL, -- stripe / lemonsqueezy / paddle
provider_id TEXT NOT NULL, -- 对应平台的 subscription ID
status TEXT NOT NULL, -- active/past_due/canceled/trialing
plan_id TEXT NOT NULL,
current_period_start TIMESTAMPTZ,
current_period_end TIMESTAMPTZ,
cancel_at_period_end BOOLEAN DEFAULT FALSE,
trial_end TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE invoices (
id UUID PRIMARY KEY,
user_id UUID REFERENCES users(id),
subscription_id UUID REFERENCES subscriptions(id),
provider TEXT NOT NULL,
provider_id TEXT NOT NULL,
amount_cents INTEGER NOT NULL,
currency TEXT NOT NULL DEFAULT 'usd',
status TEXT NOT NULL, -- paid/open/void/uncollectible
period_start TIMESTAMPTZ,
period_end TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- 按量计费:使用量记录
CREATE TABLE usage_records (
id UUID PRIMARY KEY,
user_id UUID REFERENCES users(id),
metric_type TEXT NOT NULL, -- api_calls/storage/events
quantity INTEGER NOT NULL,
recorded_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_usage_user_metric_date ON usage_records (user_id, metric_type, recorded_at);
// Next.js 中间件示例
const PLANS = {
free: {
maxProjects: 3,
maxMembers: 1,
apiCallsPerDay: 100,
customDomains: false,
export: false,
},
pro: {
maxProjects: 50,
maxMembers: 25,
apiCallsPerDay: 10000,
customDomains: true,
export: true,
},
enterprise: {
maxProjects: Infinity,
maxMembers: Infinity,
apiCallsPerDay: Infinity,
customDomains: true,
export: true,
},
};
function checkFeature(plan, feature) {
const limits = PLANS[plan];
if (!limits) return false;
return limits[feature] === true || limits[feature] > 0;
}
function checkLimit(plan, feature, current) {
const limit = PLANS[plan][feature];
if (limit === Infinity) return true;
return current < limit;
}
// 使用
app.get('/api/projects', requireAuth, async (req, res) => {
const projectCount = await db.projects.countByUser(req.user.id);
if (!checkLimit(req.user.plan, 'maxProjects', projectCount)) {
return res.status(403).json({
error: 'Project limit reached',
upgradeUrl: '/pricing',
limit: PLANS[req.user.plan].maxProjects,
});
}
// ...
});
// Stripe 订阅升级
async function upgradeSubscription(userId, newPlanId) {
const sub = await db.subscriptions.findByUser(userId);
const updated = await stripe.subscriptions.update(
sub.providerId,
{
items: [{
id: sub.stripeItemId,
price: newPlanId,
}],
proration_behavior: 'create_prorations', // 按比例计费
// 'none' = 下个周期生效(更友好)
}
);
await db.subscriptions.update(sub.id, {
planId: newPlanId,
status: updated.status,
});
}
// Stripe 订阅降级(下周期生效)
async function downgradeSubscription(userId, newPlanId) {
const sub = await db.subscriptions.findByUser(userId);
await stripe.subscriptions.update(
sub.providerId,
{
items: [{
id: sub.stripeItemId,
price: newPlanId,
}],
proration_behavior: 'none', // 下个周期生效,不退款
cancel_at_period_end: false,
}
);
// 标记下周期变更
await db.subscriptions.update(sub.id, {
pendingPlanId: newPlanId,
pendingChangeAt: sub.currentPeriodEnd,
});
}
定价页是转化率最高的页面之一。设计得好坏直接影响收入。
| 技巧 | 说明 | 示例 |
|---|---|---|
| 锚定效应 | 先展示高价档,让中档看起来合理 | Enterprise $199 → Pro $49 "看起来划算" |
| 诱饵效应 | 加一个"不值得"的选项引导选择 | Starter $19(功能少)vs Pro $49(功能多得多) |
| 尾数定价 | $49 比 $50 感觉便宜很多 | $9, $19, $49, $99 |
| 年付折扣 | 月付 vs 年付对比,年付标"省 X%" | $49/月 vs $399/年(省 $189) |
| 社交证明 | 显示"最受欢迎"标签 | Pro 档加 ⭐ "Most Popular" |
| 损失厌恶 | 不升级会失去什么,而非升级得到什么 | "没有高级分析你将错失..." |
定价不是一次性决策——持续实验和调整。
注意:直接 A/B 测试价格有公平性争议(同产品不同价)。更好的方法:
不同国家购买力不同。$49/月在旧金山是午餐钱,在孟买可能是一周生活费。
| 策略 | 做法 | 优劣 |
|---|---|---|
| 全球统一定价 | $49/月全球统一 | 简单,但发展中国家用户负担重 |
| PPP 折扣 | 按国家自动打折(印度 -40% 等) | 更公平,但可能被 VPN 绕过 |
| 区域定价 | 不同地区不同价格 | 精确,但维护成本高 |
| 免费 + 增值 | 核心免费,高级功能付费 | 低收入国家用户也能用,有支付能力的自然会升级 |
LemonSqueezy 和 Paddle 作为 MoR 都支持自动 PPP 定价调整。
// Stripe 多币种定价
const prices = {
USD: { amount: 4900, currency: 'usd' },
EUR: { amount: 4500, currency: 'eur' },
GBP: { amount: 3900, currency: 'gbp' },
JPY: { amount: 5500, currency: 'jpy' }, // 无小数
};
// 根据用户 IP 或偏好显示本地货币
function getLocalizedPrice(country) {
const currencyMap = {
US: 'USD', EU: 'EUR', GB: 'GBP', JP: 'JPY',
};
const currency = currencyMap[country] || 'USD';
return prices[currency];
}
付费失败(信用卡过期、余额不足等)是 SaaS 流失的重要原因。好的催收流程可以挽回 10-30% 的流失用户。
// Stripe Billing 内置催收配置
await stripe.subscriptions.update(subscriptionId, {
collection_method: 'charge_automatically',
// 或者使用 Stripe Smart Retries(Billing 0.7% 包含)
});
// 自定义催收流程
async function handleFailedPayment(invoice) {
const daysSinceFailure = daysBetween(
new Date(invoice.created * 1000),
new Date()
);
if (daysSinceFailure === 1) {
// Stripe 自动重试
await stripe.invoices.pay(invoice.id);
} else if (daysSinceFailure === 3) {
await emailService.send('payment_failed_reminder', {
to: invoice.customer_email,
updateUrl: `${APP_URL}/billing/update-card`,
});
} else if (daysSinceFailure === 7) {
await emailService.send('payment_urgent', {
to: invoice.customer_email,
});
} else if (daysSinceFailure >= 14) {
// 降级到免费计划
await downgradeToFree(invoice.customer);
}
}
// 取消流程:先了解原因,再挽留
app.post('/api/cancel-subscription', requireAuth, async (req, res) => {
const { reason, feedback } = req.body;
const user = req.user;
// 记录取消原因
await db.cancellationReasons.create({
userId: user.id,
reason,
feedback,
});
// 挽留策略
if (reason === 'price') {
// 降价挽留
return res.json({
action: 'offer_discount',
message: '我们会给你 30% 折扣续费 3 个月',
discountPercent: 30,
});
}
if (reason === 'missing_feature') {
// 功能路线图承诺
return res.json({
action: 'feature_roadmap',
message: `你提到的功能正在开发中,预计 X 周内上线`,
});
}
// 确认取消 → 期末降级
await stripe.subscriptions.update(user.stripeSubscriptionId, {
cancel_at_period_end: true,
});
res.json({ action: 'cancelled_at_period_end' });
});