Stripe 的 Product、Price、Coupon、Promotion Code、Discount 和 Tax Rate 有什么区别?
Stripe 的商品、价格、优惠与税率对象经常同时出现在 Checkout、订阅和发票中,但它们不在同一层。Product 描述卖什么,Price 描述如何收费,Coupon 定义优惠规则,Promotion Code 是客户可输入的兑换码,Discount 记录优惠实际应用,Tax Rate 则描述税费如何计算和展示。 把这些对象混成一张“商品表”,容易造成改价覆盖历史记录、优惠码失控、税费重复或账单无法解释。
本文目录(27 节)
六种对象快速对比
| 对象 | 核心问题 | 常见内容 | 是否直接代表一次交易 |
|---|---|---|---|
| Product | 卖什么 | 名称、描述、图片、元数据 | 否 |
| Price | 怎么收费 | 金额、币种、一次性或周期、计费方式 | 否 |
| Coupon | 优惠规则是什么 | 百分比或固定金额、持续时间、适用商品 | 否 |
| Promotion Code | 客户输入什么 | 可读代码、适用客户、最低金额、到期限制 | 否 |
| Discount | 哪次优惠已被应用 | 来源、开始与结束时间、应用目标 | 是优惠应用记录 |
| Tax Rate | 税怎么收 | 税率、含税或未税、辖区、展示名 | 是计税配置,不是折扣 |
最简单的记忆方式是:Product 与 Price 构成目录,Coupon 与 Promotion Code 构成促销配置,Discount 是兑换后的结果,Tax Rate 是独立的税务维度。
Product 是“卖什么”
Product 表示业务提供的商品或服务,例如“专业版会员”“技术咨询一小时”或“海外仓打包服务”。它适合保存面向业务的名称、描述、图片以及内部元数据,而不应承担具体金额和周期规则。
同一个 Product 可以关联多个 Price。这样“专业版”可以同时有月付、年付、美元和欧元价格,而无需复制多份商品。Product 的 default_price 只是常用展示价格,并不意味着其他 Price 失效。
Product 不等于订单行
Product 是目录主数据,不是客户已经购买的凭证。Checkout Session、Invoice Line Item 或 Subscription Item 会引用相应的价格或价格快照,才形成具体交易上下文。
因此,不要通过修改 Product 名称来试图改写历史账单。Stripe 会为历史交易保留商品和价格记录;展示历史单据时,应以单据保存的交易信息为准。
Price 是“如何收费”
Price 把 Product 转换成可收费方案。它通常包含币种、单位金额、一次性或周期性属性,以及按单位、分层或用量计费等模型。一个 Product 可以有“每月 10 美元”和“每年 100 美元”两个独立 Price。
创建 Checkout 或 Subscription 时,真正决定收费方式的通常是 price ID,而不是 Product ID。应用代码应保存稳定的 Price ID 或 lookup_key 映射,不应仅靠界面文案猜测价格。
为什么改价要新建 Price
Stripe 官方说明,已创建 Price 的核心计价字段不能像普通数据库行一样随意覆盖;API 可更新的重点字段包括 metadata、nickname 和 active。金额变化时,应创建新 Price,把新购买流程切换到新 ID,再把旧 Price 设为非活动。
这样做能保护历史交易语义:旧订阅继续知道自己原来按什么价格签约,新客户则使用新价格。直接复用业务侧同一个“套餐编号”覆盖金额,会让对账、退款和收入分析难以解释。
一次性 Price 与周期性 Price
一次性 Price 不设置周期,常用于买断、设置费或单次服务。周期性 Price 使用 recurring 描述月、年等周期,并可配合订阅和用量计费。
“同一 Product 下有多个 Price”不代表客户会被全部收费。实际收费取决于 Checkout Line Item、Subscription Item 或 Invoice Item 引用了哪一个 Price,以及数量与计费周期如何设置。
Coupon 是优惠规则模板
Coupon 定义“减多少、减多久、适用于什么”的规则,例如九折、减 20 美元、仅首次账单生效,或只适用于某些 Product。它是可被兑换的促销规则,不是客户看到的口令。
固定金额优惠还与币种相关;百分比优惠则按符合条件的金额计算。设计 Coupon 时应先确定适用范围、持续时间和财务上限,而不是先想一个营销代码。
Coupon 与 Price 的区别
Price 是正常售价,Coupon 是在满足条件后对金额进行调整的优惠规则。限时促销通常不需要为每个活动复制一套低价 Price;可以保留标准 Price,再通过 Coupon 或 Promotion Code 应用优惠。
但如果“促销价”实际上是长期的新定价方案,使用新的 Price 往往更清楚。判断标准是它属于稳定的产品定价,还是一次受条件约束的优惠。
Promotion Code 是客户可兑换入口
Promotion Code 是面向客户的字符串,例如 WELCOME25,它引用一个既有 Coupon。多个 Promotion Code 可以指向同一个 Coupon,从而共享“减 25%”规则,但分别设置渠道、客户或有效期限制。
这层分离让营销口令与财务规则解耦:Coupon 回答优惠怎么算,Promotion Code 回答谁能在什么条件下兑换以及客户输入什么。
Promotion Code 可以限制什么
Stripe 支持为 Promotion Code 配置指定客户、首次订单、最低订单金额、到期时间和兑换次数等限制。代码在活动状态下的唯一性也有规则,且匹配不区分大小写。
如果底层 Coupon 失效,关联的 Promotion Code 会永久失效;达到最大兑换次数或到期的代码也不能重新激活。运营后台应把“主动停用”和“因规则耗尽而永久失效”区分展示。
Coupon 与 Promotion Code 如何选择
后台直接给指定订阅优惠时,可以应用 Coupon;需要客户在 Checkout 输入、分渠道投放或限制首次购买时,更适合使用 Promotion Code。两者最终都可能产生 Discount。
不希望客户分享代码时,不要只依赖难猜的字符串。应使用客户限制、首次交易限制、到期时间和兑换上限,或者由服务端直接应用 Coupon。
Discount 是实际应用结果
Discount 表示 Coupon 或 Promotion Code 已经被应用后的结果。它包含优惠来源、开始时间、可能的结束时间,以及关联的客户、订阅、订阅项、发票或 Checkout Session 等上下文。
因此 Discount 不是另一种“优惠券模板”。Coupon 是规则,Promotion Code 是兑换入口,Discount 才是某个目标已经获得该优惠的事实记录。
为什么不能把 Discount ID 当通用资源查询
Stripe API 文档指出,Discount 不能像普通顶层资源那样仅凭 ID 单独获取。需要从包含它的对象读取,或在相关 API 调用中使用 expand[]=discounts 展开。
数据模型中可以记录 Discount ID 用于审计关联,但读取流程必须从 Customer、Subscription、Invoice 等拥有该优惠的资源出发。否则容易出现“数据库有 ID,API 却查不到”的误判。
多个优惠如何理解
Stripe 的新式 discounts 参数允许在支持的对象上应用多个优惠。更新时,必须把希望保留的既有 Coupon、Promotion Code 或 Discount 一并传入;遗漏可能改变订阅当前的优惠集合。
不要在业务代码中假设所有优惠都简单相加。固定额与百分比优惠、适用 Product 和账单项目会影响结果。应以 Stripe 返回的 Invoice、Line Item 和折扣金额为准,并针对组合顺序做沙箱测试。
Tax Rate 是税率,不是加价版 Price
Tax Rate 描述税的显示名称、百分比、含税或未税、国家或辖区等信息。它可以应用到 Checkout、发票或订阅的计税场景,但不会改变 Product 是什么,也不是一个负数 Coupon。
税费与优惠需要分开建模,因为它们的法规意义、会计科目和展示要求不同。把税直接加进 Price 文案或用负折扣模拟税,会破坏发票透明度。
inclusive 与 exclusive 的区别
inclusive=true 表示标价已包含税,税额从含税总额中拆分;inclusive=false 表示在未税金额之上增加税。两者即使百分比相同,客户看到的应付总额也可能不同。
选择方式应符合销售地区、商品类型和价格展示规则。不要只因前端想显示整数价格就切换含税模式,税务处理需要经过合规确认。
手动 Tax Rate 与 Stripe Tax
手动 Tax Rate 适合业务已经确定税率并负责适用性判断的场景。Stripe Tax 的自动税务能力则会根据客户位置、产品税码、注册地等信息计算适用税费。
两者不是简单的“手动值与自动值”字段替换。启用自动税务前,要准备准确的客户地址、产品税码和税务注册信息,并检查当前产品及地区是否受支持。
对象之间的典型数据流
一条常见路径是:先创建 Product,再为它创建 Price;客户在 Checkout 选择该 Price;若输入 Promotion Code,Stripe 按其关联 Coupon 验证限制并产生 Discount;随后在符合条件的金额上计算或应用 Tax Rate;最终形成 Payment、Invoice 或 Subscription 记录。
这条路径并非每种集成都完整出现。一次性 Payment Link 可能没有订阅,后台赠送优惠可能不需要客户输入 Promotion Code,自动税务也可能不使用手工创建的 Tax Rate。
推荐的内部数据模型
业务数据库至少应分别保存 product_id、price_id、可选的 coupon_id 或 promotion_,以及交易对象 ID。不要用一个 stripe_plan 字段混装所有概念。
本地套餐编码可以映射 Price 的 lookup_key,但仍要保存结算时实际使用的 Price ID。促销活动还应记录活动名称、投放渠道和授权状态,不能只保存客户输入字符串。
Checkout 集成要注意什么
开启 allow_ 后,Checkout 才会显示客户兑换输入框。服务端创建 Session 时应明确允许的 Line Item、模式和税务配置,不要相信前端提交的金额或 Product 名称。
回调处理中应读取 Checkout Session、PaymentIntent 或 Invoice 的最终状态和金额。客户输入过代码并不等于 Discount 一定生效,支付成功也不代表业务侧可以忽略税额与折扣明细。
Subscription 更新的常见陷阱
修改订阅 Price 可能触发按比例计费,既有优惠也会参与计算。Stripe 文档特别提醒,价格更新与 Promotion Code 应用可能分开处理,因此一次请求中的部分变化可能成功、另一部分因支付失败而失败。
更新后要重新读取 Subscription 和最新 Invoice,确认项目、优惠、税费与支付状态,而不能只把一次 API 200 响应视为所有业务动作都原子完成。
Webhook 中应记录哪些 ID
建议记录 Event ID 防重、Request ID 排障,并保存 Customer、Checkout Session、Subscription、Invoice、PaymentIntent、Price 及 Discount 关联。Promotion Code 和 Coupon ID 则帮助解释优惠来源。
Webhook 处理必须先验签再做幂等处理。收到重复事件时,不应重复发货、重复延长会员或再次生成优惠权益。
测试环境检查清单
在 Stripe 沙箱中至少测试标准价、一次性价、周期价、无优惠、直接 Coupon、Promotion Code、过期代码、次数耗尽、最低金额不满足、含税与未税、多优惠和订阅改价。
每个用例都检查 Stripe 返回的 subtotal、discount、tax、total 与本地订单一致,并验证退款、取消和失败支付不会留下错误权益。测试数据与正式模式资源彼此独立,正式密钥不得进入浏览器或日志。
常见错误判断
“一个 Product 只能有一个价格”是错的;“修改 Product 就能修改现有订阅金额”也是错的。“Coupon 就是客户输入的代码”混淆了规则和入口;“Discount 可以全局按 ID 查询”不符合其读取方式;“Tax Rate 就是给金额乘百分比”则忽略了含税、辖区和适用性。
排障时先确认对象类型与 ID 前缀,再沿 Checkout、Subscription 或 Invoice 的实际引用关系查看,而不是根据后台显示名称推断。
选型结论
需要描述商品,用 Product;需要表达币种、金额和周期,用 Price;需要定义减免规则,用 Coupon;需要客户输入且带兑换限制,用 Promotion Code;需要追踪优惠已应用到哪里,用 Discount;需要表达税率和含税方式,用 Tax Rate。
稳定的系统会让这六层各司其职,并以 Stripe 返回的交易对象为结算事实。改价新建 Price、促销保留来源、税费独立核算,能显著降低对账与订阅变更风险。
常见问题
一个 Product 能否同时有月付、年付和一次性价格?
可以。为同一 Product 创建多个 Price,每个 Price 分别设置币种、金额和一次性或周期性属性。创建交易时明确选择所需 Price。
Coupon 和 Promotion Code 是否必须同时创建?
Coupon 是优惠规则。若由后台直接应用,可以不创建客户代码;若希望客户输入可读口令,则创建引用该 Coupon 的 Promotion Code。
Price 金额填错后可以直接修改吗?
不应覆盖已使用 Price 的金额。创建正确的新 Price,切换新购买入口,再将旧 Price 设为非活动,并检查既有订阅是否需要单独迁移。
为什么有 Promotion Code 却看不到 Discount?
代码可能未满足客户、最低金额、有效期或次数限制,也可能只完成了输入但交易未形成。应读取 Checkout Session、Subscription 或 Invoice 的最终折扣数据。
Tax Rate 应该在优惠前还是优惠后计算?
不要在本地凭经验硬编码顺序。税务计算会受地区、含税模式、商品税务属性和优惠适用范围影响,应使用 Stripe 最终 Invoice 或 Checkout 结果并经税务专业人员确认。
官方资料
- Stripe:Products and prices overview — https:
/ / docs. stripe. com/ products- prices/ overview - Stripe:Manage products and prices — https:
/ / docs. stripe. com/ products- prices/ manage- prices - Stripe API:Product object — https:
/ / docs. stripe. com/ api/ products/ object - Stripe API:Price object — https:
/ / docs. stripe. com/ api/ prices/ object - Stripe:Coupons and promotion codes — https:
/ / docs. stripe. com/ billing/ subscriptions/ coupons - Stripe API:Discount object — https:
/ / docs. stripe. com/ api/ discounts/ object - Stripe API:Tax Rate object — https:
/ / docs. stripe. com/ api/ tax_ rates/ object