> ## Documentation Index
> Fetch the complete documentation index at: https://waffo.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 订阅到底在什么时候扣款？

> Waffo 如何从订阅开始时间推算每个计费日期，为什么 31 号开始的月度订阅在二月之后会弹回 31 号，延迟重试成功是否会挪动下一个日期，为什么首期失败不重试，以及每个按期扣款状态的含义。

本页讲的是**时间**：某一期在哪一天扣款，以及这一天如何移动。重试策略和支付方式行为见
[订阅重试与支付方式](/docs/zh/support/subscription-retry-and-payment-methods-faq)；
金额见
[订阅金额与按期排期](/docs/zh/support/subscription-amount-scheduling-faq)。

## 续订扣款实际是什么时候发起的？

Waffo 在订阅上保存一个**下次扣款时间戳**，时间戳过去之后，由周期性扫描发起该期的扣款。两个后果：

* 日期是确定的；**当天的具体时刻不是**。对账和客户通知请按天的粒度规划，而不要精确到分钟。
* 所有保存的订阅时间戳——下次扣款时间、期开始和结束时间、订阅结束时间——都是 **UTC**，API 以 ISO 8601 返回。
  如果你的计费日历是本地时间，请在你这一侧转换；没有按商户设置的计费时区。

无法把订阅固定为「在客户所在时区的 09:00 扣款」。你最接近的控制手段是 `/api/v1/subscription/create` 上的 `startTime`，
它设定整个排期推导所依据的锚点——见
[订阅创建与校验](/docs/zh/support/subscription-creation-validation-faq)。

## 后续每个计费日期是怎么推算出来的？

从**订阅的开始时间**出发，累加整数个周期：

```
charge date of period n = subscription start + (n − 1) × (periodInterval × periodType unit)
```

不是从上一次扣款成功的日期算，也不是从上一期的日期逐步推进。每一期都从同一个锚点计算，所以某一期延迟扣款不会挪动之后各期，
舍入也永远不会从一期累积到下一期。

所使用的周期是**该期号所适用的周期**：如果你配置了单独的试用周期，试用期各期按试用周期从开始时间起计数，
正式期各期按正式周期从试用结束起计数。切换发生在试用结束的那个期号。

## 月度订阅从 31 号开始，二月会怎样？

它会**在短月份收敛到最后一个有效日，之后再弹回 31 号。**

因为每一期都按*开始 + n 个月*计算，1 月 31 日加一个月得到 2 月 28 日（闰年为 29 日）——没有 2 月 31 日——但加两个月得到 3 月 31 日，
加三个月得到 4 月 30 日。收敛只作用于落到的那个月；它不会成为新的锚点。

| 期 | 计划日期 |
| - | - |
| 1 | 1 月 31 日 |
| 2 | 2 月 28 日（收敛） |
| 3 | 3 月 31 日 |
| 4 | 4 月 30 日（收敛） |
| 5 | 5 月 31 日 |

这是月末订阅中最常见的意外：\*\*订阅确实会弹回 31 号。\*\*31 号开始的客户在每个月的最后一天被扣款——28、29、30 或 31 日，
取该月实际有的那一天。不要为这类订阅构建假定固定日号的提醒。

如果在稳定的日号计费对你的产品很重要，请让订阅在每个月都存在的日子（1–28 日）开始，或者显式设置 `startTime`，而不是让「现在」决定锚点。

## 某一期重试了三天才成功，下一期会挪动吗？

\*\*默认不会。\*\*下一期按上文所述从订阅开始时间计算，所以靠重试补收的一期不会把后面的排期往后推——客户不会多得天数。

有一个**账户级设置，可以把排期重新锚定到实际支付时间**：启用后，一次成功的续订会从该次扣款成功的那一刻重新计算下次扣款日期，
订阅的结束日期也随之重新计算。关于它有两点需要了解：

* 它只会把排期**向后**移。如果重新计算出的日期早于已保存的日期，则保留已保存的那个。
* 它由 Waffo 在你的收单协议上配置，不在 Portal 中。如果你需要「客户永远从实际付款那天起获得完整一个周期」，
  在按任一种行为开发之前，先问你的 Waffo 对接人你的账户设置的是哪种。

因为两种行为产生不同的日期，不要自己推导下次扣款日期。每期结束后从 `/api/v1/subscription/inquiry` 读回 `nextPaymentDateTime`。

## 做「下次扣款」提醒该读哪个日期字段？

| 字段 | 含义 | 何时变化 |
| - | - | - |
| `startDateTime` | 订阅开始的时间 | 只写一次 |
| `currentPeriod` | 订阅当前所在的期号 | 开启下一期时推进 |
| `nextPaymentDateTime` | **下一**期的计划扣款时间 | 随 `currentPeriod` 推进；**最后一期不推进**；**续订被挂起期间返回 `null`** |
| `endDateTime` | 订阅最后一期结束的时间 | 总期数确定时写入；排期重新锚定时重新计算 |

所以：做提醒读 `nextPaymentDateTime`，但在向客户承诺日期之前先处理两种情况。

* \*\*`null` 不代表「不再扣款」。\*\*订阅的续订被挂起期间——例如当前期仍在尝试扣款，或有套餐变更待处理——Waffo 返回 `null`。
  挂起解除后日期会重新出现。把 `null` 当作*尚未确定*，而不是*已结束*。
