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

# 限额、币种与配置类错误

> 其他页面未覆盖的下单拒绝原因：A0008 / A0020 / A0021 三种金额限额的区别，为什么未签约币种返回 A0018 而不是 A0007，A0026 / A0047 收银台语言，A0024 汇率过期（不是 A0023），A0014 跨币种退款换算后归零，A0022 支付方式指向多个产品——以及为什么限额不随汇率变动、为什么 Portal 里可能没有结算菜单、Sandbox 与生产环境的可用性差异，和周期扣款的相关规则。

[常见错误排查](/docs/zh/support/errors-troubleshooting-guide) 覆盖了产生工单最多的几个错误码：`A0001`、`A0002`、`A0003`、`A0018` 以及 `E`xxxxx 系列。本页覆盖其余的下单拒绝原因——限额、币种、语言、汇率与配置——然后再讲那些同样会产生「为什么我不能……」工单、但根本不会返回错误码的配置问题。

## 三个错误码分别对应哪种限额？

它们是三个不同层级的上限，在不同层级校验。把它们当成同一回事，是商户「修错了配置」的常见原因。

| 错误码 | 报错信息 | 含义 | 限额所在位置 |
| - | - | - | - |
| `A0008` | Payment amount should be within the range | 订单金额超出该币种下**支付方式**的最小/最大范围 | 支付方式配置 |
| `A0020` | Payment amount exceeds transaction limit | **单笔订单**超过你账户在该订单币种下的单笔交易限额 | 账户级限额，按订单币种 |
| `A0021` | Accumulative payment amount exceeds daily transaction limit | 本笔订单**加上今天在该订单币种下已发生的全部交易**超过了日累计上限 | 账户级限额，按订单币种 |

由此可以得出三点：

* `A0020` 和 `A0021` 是**按订单币种**计算的。调高一个币种的限额对另一个币种没有任何作用。
* `A0021` 取决于今天已经发生的交易量，所以同一个请求可能早上成功、晚上失败。立即重试没有用；第二天重试才有用。
* `A0008` 是支付方式的金额范围，不是账户限额。在哪里查看这些范围见[常见错误排查](/docs/zh/support/errors-troubleshooting-guide)。

如果任一账户级限额对你的业务来说设得太低，这属于配置变更——请联系你的 Waffo 对接人。

## 我传了一个没签约的币种，会返回 `A0007` 吗？

不会——你会收到 **`A0018`** *"Payment method in merchant order does not match with current merchant contract"*。普通下单路径上没有针对币种的专门拒绝：合约查找是按你的商户 ID **和**订单币种一起匹配的，所以一个你所有协议都不包含的币种，只会导致找不到任何可匹配的协议，失败就被报为支付方式不匹配。报错信息有误导性；真正的原因是币种。

`A0007` *"Transaction currency is not supported"* 在错误码表里确实存在，但它专门用于一条只接受单一结算币种的特殊稳定币协议支付路径。如果你在创建普通订单时遇到币种问题，你要排查的错误码是 `A0018`。

| 现象 | 错误码 |
| - | - |
| 订单币种未签约 | `A0018` |
| 支付方式，或 `orderCurrency` → `userCurrency` 币种对未签约 | `A0018` |
| 金额超出签约范围 | `A0008` |

`/api/v1/paymethodconfig/inquiry` 会为每份合约返回一条记录，各自带有自己的 `currency`——在构造请求前，先按你打算收款的币种去匹配。各种因币种而触发 `A0018` 的情形，在[币种需要单独开通吗？](/docs/zh/support/currency-and-method-enablement-faq)中有逐条说明。

## `A0026` 和 `A0047`——我的 `cashierLanguage` 到底哪里错了？

它们区分的是「你要的语言我们没有」和「这不是一个合法的语言标签」。

| 错误码 | 含义 | 常见原因 |
| - | - | - |
| `A0026` | 指定的收银台语言不受支持 | 标签格式合法，但是 Waffo 不提供的语言 |
| `A0047` | 收银台语言格式无效 | 语法错误，或带了多余的子标签 |

