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

# 订单在每个状态下我能做什么？

> 订单状态列表（包括大多数商户从未见过的两个状态）、哪些状态接受取消、请款和退款、为什么订单会停在 AUTHORIZATION_REQUIRED、关闭原因写在哪里、支付方式已经收了钱时取消会怎样，以及对已授权卡支付请款的规则。

状态列表本身发布在[支付生命周期与订单状态](/docs/zh/developer-docs/core-concepts/payment-lifecycle)和[数据参考](/docs/zh/developer-docs/tools-and-references/references/data-reference)。本页是*操作*的那一半：每个状态接受哪些操作，以及三个写接口——取消、请款、退款——在订单不处于你预期状态时会做什么。

| 页面 | 用途 |
| - | - |
| [确认支付结果](/docs/zh/support/payment-results-faq) | 每个状态*意味着*什么，以及如何确认结果 |
| [超时与结果何时终态](/docs/zh/support/payment-timeout-and-finality-faq) | 结果是否还会变化，以及超时安全的集成方式 |
| **本页** | 哪个状态允许哪种操作，以及不允许时的错误 |

## 有没有不在已发布列表里的状态？

有两个，都值得了解，因为它们解释的是令人困惑的现象，而不是需要你操作的东西。

| 状态 | 是什么 |
| - | - |
| `CAPTURE_IN_PROGRESS` | 你请求的请款正在执行。它介于已授权状态和 `PAY_SUCCESS` 之间，并接受重复的请款调用 |
| *（任何东西到达支付方式之前的前置状态）* | 已被接受但尚不存在任何支付尝试的订单，**向你报告为 `AUTHORIZATION_REQUIRED`**。API 上没有单独的值 |

第二个是商户经常问的问题的答案，值得直白说明：`AUTHORIZATION_REQUIRED` 同时涵盖\*"支付方式正在等待用户授权"*和*"这个订单上还什么都没发生"\*。仅凭状态无法区分二者。

## 我的订单卡在 `AUTHORIZATION_REQUIRED`，是用户关了 WebView 吗？

可能——但状态不会告诉你这一点，而且这不是唯一的解释。`AUTHORIZATION_REQUIRED` 意味着*没有结果返回*，与以下所有情况都吻合：

* 用户根本没打开支付页面。
* 用户打开后放弃了——关闭了 WebView、杀掉了应用、走开了。
* 用户还在页面上，认证进行中。
* 支付尝试尚未发起。

所以它不是诊断，尤其**不是**你应该向用户报告的失败证据。所有情况下的正确处理都一样：保持打开，让订单到达其过期时间，从 Webhook 或 Order Inquiry 取结果。不要自己用定时器关闭它——见[超时与结果何时终态](/docs/zh/support/payment-timeout-and-finality-faq)。

如果在运营上你确实需要知道页面是否被打开过，那是你自己前端埋点要回答的问题，不是订单状态。

## 哪些状态是终态，我能把它存为业务结果吗？

两个状态是终态：**`PAY_SUCCESS`** 和 **`ORDER_CLOSE`**。其他都是过渡态，处于过渡态的订单仍可能变化。

`PAY_SUCCESS` 和 `ORDER_CLOSE` 不会互相翻转。订单一旦关闭，支付方式之后传来的成功报告**不会**重新打开它，也**不会**把它改写为 `PAY_SUCCESS`；一旦成功，就保持成功。所以是的——你可以把终态持久化为你的业务结果。

唯一*不*安全的持久化假设是：终态意味着**资金**不会再有任何变化。成功的订单之后仍可能被退款或发生争议，而这两者都不改变 `orderStatus`——见下文的退款问题。

## 订单在每个状态下我能做什么？

