> ## 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.

# 订阅金额与按期排程 FAQ

> scheduledAmounts 是什么意思、Waffo 如何为每个账单周期选取金额、/subscription/update 能改什么不能改什么（它只能下调金额；上调需要变更套餐或席位加购补款）、金额更新 Webhook，以及为什么没有按比例计费字段。

本页介绍**每个账单周期收多少钱**：按周期配置不同金额、在生效中的订阅上变更金额，以及 Waffo 对周期中途改价做什么（以及不做什么）。

创建时的校验和状态值见[订阅创建与校验 FAQ](/docs/zh/support/subscription-creation-validation-faq)。延期开始、支付方式和重试见[订阅生命周期与支付方式管理](/docs/zh/support/subscription-lifecycle-management)和[订阅 FAQ](/docs/zh/support/subscription-faq)。

## 订阅请求里的 `scheduledAmounts` 是什么意思？

`scheduledAmounts` 是 `productInfo` 内的一个可选列表，允许你在**特定账单周期收取不同金额**，而不是每期都收相同的 `amount`。每个条目恰好有两个字段：

| 字段 | 类型 | 含义 |
| - | - | - |
| `period` | String | 该金额适用于哪个账单周期。正整数，`1` = 订阅的**第一个**周期。 |
| `amount` | String | 该周期收取的金额，与订阅币种相同。 |

```json theme={null}
{
  "amount": "99.90",
  "productInfo": {
    "periodType": "MONTHLY",
    "periodInterval": "1",
    "numberOfPeriod": "12",
    "scheduledAmounts": [
      { "period": "1", "amount": "9.90" },
      { "period": "2", "amount": "49.90" }
    ]
  }
}
```

该订阅第 1 期收 9.90，第 2 期收 49.90，第 3 到 12 期每期收 99.90。你未列出的周期直接回退到 `amount`，列出的周期**不必**连续——只列第 1 期和第 5 期也是合法的。

你可以在创建订阅时设置 `scheduledAmounts`，之后用 `/api/v1/subscription/update` 修改。

## `period` 是从第一期算起，还是从试用期后的第一期算起？

**从订阅的第一期算起。**`period` 是覆盖每个账单周期的绝对、从 1 开始的索引，试用期也计入其中。

存在试用期时这一点很重要：如果你配置了 2 期试用，那么 `period: 1` 和 `period: 2` 指向的是两个**试用**周期，第一个正价周期是 `period: 3`。

| 订阅 | `period: 1` 指向 |
| - | - |
| 无试用 | 第一次正价扣款 |
| 2 期试用 | **第一次试用**扣款 |

任何地方都不应用偏移：Waffo 查出即将创建的扣款所在的周期号，并用这个确切的数字去读 `scheduledAmounts`。要查看生效中订阅当前所在位置，从 `/api/v1/subscription/inquiry` 读取 `productInfo.currentPeriod`——存储的计划以 `productInfo.scheduledAmounts` 在同一响应中返回，所以你在发送更新之前总能确认哪些周期号仍在未来。

## Waffo 如何决定每期的金额？

按以下顺序查阅三个输入；**最后**匹配的规则胜出：

| 优先级 | 规则 | 适用条件 |
| - | - | - |
| 1（最高） | `period` 等于本周期号的 `scheduledAmounts` 条目 | 该周期在计划中列出 |
| 2 | `trialPeriodAmount` | 本周期号在 `numberOfTrialPeriod` 之内且没有匹配的排程金额 |
| 3（回退） | `amount` | 以上都不匹配 |

所以 `scheduledAmounts` 条目会**覆盖该周期的试用金额**。如果你希望试用期按 `trialPeriodAmount` 计费，不要在 `scheduledAmounts` 中列出试用周期号。

当某次扣款与你的预期不符时，这是首先要检查的：算出该扣款的周期号，然后按顺序走一遍这三条规则。

## `scheduledAmounts` 的确切限制是什么？

| 约束 | 规则 | 违反时 |
| - | - | - |
| 列表长度 | 最多 **10** 个条目 | 参数校验错误 |
| `period` | 正整数（`≥ 1`） | 参数校验错误 |
| `period` 唯一性 | 单个请求内不得重复 | 参数校验错误，消息 `scheduledAmounts.period must be unique` |
| `period` 上限（创建） | 不得超过 `numberOfPeriod` | 参数校验错误，指出违规周期 |
| `period` 上限（更新） | 不得超过订阅的最终周期数 | 参数校验错误，指出违规周期 |
| `period` 下限（更新） | 必须**严格大于**当前周期 | 参数校验错误，指出当前周期 |
| `amount` | 每条目必填，不得为负 | 参数校验错误 |
| `amount` 精度 | 必须符合该币种的 ISO 4217 小数位，以及该币种的任何整单位倍数规则 | 金额小数位错误 |
| `amount` 范围 | 必须落在你订阅协议的金额范围内 | 金额超出范围错误 |