取值必须是 IETF BCP 47 标签，形式为 `language[-script][-region]`：

* **language**——两位 ISO 639-1 代码，且必须是 Waffo 支持的语言。传别的值不能扩展受支持的语言集合。
* **script**——可选，四个字母（ISO 15924）。如果带了，必须是 Waffo 使用的文字；目前在用的是 `Hant` 和 `Hans`。
* **region**——可选，两位 ISO 3166-1 alpha-2 代码。这里接受任何合法的国家代码；地区不限于某个支持列表。

其他任何写法都是 `A0047`：用下划线代替连字符（`en_US`）、变体子标签（`de-DE-1996`）、私有扩展（`en-US-x-foo`）都会被当作格式错误拒绝，而不是不支持。大小写不算错误——`en-us` 会被规范化为 `en-US`。

## 跨币种订单因为汇率被拒了，是哪个错误码？

**`A0024`**——"Order can not be processed due to the fx rate is expired."

> [!WARNING]
>
> 错误码是 `A0024`，不是 `A0023`。`A0023` 是 **"Order cannot be created due to expired token"**——这是完全不同的失败，关于卡 token，修复方式也完全不同。如果你的集成笔记里把汇率过期或汇率变差映射到了 `A0023`，那是错的，请更正。

跨币种订单在创建时会校验报价汇率。如果报价已不再有效——已过期，或当前汇率相对报价发生了不利变动——订单会被**直接拒绝**。Waffo 不会悄悄按新汇率重新定价，因为那会在你已承诺价格之后改变用户实际支付的金额。

应对方式：

1. 把 `A0024` 当作可重试错误。重新创建订单，它会取到当前报价。
2. 不要把一个报价带过很长的下单流程。从报价到创建订单之间的间隔越长，遇到这个错误的频率就越高。
3. 如果你的界面在创建订单前展示了本地币种金额，请向用户展示刷新后的金额。

汇率如何报价、有效期多长，见[支付与结算中的汇率](/docs/zh/support/exchange-rates-faq)。

## `A0023` 和 `A0024` 的区别，有没有一段可以直接贴进代码注释的总结？

| 错误码 | 报错信息 | 对象 | 修复 |
| - | - | - | - |
| `A0023` | Order cannot be created due to expired token | 卡 `tokenId` 已不可用 | 重新绑卡 token 化；见[Token 化与卡支付](/docs/zh/support/tokenization-faq) |
| `A0024` | Order can not be processed due to the fx rate is expired | 跨币种订单上的汇率报价 | 重新创建订单以获取当前汇率 |

## 我的跨币种部分退款被 `A0014` 拒了，但金额看起来没问题

请检查**换算之后**的金额。跨币种订单上，你传的退款金额会先换算再校验，如果换算后的金额为**零或更小**，退款就会被 `A0014`（"Order cannot be refunded due to refund rules"）拒绝。

这在两种情况下容易发生：

* 在汇率差距很大的币种对上做很小额的部分退款——换算后金额向下取整为零。
* 币种的最小单位位数比你预想的少，换算后金额被截断成零。

注意 `A0014` **不**覆盖的情形：申请的金额超过剩余可退金额。如果一笔退款的金额加上已退款和退款中的全部金额超过了原支付金额，会被当作普通参数错误拒绝——`A0003 Parameter validation failed`——而不是违反退款规则。所以在跨币种订单上，把 `A0014` 理解为「换算后的金额没有通过退款规则」，把 `A0003` 理解为「你要的太多了」；两种情况都要看换算后的数字，而不是你传的数字。换算规则见[汇率](/docs/zh/support/exchange-rates-faq)；各支付方式的退款规则见[各支付方式的退款限制](/docs/zh/support/payment-method-refund-limits-faq)。

## `A0022` "multiple products are found"——我应该指定什么？