| 状态 | 取消 | 请款 | 退款 |
| - | - | - | - |
| 前置状态 / 尚无支付尝试 | 可以 | 不可以 | 不可以 |
| `PAY_IN_PROGRESS` | 可以 | 不可以 | 不可以 |
| `AUTHORIZATION_REQUIRED` | 可以 | 不可以 | 不可以 |
| `AUTHED_WAITING_CAPTURE` | 可以 | **可以** | 不可以 |
| `CAPTURE_IN_PROGRESS` | 不可以 | 可以（幂等重复） | 不可以 |
| `PAY_SUCCESS` | 不可以——`A0013` | 不可以 | **可以** |
| `ORDER_CLOSE` | 可以，作为空操作 | 不可以 | 不可以 |

仔细读这两个边界，因为集成往往在这里出错：

* \*\*只有 `PAY_SUCCESS` 才能退款。\*\*不存在"退款一个待支付订单"——如果钱还没到，你要的操作是取消。
* **取消是释放你不打算请款的授权的方式**，而且它实质上优于先授权、请款再退款。

## 我调用了取消但被拒绝，这些错误是什么意思？

| 情况 | 错误码 |
| - | - |
| 支付已经成功 | `A0013` Order cannot be cancelled due to payment already success |
| 支付方式不支持取消 | `A0015` Order cannot be cancelled due to payment channel not supported |
| 支付方式拒绝了取消 | `A0016` Order cannot be cancelled due to payment channel rejection |
| 订单处于不可取消的状态 | Order status is invalid to proceed |
| 订单不存在，或 id 不匹配 | Order not found / id mismatch |
| 两个取消调用同时发生 | 并发错误——重试 |

各自如何处理：

* \*\*`A0013` 不是可以重试的错误。\*\*用户已付款。如果你不想履约，操作是退款，不是取消。
* **`A0015` 是关于支付方式的事实**，不是关于你的请求。有些方式根本没有取消操作；对于这些方式，未支付订单的结束方式是过期。请为"取消可能不可用"做设计，让过期机制来完成。
* \*\*`A0016` 来自支付方式一侧。\*\*重试一次或许值得，但如果重复出现，请停止并让订单过期。
* **取消一个已关闭的订单会成功**且什么都不做。这使取消可以安全地从清理任务中调用，无需先检查状态。

你可以发送 `paymentRequestId` 或 `acquiringOrderId` 来标识订单，加上你的 `merchantId`；两个 id 都不发是校验失败。

## 取消之后，用户还能在支付方式的页面上付款吗？

取消把订单置为 `ORDER_CLOSE`——一个终态——并请求支付方式也取消其一侧。从那一刻起订单无法完成：之后到达的成功报告不会被应用，所以订单不会在你背后悄悄变成已支付订单。

取消无法保证的是**已经打开在用户面前的第三方支付页面**停止接受输入。在支付方式完全不支持取消的情况下（`A0015`），从定义上讲他们那边什么都没被取消。所以对"用户还能付款吗"的诚实回答是：\*他们可能仍能交出钱，而它不会成为已完成的订单。\*在那个窗口内流动的资金是回收场景，不是履约场景——处理方式见[超时与结果何时终态](/docs/zh/support/payment-timeout-and-finality-faq)。

实用规则：在你决定不卖时取消，不要把取消当成关闭用户仍在查看的收银台的手段。

## "设一个短过期时间，到期后取消"是好的设计吗？

是合理的设计，但有一处修正和一处提醒。

* \*\*修正：\*\*你不需要取消调用。到达过期时间仍未支付的订单会替你关闭，并通知你。之后加上你自己的取消无害——对已关闭订单是空操作——但它不是让订单结束的原因。
* \*\*提醒：\*\*短过期时间不会缩短支付方式自己的窗口，也不会阻止他们那边收取迟到的付款。所以三分钟的过期时间给你的是三分钟的*收银台*，而不是三分钟后不会有资金流动的保证。

如果你的业务确实需要一个真正短的窗口，设置过期时间**并**构建迟付回收路径。如果只需要让收银台不再显示为可用，过期时间本身就足够。