两个值得指出的细节，因为常被反向假设：

* **金额是币种常规单位的十进制字符串，不是最小单位。**是 `"9.90"`，不是 `"990"`。多余的小数位会被**拒绝**，不会被舍入。
* **`amount: "0"` 能通过字段校验**，所以免费周期是可表达的——但该值仍须满足你协议上的最小金额，因此 0 是否被接受取决于你的合约。

## 我能直接上调下一期的订阅金额吗？

\*\*不能——不能通过 `/api/v1/subscription/update`。\*\*默认情况下该接口拒绝任何上调。这在三个金额字段上都强制执行：

| 字段 | 规则 |
| - | - |
| `amount` | 新值必须 `≤` 当前 `amount` |
| `productInfo.trialPeriodAmount` | 新值必须 `≤` 当前试用金额 |
| `productInfo.scheduledAmounts[].amount` | 按周期，新值必须 `≤` 该周期的基线 |

按周期的基线是**当前存储的同一周期的排程金额**，若该周期不在存储的计划中则是订阅的 `amount`。这堵住了显而易见的漏洞：你不能先把某期调低，再在第二次调用中调回去，因为第二次调用是与你刚写入的值比较的。

违规以参数错误返回，消息指出被拒绝的内容（`amount is not allowed to increase`、`trialPeriodAmount is not allowed to increase`，或 `scheduledAmounts.amount is not allowed to increase for period N`）。

要收**更多**，要么用 `/api/v1/subscription/change` 把用户迁到新套餐，要么——当上调属于席位加购时——在更新中带上 `topupInfo` 块：该路径立即收取当期差额，并允许从下一期起上调 `amount`（见下文按比例计费表）。通过 `update` 直接上调对账户不普遍开放；如果你认为你的集成需要它，请向集成支持提出，而不是绕着它设计。

## 我如何设置按比例计费（prorate）？

\*\*没有按比例计费字段，Waffo 也不计算按比例计费。\*\*如果你在找 `prorate` / `proration_behavior` 参数，它不存在——`/subscription/update` 和 `/subscription/change` 上都没有。

以下是每种情况下实际发生的事，供你决定在自己这边实现什么：

| 你想要的 | Waffo 做什么 | 你必须做什么 |
| - | - | - |
| 从下一期起变更金额 | `/subscription/update` **从下一个账单周期起**应用新金额。当期不受影响，也不为其计算任何贷方或借方。 | 无需额外操作——但不要期望有部分周期的调整。 |
| 把用户迁到不同套餐 | `/subscription/change` 锁定原订阅并**基于它创建一个新订阅**。你可以传入一个待结转的剩余价值，Waffo 随后用它抵扣新订阅的扣款。 | 自己计算结转价值并在变更请求中传入。Waffo 不计算它。 |
| 立即收取周期中途的差额 | 带 `topupInfo` 块的 `/subscription/update`（**席位加购**）立即把 `topupAmount` 作为当期内的额外订单收取，并从下一期起应用新的 `amount`。`topupAmount` 由你计算；Waffo 不按比例折算。 | 发送 `topupInfo`（`topupRequest` 作为幂等键、`topupAmount`、可选的 `description` 和 `orderExpiredAt`）。响应携带补款订单及其状态；新金额只在该次扣款成功后才应用。或者把差额作为单独的一次性订单收取。 |

简而言之：金额变更是**周期边界事件**，任何因变更落在周期中途而应当流动的资金，由你计算、由你收取。

## `/subscription/update` 到底改什么，何时生效？

它只改金额，从下一个账单周期起。

**它能改：**`amount`、`productInfo.trialPeriodAmount`、`productInfo.scheduledAmounts`——单独或一起。三者至少要有一个，否则请求被拒绝。

\*\*它不改：\*\*套餐、`periodType`、`periodInterval`、剩余周期数、账单日期或支付方式。它不触发按比例计费，也不创建新订阅。

**时间：**新值从下一期起应用。当期已经生成或已在进行中的扣款**不**受影响。响应会告诉你变更落在哪个周期号：