指定产品。`A0022` 表示你请求的支付方式在你的账户上解析到了**多于一个已签约产品**——例如同一支付方式既签了一次性支付又签了订阅。Waffo 不会猜你想要哪一个，所以订单会被拒绝，而不是错挂到另一个产品下创建。

修复方法是在 `paymentInfo` 中传 `productName`，使恰好只有一份合约匹配。参数组合见[收银台定制](/docs/zh/developer-docs/integration/checkout/customization)，包括 `payMethodType`、`payMethodName` 和 `payMethodCountry` 如何缩小匹配范围。

## 汇率变动时，我签约的金额限额会跟着变吗？

不会。你合约上的订单最小/最大金额是**固定值**。它们在支付方式为你的账户签约时计算一次，之后不随汇率变动——跨币种订单也一样。

两个值得了解的细节：

* 当你的定价币种与支付方式自身的币种不同时，上下限在签约时换算一次后就固定下来：最小值按该币种的最小单位**向下**取整（但不会取到零——下限是一个最小单位），最大值**向上**取整。
* 你为账户申请的限额必须落在系统计算出的范围**之内**。你的范围是它的子集，不会更宽。如果你申请了更宽的范围，配置会被拒绝，而不是被截断到边界。

所以汇率变动永远不是金额被拒的原因。如果一个金额以前能过现在不能过，请去看账户级日限额（`A0021`）或配置变更，而不是汇率。在哪里查看这些值见[常见错误排查](/docs/zh/support/errors-troubleshooting-guide)。

## 支付因为限额失败了，但不是我的限额，那是什么？

某些钱包类支付方式会对**用户自己的钱包**施加限额——最常见的是用户通过该钱包每年可消费的上限。用户触顶时支付会失败，你和 Waffo 都没有任何配置可以放行。

处理方式：

* 向用户展示中性提示并提供其他支付方式，而不是重试同一个。
* 不要把这些失败计入你自己的限额或集成健康度；它们是用户侧的。
* 不要试图把订单拆成多笔小额支付来绕过上限——年度上限不是拆单能规避的，而且会损害用户体验。

## 为什么我的 Portal 里看不到结算、手续费或结算周期？

取决于你签了什么。商户 Portal 的部分内容由你签约的产品决定，而不是由角色决定——Admin 也无法授予。菜单级别的对照表见[商户 Portal 操作](/docs/zh/support/portal-operations-faq)。

除了菜单之外，处于**纯网关**模式的商户——即签约产品只有 Direct Payment、没有其他——还会少掉与结算相关的**列**：

| 位置 | 隐藏内容 |
| - | - |
| PayIn（支付方式配置） | `Fees` 和 `Settlement Cycle` 列 |
| 退款列表 | `Settlement Status` 列 |
| 导航 | Settlements、Balance、Withdrawal 及相关子菜单 |

这是预期行为而不是缺陷：没有结算产品，就没有结算周期、没有可展示的费率表、也没有可报告的结算状态。这些都无法从你这边切换。订单和退款数据、导出和Webhook 通知不受影响。

如果你预期能看到结算数据却看不到，该问支持的问题是「我的账户签约了哪些产品」，而不是「请给我开通这个菜单」。

## 某个支付方式在 Sandbox 能用，到生产环境却失败

这是设计如此，也是 Sandbox 差异中最让人意外的一点。**Sandbox 有意包含了生产环境中尚未上线的支付方式和配置**，以便在某个支付方式正式开放真实流量之前就能开始集成和端到端测试。

所以：

* **Sandbox 可用不代表生产环境可用。**
* 请根据你的合约确认生产环境覆盖范围——看 Portal 的 PayIn 页面，或对生产环境调用 `/api/v1/paymethodconfig/inquiry`——而不是根据 Sandbox 的表现。
* 一个在 Sandbox 能用、在生产环境返回 `A0018` 的支付方式，通常就是这个原因，而不是集成 bug。

其他 Sandbox 与生产环境的差异见[Sandbox 测试](/docs/zh/support/sandbox-testing-faq)。