* \*\*在最后一期，该值是过期的而不是未来的。\*\*它在那里不再推进，所以仍显示最后一期自身的日期。在告诉客户会再次扣款之前，
  请用 `currentPeriod` 对照订阅的最终期数，或检查 `endDateTime`。

要判断「这个订阅是否已结束」，请读**状态**——
[订阅创建与校验](/docs/zh/support/subscription-creation-validation-faq)上的终态才是答案，而不是某个日期字段。

## 按期扣款状态分别是什么意思？

每个计费期都有自己的订单和自己的状态。Portal 将它们显示为 *Initial*、*To Pay*、*Retrying*、*Paid* 和 *Closed*：

| 状态 | Portal 标签 | 含义 |
| - | - | - |
| `INIT` | Initial | 该期的订单已存在，但尚未提交支付。 |
| `TO_PAY` | To Pay | 已提交；等待支付结果。 |
| `NEED_RETRY` | Retrying | 本次尝试失败，已安排下一次尝试。 |
| `PAY_SUCCESS` | Paid | 该期已收款。终态。 |
| `ORDER_CLOSE` | Closed | 该期不会再收款——重试已用尽，或已被关闭。终态。 |

比标签更重要的两条规则：

* `PAY_SUCCESS` 和 `ORDER_CLOSE` 是**唯一**的终态。其他任何状态仍可能变化。
* 某一期到达 `ORDER_CLOSE` **不会**改变订阅自身的状态。订阅保持 `ACTIVE`，下一期按计划尝试。
  权益决策由你根据这些按期结果自行做出；见
  [订阅重试与支付方式](/docs/zh/support/subscription-retry-and-payment-methods-faq)。

## 为什么第一次扣款完全没有重试？

因为立即开始的订阅的首次扣款是**客户在场**的支付，不是后台续订。它失败时，该期的订单会立即关闭：没有重试计划、不尝试备用支付方式，也不给客户发支付失败邮件。

理由是客户就在现场——正确的恢复方式是让他们再试一次，或者换一种支付方式，而不是反复重试一张他们正眼看着失败的卡。

| 情况 | 首次扣款行为 |
| - | - |
| 订阅立即开始 | 失败即关闭该期，不重试 |
| 订阅有未来的 `startTime` | 激活扣款**会**被当作后台续订处理：会尝试备用方式，重试计划也适用 |

第二行是容易让人栽跟头的例外。延迟开始的订阅是预先授权、之后在客户不在场时扣款的，所以它的首次扣款表现得和后续各期一样。

对立即开始的情况，恢复方式是在客户选好另一种支付方式后创建一个**新的**订阅。不要为同一期单独创建一次性订单并指望订阅能感知到它。

## 我能让客户自己支付失败的那一期，而不是等重试吗？

\*\*没有面向商户的接口可以针对某个失败的期收款。\*\*订阅 API 只有 `create`、`inquiry`、`cancel`、`manage`、`change`、`change/inquiry` 和 `update`——
没有一个会重新发起某期的扣款，也没有「立即支付」或「补缴」调用。

你实际可以做的：

| 目标 | 做法 |
| - | - |
| 让失败的那一期收到款 | 让重试计划跑下去。让客户在托管管理页面添加或修正支付方式，使下一次尝试有可扣的东西。 |
| 立刻向客户收一笔款 | 创建一个普通的**一次性订单**。它是独立交易，不挂在订阅期上。 |
| 把客户换到另一个套餐或价格 | `/api/v1/subscription/change`——见[订阅套餐变更](/docs/zh/support/subscription-plan-change-faq)。 |
| 停止计费 | `/api/v1/subscription/cancel`。 |

添加一个可用的支付方式是价值最高的动作，因为已绑定的备用方式会在下一次失败时**立即**尝试，而不是等待重试间隔。

## 我能在 Portal 里自己改重试策略吗？

不能。重试策略——每周期的间隔和最大尝试次数——位于你的收单协议上，由 Waffo 设置。没有 Portal 页面、也没有 API 可以写入它，
所以不能自助修改，它也不是按请求的参数。

协议上其他影响排期的设置也是如此：上文的支付后重新锚定行为，以及取消订阅时是否关闭待执行的重试。三者都是账户级的。
其中任何一项被修改时，请明确询问它是适用于已有订阅还是仅适用于新订阅——答案取决于是哪项设置，而假设错了正是对账出问题的原因。

## 不等真实周期，我怎么测试这些？

使用沙箱续订模拟器：激活一个订阅，用 `/api/v1/subscription/manage` 获取其管理 URL，打开它，用模拟下次支付的控件一期一期地推进。
每点一次就是一期，所以你可以串起「第 2 期成功、第 3 期失败」。详情和保留的测试金额见
[沙箱模拟器](/docs/zh/developer-docs/tools-and-references/developer-tools/sandbox-simulator)
和[沙箱测试](/docs/zh/support/sandbox-testing-faq)。

沙箱**不**允许你快进真实时钟，所以上文的月末行为最好通过在每次模拟一期后读取 `nextPaymentDateTime` 来验证，而不是靠等待——
31 号开始的订阅应在二月显示 28/29 日，在三月重新显示 31 日。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.