## 订单会精确在我设置的过期时间关闭吗？

接近，但不精确到秒。关闭由周期性扫描执行，因此订单在名义过期时间之后可能仍在技术上短暂保持打开，高并发下一批到期订单可能溢出到下一轮。关闭之前会检查支付方式，已有支付进行中的订单会被放过，而不是在支付底下被关闭。

这对你意味着：

* \*\*不要把"订单已关闭"当时钟用。\*\*如果你的履约逻辑需要截止时间，用你自己的计时器对照你发送的过期时间；用订单状态了解*结果*，而不是*时间*。
* \*\*不要把略微迟到的关闭当作事故。\*\*这就是设计。
* \*\*过去的过期时间不会被拒绝——而是被丢弃。\*\*如果创建订单时 `orderExpiredAt` 已经落后于时钟，该值会被丢弃，订单改用支付方式的默认过期时间。所以你这边的时钟 bug 不会大声失败；它会产生一个比你预期保持打开更久的订单。发送前请检查时间戳。

如果你完全不发送 `orderExpiredAt`，订单最终仍会被关闭，但该时间不是你设置的值，也不应依赖它。只要窗口对你的业务重要，就发送明确的过期时间。

## 订单因超时关闭时我会收到通知吗？

会。关闭的订单产生普通的支付通知——`PAYMENT_NOTIFICATION`，携带与 Order Inquiry 相同的订单结构，`orderStatus` = `ORDER_CLOSE`，原因在 `orderFailedReason` 中。没有单独的"订单已过期"事件类型可订阅，也没有额外需要启用的东西。

所以一个处理 `PAYMENT_NOTIFICATION` 并按 `orderStatus` 分支的集成已经处理了超时关闭。如果你没有收到，那是 Webhook 投递问题——见 [Portal Webhook 日志](/docs/zh/support/portal-webhook-log-faq)和 [Webhook 重试](/docs/zh/developer-docs/webhook/retry)。

## 我能在错误码表里查 `orderFailedReason.orderFailedCode` 吗？

**不能——那是另一套码。**`Axxxx` 码是你的*请求*有误或被拒绝时 API 调用同步返回给你的。`orderFailedReason` 里的码描述的是*订单*为什么以那种方式结束，是一个独立的、面向原因的命名空间。在一方的表里查另一方的码，正是商户得出"该码不存在"结论的原因。

| 你手上的 | 它是 | 去哪里查 |
| - | - | - |
| API 响应上的 `code` / `msg` | API 错误码 | [错误码](/docs/zh/developer-docs/tools-and-references/developer-tools/error-codes)、[API 参考表](/docs/zh/support/api-reference-tables) |
| 已关闭或失败订单上的 `orderFailedReason.orderFailedCode` | 订单失败原因 | 随之返回的 `orderFailedDescription`，以及 Portal → Transactions → 该订单的 Order Failure Description |

能基于它做自动化吗？部分可以，且要谨慎：

* **要**基于你可以依赖的粗粒度区分做分支——超时关闭与支付拒绝是不同的业务事件，二者又都与取消不同。
* **要**始终把 `orderFailedDescription` 与码一起存储，因为当一个你从未见过的码到来时，它是仍然可读的部分。
* **不要**构建把未识别原因视为你自己代码失败的穷举 switch。这个集合比你测试时见到的那几个大，而且随着支付方式变化会出现新原因。默认处理为"已关闭、未支付、原因已记录"，并提醒人工处理而不是猜测。

有两种不同的超时原因——一种是订单从未到达支付方式，一种是到达了——[确认支付结果](/docs/zh/support/payment-results-faq)解释了实际区别。

## 我能请款少于授权金额吗？

可以。请款金额可以是**大于零且不超过授权金额的任意值**；授权的剩余部分会被释放而不是继续冻结。请款超过授权金额会被拒绝。