## 用户如何授权微信支付的周期扣款？

通过两种流程之一，取决于用户所在的环境：

| 用户环境 | 签约流程 |
| - | - |
| 桌面网页 | 用户扫码授权 |
| 手机浏览器 | 用户在 H5 页面授权 |

授权建立后，Waffo 会据此发起周期扣款，无需用户再次操作；用户或你都可以终止授权，已扣款的订单可以全额或部分退款。订阅本身的机制——套餐变更、扣款失败、重试、通知——见[订阅 FAQ](/docs/zh/support/subscription-faq)。

只存在上述两种流程。如果你参照的设计文档还列了 App 内、小程序或客户端内授权，那些并不可用。

## 首期支付退款会不会让整个周期扣款系列终止？

会，对卡类周期扣款系列是这样，而且这是几个月后最容易让你意外的失败模式。

| 系列的首期支付发生了什么 | 对系列的影响 |
| - | - |
| **全额退款** | 系列**终止**——不能再据此发起后续周期扣款 |
| 被欺诈或争议交易引用 | 系列**终止** |
| **部分退款** | 无影响——系列继续 |

所以客服对首期扣款做一次全额退款，会在支付层面悄悄结束客户的订阅，即便你自己的记录里它仍显示为有效。两条防护措施：

1. 在补偿金额允许的情况下，优先做部分退款。
2. 如果确实要对首期扣款全额退款，把该系列视为已结束；客户如果继续留存，需重新建立授权。

## 我需要告诉收银台用户用的是什么设备吗？

不需要。Waffo 收银台会自行检测用户设备并选择展示方式：

| 用户设备 | 收银台的行为 |
| - | - |
| 手机浏览器 | 跳转到支付 App 或支付页面 |
| 桌面浏览器 | 渲染二维码供用户扫码 |

你不需要为此传任何设备、终端或认证模式参数——没有什么会出错，也没有什么需要在支付方式行为变化时同步。部分基于 App 的钱包支付方式在移动端还会更进一步：收银台要么直接深度链接到用户选择的那个 App，要么交给操作系统的 App 选择器。

你*能*控制的是哪些支付方式会出现——见[收银台定制](/docs/zh/developer-docs/integration/checkout/customization)和[收银台展示规则](/docs/zh/support/cashier-display-rules-faq)。

## 我没有 token 化就用卡扣款了，以后还能再扣这张卡吗？

不能。不带 `tokenId` 的卡支付是一笔**一次性的用户发起交易**。不会保留任何可以让你再次扣这张卡的信息，所以这笔支付不具备商户发起的后续扣款能力。

要以后再扣同一张卡，必须先 token 化：完成 token 化流程、持有一个有效的 `tokenId`，并在后续扣款中引用该 token。已完成的普通卡支付无法事后转成 token——用户必须走一遍绑卡。

完整的 token 生命周期、CIT/MIT 区别以及 `AUTHORIZATION_REQUIRED` 情形，见[Token 化与卡支付](/docs/zh/support/tokenization-faq)。

## 接下来该看哪里？

| 问题 | 页面 |
| - | - |
| `A0001`、`A0002`、`A0003`、`A0018`、`E`xxxxx、Webhook 通知重试 | [常见错误排查](/docs/zh/support/errors-troubleshooting-guide) |
| 跨币种订单使用哪个汇率、有效多久 | [支付与结算中的汇率](/docs/zh/support/exchange-rates-faq) |
| `A0017` 和 `A0014` 背后各支付方式的退款规则 | [各支付方式的退款限制](/docs/zh/support/payment-method-refund-limits-faq) |
| Portal 菜单、角色，以及为什么不同商户看到的不一样 | [商户 Portal 操作](/docs/zh/support/portal-operations-faq) |
| Sandbox 凭据、模拟器和测试卡 | [Sandbox 测试](/docs/zh/support/sandbox-testing-faq) |
| Token、CIT 与 MIT | [Token 化与卡支付](/docs/zh/support/tokenization-faq) |


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