| 响应字段 | 含义 |
| - | - |
| `subscriptionId` / `subscriptionRequest` | 标识订阅 |
| `previousAmount` / `newAmount` | 变更前后的基础金额（未变则相等） |
| `previousTrialPeriodAmount` / `newTrialPeriodAmount` | 变更前后的试用金额 |
| `previousScheduledAmounts` / `newScheduledAmounts` | 变更前后的计划；未存储计划时省略 |
| `nextEffectivePeriod` | 新金额开始适用的**周期号** |

## 金额更新何时会被直接拒绝？

| 条件 | 行为 |
| - | - |
| `subscriptionRequest` 和 `subscriptionId` 都未提供 | 拒绝 |
| `amount` / `trialPeriodAmount` / `scheduledAmounts` 都未提供 | 拒绝 |
| 订阅在你的 MID 下不存在 | 未找到错误 |
| 订阅不是 `ACTIVE` | 拒绝——状态错误 |
| 订阅已到达最终周期 | 拒绝，消息中带最终周期号 |
| 试用期结束后发送 `trialPeriodAmount` | 拒绝——试用金额不再可修改 |
| 订阅的排程由支付方式而非 Waffo 驱动 | 该订阅不支持 |
| 同一订阅有另一个更新或续订正在处理 | 拒绝——稍后重试 |

最后一行意味着更新是**按订阅串行化**的。如果你要给大量订阅重新定价，请把"正在修改，请稍后重试"响应当作可重试的，而不是失败。

## 如果我在更新中发送 `scheduledAmounts`，会与现有计划合并吗？

\*\*不会——你发送的列表整体替换存储的计划。\*\*它不是补丁：旧计划中存在但你的请求中缺失的周期不再有排程金额，回退到 `amount`。

两个需要为之设计的后果：

* 始终发送你想定价的**完整**未来周期集合，而不只是你要改的那些。
* 因为更新只能针对当前周期**之后**的周期，替换计划时已扣款周期的条目会从存储中删除。这是预期行为，不会改变任何已发生的扣款。

发送**空数组**或省略该字段被视为*无变更*——它**不会**清空计划。没有办法通过 `/subscription/update` 清空排程金额计划；要回到单一固定金额，请把每个剩余未来周期都列为你想要的金额，或用 `/subscription/change` 把用户迁到新套餐。

## 升级或降级时 `scheduledAmounts` 会怎样？

不继承任何东西。`/subscription/change` 创建一个**新**订阅，该新订阅的 `amount` 和 `scheduledAmounts` **完全来自变更请求**。如果你在那里省略 `scheduledAmounts`，新订阅就完全没有按期计划，每期都按新的 `amount` 计费。

所以如果分级价格阶梯应该在升级后延续，你必须在变更请求中重新声明它。

## 终端用户会被告知金额变了吗？

会——金额更新成功后 Waffo 会给订阅者发邮件。邮件包含原金额、新金额、变更前后的按期计划，以及变更生效的周期号。

两个运营提醒：

* 只有在你的账户和产品启用了金额变更通知时才发送邮件。关闭时不会向用户发送任何内容。
* 发送是尽力而为且异步的：邮件失败**不会**回滚金额变更。API 响应才是变更内容的记录。

## 金额更新成功时 Waffo 会给我发 Webhook 吗？

会。`/subscription/update` 成功后，Waffo 向订阅上存储的 `notifyUrl` 推送 **`SUBSCRIPTION_UPDATE_NOTIFICATION`**。对于普通金额变更，更新提交后立即发送；对于席位加购（见下文），在补款扣款成功并应用新金额后发送。报文是查询 API 返回形式的订阅，因此已经反映新金额。

为保持你自己的记录一致：

* 把 `/subscription/update` 的响应当作主要记录——从中读取 `newAmount`、`newScheduledAmounts` 和 `nextEffectivePeriod` 并存储。Webhook 异步确认同一变更，是变更在你的即时请求路径之外提交时（补款场景）应使用的信号。
* 继续监听按期通知和订阅支付订单通知以获取每期的**实际扣款金额**——它们反映实际收取的数字，也是你应据以对账的数字。

## 哪些订阅可以使用按期金额？

按期金额和 `/subscription/update` 可用于**由 Waffo 驱动账单排程**的订阅。对于某些支付方式，排程由支付方式自身驱动；这些订阅在创建时拒绝 `scheduledAmounts`，也不能进行金额更新。如果创建调用返回说该订阅不支持排程金额，原因就在此——解决方法是换支付方式，不是换请求形态。


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