| 你发送的 | 结果 |
| - | - |
| 少于授权金额 | 请款成功；其余释放 |
| 恰好等于授权金额 | 请款成功 |
| 多于授权金额 | 拒绝——该金额不支持请款 |
| 第二次请款，金额与第一次相同 | 幂等：返回原始结果 |
| 第二次请款，金额**不同** | 以幂等不匹配拒绝（`A0011`） |
| 对不处于已授权状态的订单请款 | 拒绝——当前状态不允许请款 |
| 对从未设为手动请款的订单请款 | 拒绝——该订单不支持请款 |

最后一行是让人意外的那一个。请款只存在于**以手动请款模式**创建的订单——你在创建订单时通过 `paymentInfo.captureMode` 选择加入，那里唯一接受的值是 `manualCapture`。普通订单会自动请款，你无需调用任何东西。

已发布的产品行为与代码在最关键的一点上一致：请款实际上是**单次**的——一旦请款，即便是部分请款，授权的其余部分就会释放，因此你无法分期提取一笔授权。对于按用量计费，模式是存储 token 加周期性扣款，而不是重复请款。见 [Auth-Capture](/docs/zh/essentials/auth-capture) 和 [Tokenization](/docs/zh/support/tokenization-faq)。

## 我有多长时间可以请款？

窗口从**订单创建时**起按整天计算，而不是从你注意到授权时。它是单一的平台级设置，对每个商户一视同仁——不按账户协商，拒绝消息的措辞也不是当前数值的可靠指引。在围绕它设计履约流程之前，请向支持确认该窗口。

窗口过后会发生两件事，你应该为两者都做好准备：

* \*\*你的请款调用开始失败。\*\*它以不支持被拒绝，而不是排队。
* \*\*授权会替你释放。\*\*过期的授权会被主动取消，因此客户的资金不会因为你忘了而一直被冻结。

所以授权不是你可以无限期持有的承诺，请款也不是可以无截止时间地放在重试队列里的东西。如果你的履约可能比请款窗口更长，在发货时而不是送达时请款，或者使用存储的 token，在准备好时扣款。

## 为什么我有些订单上的 `refundExpiryAt` 是空的？

`refundExpiryAt` 是订单不再能退款的时点。它由**你协议中该支付方式的退款窗口**推导而来，从订单的**创建日期**起算——不是从支付成功那一刻——并落在那一天的结束。

两个后果：

* 以天表示的窗口是**日历**窗口。当天晚些时候创建的订单，可用窗口比早些时候创建的略短，因为边界无论如何都是一天的结束。
* 时钟不会在支付成功时重新开始。一个在创建后很久才支付的订单，已经用掉了部分退款窗口。

在所有该问题不适用的情况下，它为空——`null`：

| 何时为 null | 原因 |
| - | - |
| 订单未成功 | 没有可退的 |
| 该协议不允许退款 | 没有窗口可表达 |
| 该协议未配置退款窗口 | 同上 |

所以不要把缺失的 `refundExpiryAt` 读成"永远可退"。把它读成"该订单没有公布截止时间"，查看[按支付方式的退款限制](/docs/zh/support/payment-method-refund-limits-faq)了解适用规则，并用退款 API 上的 `remainingRefundAmount` 决定还有多少可退。

## 退款会改变原订单的状态吗？

不会——这是这个接口上最常见的误报。退款永远不会改写 `orderStatus`；全额退款的订单仍然报告 `PAY_SUCCESS`。退款进度在退款记录和订单单独的退款状态字段上，而不是支付状态上。

如果你的账务用 `orderStatus` 作为退款状态的键，它会看起来永远卡住。请改用退款记录作为键——[按支付方式的退款限制](/docs/zh/support/payment-method-refund-limits-faq)列出了每个问题该看哪里。

***

卡在一个不动的状态上？请[联系支持](mailto:support@waffo.com)，附上 `acquiringOrderId` 和你看到的状态。


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