Skip to main content
在订阅存在之前必须正确的一切:接受的取值范围、必须一起提供的字段,以及创建响应的含义。 金额配置见 订阅金额与按期排程 FAQ。 跨币种行为和 Portal 查询见 跨币种订阅与 Portal FAQ。

我可以配置哪些计费周期?

periodType 和 periodInterval 共同定义周期长度。两者都是必填, 且 periodInterval 的接受范围取决于 periodType: 没有 YEARLY 周期类型。 年度订阅请使用 periodType: MONTHLY 加 periodInterval: 12。 这两个字段同样覆盖了商户通常按名称询问的周期: 个别支付方式可能进一步收窄范围——有些拒绝按日周期,有些只接受特定的周期/间隔组合。 通过了上述范围的周期,仍可能被您选择的支付方式拒绝。

试用期可以使用与正式周期不同的周期吗?

可以。试用周期通过 trialPeriodType 和 trialPeriodInterval 独立于正式周期配置, 接受范围与正式周期相同:
  • trialPeriodType 和 trialPeriodInterval 必须一起提供——只提供其中一个会被拒绝。
  • 如果两者都省略,试用期直接沿用 periodType 和 periodInterval。
  • 独立配置不意味着没有交叉校验。见下一个问题。

哪些订阅字段必须一起提供?

即使试用周期是独立配置的,以下跨字段规则仍会强制执行:

一个订阅可以运行多少期?

“没有商户定义的结束”并不是字面意义上的无限:没有 numberOfPeriod 的订阅仍受您订阅协议上的最长时限约束, Waffo 会根据该时限和您的周期推导出一个有效的最终期数。有些支付方式也有自己的最长时限。 所以即使您从未设置过,也要为订阅最终到达最后一期做好准备。 订阅一旦到达最后一期,金额更新会被拒绝——见金额页面。

创建订阅时 goodsUrl 和 appName 是必填的吗?

不是。 在 /api/v1/subscription/create 上两者都是可选的,您可以两者都不提供地创建订阅。 您可能见过的”提供 goodsUrl 或 appName 之一”规则属于一次性订单创建,而不是订阅创建。 个别协议出于合规和风控原因仍可能要求 goodsUrl,所以提供两者之一仍是好的做法—— 但它不是订阅创建的通用校验,把集成建立在它是通用校验的假设上,会在您排查拒绝原因时误导您。

订阅有哪些状态,哪些流转是合法的?

共有九个状态。每个状态只能从特定的一组来源状态到达,所以一个您没预料到的状态, 通常是您漏掉了更早的一次流转,而不是状态本身无效: 按您的集成大概需要的方式分组: 把整个终态组当作”不会再开启新的计费期”,并按组而不是按单个值做分支——这样一个您没有映射到的状态就不会悄悄地看起来像一个活跃订阅。

PLATFORM_CANCELLED 是什么?

这是当 Waffo 主动取消订阅时设置的终态,原因是该订阅的某笔扣款产生了争议、拒付或欺诈信号。 它和其他任何取消一样通过订阅状态通知到达您这里,通知中带有取消原因,标明是哪种信号触发的。 对您的集成重要的几点:
  • 它只能从 ACTIVE 到达。
  • 自动取消是按商户、按信号类型可配置的,且未配置时默认关闭——所以您可能永远见不到这个值, 它的缺席并不意味着争议被忽视了。
  • 因为是 Waffo 而不是您发起的,在您处理该通知之前,您自己的记录会显示订阅仍是活跃的。请把 Webhook Webhook 通知当作事实来源。
争议和拒付处理本身见 拒付 FAQ。

创建返回了 AUTHORIZATION_REQUIRED,我该怎么做?

用户仍需授权这个周期性扣款授权。创建响应带有 subscriptionAction,其中包含要把用户引导去的 URL(webUrl)。 把用户重定向到那里;授权成功后订阅进入 ACTIVE。 subscriptionAction 只在订阅处于 IN_PROGRESS 或 AUTHORIZATION_REQUIRED 时才有值。 订阅一旦激活或进入终态就不再返回,这是预期行为而非错误。 授权链接有时效。创建请求上的 orderExpiredAt 设置该截止时间;如果省略,则应用平台默认值,而且它很短—— 是分钟级而不是小时级——所以请立即把用户引导到链接。授权在窗口期内始终未完成的订阅会进入 CLOSE。

如果我用同一个请求 ID 再次调用创建会怎样?

创建按 subscriptionRequest——您生成的请求 ID——幂等,而不是按 merchantSubscriptionId。 在同一 MID 下用相同的 subscriptionRequest 重复调用不会创建第二个订阅。 返回的内容取决于已存在的订阅走到了哪一步: 重复调用还会做一致性校验:如果 amount 或 currency 与原请求不同,该调用会被作为重复请求拒绝,而不是被悄悄接受。 所以请用完全相同的载荷重试,且不要把一个 subscriptionRequest 用于两个不同的订阅。 如果用户放弃了授权而您需要给他们一个新链接,请在订阅仍处于激活前状态时重试创建,并使用返回的 subscriptionAction; 不要缓存链接并假定它一直有效。

我如何查询订阅,以及如何获取每期的扣款?

调用 /api/v1/subscription/inquiry,传 subscriptionRequest 或 subscriptionId——至少需要一个。两个都传也可以。 每期扣款默认不返回。把 paymentDetails 设为 1 才能获取(默认值 0 不返回;任何其他值会被拒绝): 每个 paymentDetails 条目带有 acquiringOrderId、orderCurrency、 orderAmount、orderStatus、orderUpdatedAt 和 period,在有额外(席位加购)扣款的期上还有一个 topupDetails 列表——这些行如何编号见 跨币种订阅与 Portal FAQ。 反过来——从一笔扣款找到它的订阅——订单查询响应带有一个 subscriptionInfo 块,包含 subscriptionId、period、 subscriptionRequest 和一个 subscriptionEvent,告诉您这笔扣款是周期扣款还是支付方式添加。一次性订单没有 subscriptionInfo。 订阅响应还会报告 productInfo.currentPeriod 和已存储的 productInfo.scheduledAmounts,这是您在排程金额变更之前要读取的内容。

一个用户可以有多少个订阅?

任意数量。在一个 MID 下,同一个 merchantUserId 可以持有您创建的任意多个订阅——没有按用户的上限, 创建时也不对 merchantUserId 做唯一性检查。 这是多产品、多席位业务的常态:一个用户、多个并行订阅,每个有自己的 subscriptionId 和自己的生命周期。 因此,永远不要把 merchantUserId 当作”该用户的订阅”的键——请以 subscriptionId 或您自己的 merchantSubscriptionId 为键。

订阅可以在未来某个日期开始吗?

可以——创建时传 startTime。校验规则: 不支持回溯。 无法创建一个表现得像更早就已开始的订阅,也无法让第一期落在过去。 如果您需要对已经过去的周期收费,请作为单独的一次性订单收取。 延后开始时还有两个约束:
  • 开始日期必须落在将要使用的协议的有效期窗口内,所以即使在 365 天以内,过远的开始日期也可能因此被拒绝。
  • 变更套餐时,startTime 不得早于原订阅的下一次计划扣款。
从创建到开始日期之间您能做和不能做什么,见 订阅生命周期与支付方式管理。