# 收款单生命周期

收款单从创建走到关闭或过期。本节介绍它可能处于的状态、状态之间的流转，以及商户在每一步可以做什么。

## 收款单状态

| 状态             | API 值     | 说明                                             | 是否参与付款检索          |
| ---------------- | ---------- | ------------------------------------------------ | ------------------------- |
| 待支付 (Unpaid)   | `unpaid`   | 收款单已开出，支付期限未过，未收到付款           | 是                        |
| 已支付 (Paid)     | `paid`     | 已找到付款并关联到收款单                         | 否                        |
| 已过期 (Expired)  | `expired`  | 支付期限已过，未收到付款                         | 是，过期后再持续 1 小时   |
| 已取消 (Canceled) | `canceled` | 商户手动或通过 API 取消了收款单                  | 否                        |

## 状态流转

* **创建收款单**。收款单立即获得待支付状态。
* **待支付 → 已支付**。收到与收款单金额完全一致的付款，或商户手动关联了付款。
* **待支付 → 已过期**。支付期限已过，未收到付款。
* **待支付 → 已取消**。商户取消了收款单。
* **已过期 → 已支付**。付款在过期后 1 小时内到达并被自动找到，或由商户手动关联。
* **已取消**。终态，无法回退。

处于已支付状态的收款单同样不再变化——不能再次支付，也不能取消。

## 支付期限

支付期限在创建收款单时设定，范围从 30 分钟到 12 小时。可选值：30 分钟、1 小时、3 小时、6 小时、12 小时。

期限之内，买家能看到支付表单并支付收款单。过期后，收款单转为已过期状态，支付表单不再提供支付。

两个极端都有代价。期限太短在慢速网络上有风险——买家可能来不及；太长则拉大创建收款单时与付款时汇率之间的差距。

## 付款检索窗口

付款检索在支付期限过后再持续 1 小时——照顾慢速网络：交易可能在收款单形式上过期之后才确认。这段时间里买家看到的收款单是已过期的，但只要金额正确的付款到达，收款单就自动转为已支付，并发送全部通知。

由此得出集成方的规则：不要因为期限已过就拒绝付款通知——这种检查会砍掉一部分真实付款。

## 取消收款单

收款单有误时可以取消。取消需要满足两个条件：

* 收款单未支付——即处于待支付状态
* 没有人打开过收款单的支付页面，浏览计数为零

第二个条件防止取消买家已经看到、且可能已开始支付的收款单。

取消不可逆。已取消的收款单被排除在付款检索之外，连手动也无法把付款关联上去。如果付款仍有可能到来，与其取消，不如等期限过去——已过期的收款单仍可以由付款关闭。

## 创建时锁定与付款时重算的内容

创建收款单时，服务按当前汇率把法币金额换算成加密货币，并为收款单锁定这些金额。买家看到的是这些金额，服务在链上找的也是这些金额。汇率不再影响它们：无论过去多久，买家支付的都是锁定的金额。

付款时会重算记账金额：

| 字段                | 变化                                                     |
| ------------------- | -------------------------------------------------------- |
| `amountFiat`        | 收款单的法币原始金额，永不改变                           |
| `amountFiatUSD`     | 被实际收到的金额覆盖，按付款时的汇率折算成 USD           |
| `commissionFiatUSD` | 按项目费率由新的 `amountFiatUSD` 值重新计算              |

由于汇率波动，即使付款金额分毫不差，这些值也可能与最初的不同。与店铺订单对账时使用 `amountFiat`——唯一保持不变的金额。

## 收款单生命周期中的通知

通知按项目配置。与收款单相关的有两种：

* **入账付款 (Incoming payment)**。钱包上检测到任何入账交易时发送到邮箱和 Telegram，无论是否关联到了收款单。
* **收款单已支付 (Invoice paid)**。收款单转为已支付的那一刻发送到邮箱、Telegram 和 Webhook URL——自动关联和手动关联都会发送。

由此得到一条简单的诊断规则：收到了入账付款通知，却没有随后的收款单已支付通知，说明付款因金额不一致而未关联，需要人工处理。

## 将买家带回店铺站点

在项目设置中可以设定两个地址，买家会从支付页面返回到那里：

* **成功跳转地址 (Successful URL)**——收款单支付后自动跳转
* **失败跳转地址 (Unsuccessful URL)**——打开已过期或已取消的收款单时自动跳转

两个地址分别启用。未设定时，买家停留在支付页面并看到收款单状态。

地址后会附加 `uid` 参数——面向买家的收款单标识：`https://example.com/order/success?uid=AFhygKX21ecd`。店铺靠它找到订单，并向买家展示自己的页面。

到达这些地址并不代表付款成功——买家可以手动打开链接。发货要依据 [Webhook](./webhook-url/index.md)，或先通过 API [核实收款单状态](./api/index.md)。
