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

# 读懂您的支付方式配置

> 如何以编程方式发现您的账户可以使用哪些支付方式：支付方式配置响应上的每个字段、为什么 currentStatus 可能返回为空、四个 refundAllowed 编码的含义、点名您商户 ID 或 notifyUrl 的参数错误，以及发生变化的导出列和列表筛选。

本页讲的是 **API 契约**：如何从代码读取您的支付方式
配置，以及配置字段有误时返回的请求级
错误。

三个相邻页面从其他角度覆盖同一主题，本页
不重复它们：

* [Payin 协议与交易限额](/docs/zh/support/payin-agreements-and-limits-faq)——
  Portal 在 **Service → Payin** 渲染的同一份配置：每一
  列、费用标注、协议状态、筛选和导出。
* [限额、币种与配置错误](/docs/zh/support/error-codes-and-limits-supplement)——
  `A0008` / `A0020` / `A0021` 各指哪个限额，以及每日
  上限如何计数。
* [条件与必填字段](/docs/zh/support/conditional-required-fields-faq)——
  哪些创建订单字段对哪类支付方式变为必填。

## 我怎么从代码得知我的账户能用哪些支付方式？

调用 `/api/v1/paymethodconfig/inquiry`。它接受一个有意义的字段：

| 字段 | 必填 | 说明 |
| - | - | - |
| `merchantId` | 是 | 必须与您签名所用 API key 所属的商户 ID 相同——见[下文的商户 ID 错误](#i-got-a-parameter-error-that-mentions-my-merchant-id-what-is-wrong) |

响应是您的商户 ID 加 `payMethodDetails`，一个数组，**您账户上
当前生效的每个支付方式合同对应一个条目**。

请把该接口当作您自己集成逻辑的事实来源——
提供哪些方式、接受哪些币种、创建订单前按什么金额范围
校验——而不是硬编码一份您曾从规范复制的
列表。

## 响应中每个字段是什么意思？

| 字段 | 含义 |
| - | - |
| `productName` | 合同所属的 Payin 产品：`ONE_TIME_PAYMENT`、`DIRECT_PAYMENT`、`SUBSCRIPTION` 或 `MINI_PROGRAM_PAYMENT` |
| `payMethodName` | 支付方式的名称，与您在创建订单时回传的拼写一致 |
| `country` | 支付方式的国家，三字母代码。两个值不是国家：`EU_LIST` 代表一组欧洲市场，`GLB` 代表不绑定市场的方式 |
| `payMethodType` | 该方式所属的类别，例如 `EWALLET`、`CREDITCARD`、`ONLINE_BANKING`——[完整枚举](/docs/zh/support/payment-method-coverage-faq#what-are-the-paymethodtype-categories) |
| `currency` | 该合同支持的币种，ISO 4217 代码 |
| `orderAmountMin` / `orderAmountMax` | 该合同接受的订单金额范围，十进制字符串 |
| `refundAllowed` | 该方式允许的退款形态——[四个编码，见下文](#what-do-the-four-refundallowed-values-mean) |
| `currentStatus` | 实时可用性：`1` 可用，`0` 不可用。**可能为空**——见下文 |
| `fixedMaintenanceRules` | 计划内不可用窗口，成对的 cron 表达式 |
| `fixedMaintenanceTimezone` | 评估维护 cron 表达式所用的时区，例如 `UTC+08:00` |

两条值得从一开始就纳入的解析规则：

* \*\*金额是字符串，不是数字。\*\*按十进制解析；不要让
  JSON 库把它们变成浮点数。
* \*\*`orderAmountMin` / `orderAmountMax` 可能缺失。\*\*合同没有
  配置范围时，该字段就不填充，该合同也不适用
  金额范围检查。

## 为什么同一个支付方式出现多次？

因为数组以**合同**为键，不是以支付方式为键。每个生效合同
产生一个条目，而一个支付方式合理地可以
处于多个合同下：每币种一个，或每个 Payin 产品一个。

所以 `payMethodName` 在此响应中**不是**唯一键。如果您在构建
查找表，请以您实际需要的组合为键——通常是
`payMethodName` + `currency`，或 `productName` + `payMethodName` + `currency`。

响应中没有任何内容会为您去重。

## `currentStatus` 返回为空，支付方式挂了吗？

不——空的 `currentStatus` 表示\*\*"目前未知"\*\*，不是"不可用"。

合同数据和实时可用性来自两个不同的地方。
合同那一半始终存在。可用性那一半单独
查询，当该查询未覆盖某合同时，该条目的 `currentStatus`、
`fixedMaintenanceRules` 和 `fixedMaintenanceTimezone` 都保持未设置，
而不是猜测。

如何处理：

| `currentStatus` | 含义 | 合理的行为 |
| - | - | - |
| `1` | 可用 | 提供该方式 |
| `0` | 目前不可用 | 隐藏该方式，或显示为暂时不可用 |
| 空 / 缺失 | 无法确定可用性 | \*\*不要当作不可用。\*\*回退到您的正常行为，让创建订单作为权威 |

最后一行最重要：把"空"读作"关闭"的客户端，会在可用性
查询出问题的那一分钟隐藏完全正常的支付方式。
"这个方式能否接受这笔支付"的权威答案
始终是创建订单的响应。

## 响应包含已结束的合同吗？

不包含。该接口背后的查询只选择处于 **`ACTIVE`
状态** *且*有效期覆盖当前时刻的合同——开始日期
在现在或之前，且结束日期在现在或之后或没有结束日期。

后果：

* 处于 `INIT`、`SUSPENDED`、`TERMINATED` 或 `ON_BOARDING` 状态的合同
  不会出现。
* 尚未开始或结束日期已过的合同不会
  出现。
* 因此支付方式从响应中消失是一个**合同**
  事件，不是可用性抖动。已签约但暂时
  不可用的方式仍留在响应中，`currentStatus` 为 `0`。

所以这两个问题在此响应中有两个不同的答案：\*"我是否
签约了它？"*看条目是否存在；*"它现在能否
收款？"\*看 `currentStatus`。不要用一个回答另一个。

Portal 显示的协议状态见
[Payin 协议与交易限额](/docs/zh/support/payin-agreements-and-limits-faq)。

## 四个 `refundAllowed` 值是什么意思？

它们描述支付方式允许的退款**形态**——不是某笔特定订单
现在能否退款。

| 编码 | 含义 | 退款调用会得到什么 |
| - | - | - |
| `0` | 该支付方式不允许退款 | 任何退款都被拒绝 |
| `1` | 仅一次全额退款 | 部分金额被拒绝；第二次退款被拒绝 |
| `21` | 一次退款，全额或部分 | 接受部分退款，但仅一次 |
| `22` | 多次退款，全额或部分 | 接受直到原金额耗尽 |

Portal 将同样四个值渲染为 *No*、*Only Full Refund*、*Full
Refund or One-time Partial Refund* 和 *Full Refund or Multiple Partial
Refunds*。

该值**不**告诉您的两件事：

* \*\*退款窗口是否仍开放。\*\*那是单独的设置；见
  [支付方式退款与限制](/docs/zh/support/payment-method-refund-limits-faq)。
* \*\*订单是否处于可退款状态。\*\*未支付或已全额
  退款的订单无论 `refundAllowed` 如何都会被拒绝。

## `fixedMaintenanceRules` 是什么？怎么读？

它们是支付方式的**计划内**不可用窗口：每条规则是
一对 cron 表达式 `startRule` 和 `endRule`，标记窗口的开始
和结束。`fixedMaintenanceTimezone` 是评估它们所用的时区
——通常不是您自己的，所以请读取它而不是假定。

典型形态：

| 开始 / 结束对 | 窗口 |
| - | - |
| `0 30 1 * * ?` / `0 30 2 * * ?` | 每天 01:30 至 02:30 |
| `0 00 23 ? * 1,2,3,4,5` / `0 59 23 ? * 1,2,3,4,5` | 工作日 23:00 至 23:59 |
| `0 00 0 1,15 * ?` / `0 59 23 1,15 * ?` | 每月 1 日和 15 日全天 |

这些是预先可知的，所以是可用性中您唯一能在 UI 里
有效预判的部分。非计划的故障则表现为 `currentStatus` 为
`0`，没有事先通知。

## 创建订单前我怎么检查金额范围？

从匹配的条目读取 `orderAmountMin` 和 `orderAmountMax`——按
支付方式**和币种**匹配，因为范围是按合同的，同一方式下的两种
币种可能有不同的范围。

客户端校验能让您的客户免于一次被拒订单，但这不是
唯一的上限。有三个独立的限额，三个独立的错误码，
而该接口只暴露第一个：

| 错误码 | 哪个上限 | 这里可读？ |
| - | - | - |
| `A0008` | 支付方式自身的金额范围 | 是——`orderAmountMin` / `orderAmountMax` |
| `A0020` | 您账户的单笔限额，按订单币种 | 否 |
| `A0021` | 您账户的每日累计限额，按订单币种 | 否 |

它们相互独立：通过支付方式的范围不能说明
账户级限额，反之亦然。完整拆解，包括每日总额如何
计数以及额度何时恢复，见
[限额、币种与配置错误](/docs/zh/support/error-codes-and-limits-supplement)。

## 我收到一个提到我商户 ID 的参数错误，怎么回事？

每个签名接口都会把您**请求体**中的 `merchantId` 与
您**签名所用 API key** 所属的商户 ID 比对。如果不一致，
请求在任何其他处理之前被拒绝，原因为
`mid in params is inconsistent with apiKey`，以 `A0003` 返回。

这有意做成一条独立信息而不是通用参数错误，
因为其两个原因与其他所有参数问题都截然不同：

| 原因 | 表现 | 修复 |
| - | - | - |
| 环境用错凭证 | 用 sandbox key 对生产商户 ID，或反过来 | 让 key 和商户 ID 匹配同一环境 |
| 子商户混淆 | 在 `merchantId` 中发送子商户的 ID | `merchantId` 是 API key 所属的 ID。子商户在自己的字段中标识——见[多品牌与子商户](/docs/zh/support/multi-brand-and-sub-merchant-faq) |
| 跨账户复制粘贴 | 一个账户的配置，另一个账户的 key | 每个账户的凭证和 ID 放在一处 |

它从不表示商户 ID 不存在，也永远不会靠
重试修复。

## 返回了 `A0003`，我怎么知道哪个字段错了？

读信息，不只是错误码。具体对 `A0003`，具体
原因**以括号附加在通用信息后**：

```
Parameter validation failed ( refundAmount must be greater than 0 )
```

括号外的部分是固定的。括号内的部分点名实际
问题——通常是出问题的字段以及对它的要求。`A0003`
以 HTTP `400` 返回。

对您错误处理的两点启示：

* \*\*记录完整信息，不只是错误码。\*\*只记 `A0003`
  的日志行丢掉了唯一能定位 bug 的部分。
* \*\*不要用程序解析括号内文本。\*\*它是写给看日志的人的。
  按错误码分支；展示文本。

`A0003` 以外的错误码返回其标准信息，不附加详情，
除非该特定失败被定义为携带额外上下文。

## 我的回调 URL 有什么规则？

`notifyUrl`——Waffo 推送支付通知的 URL——在
您配置时校验，每种失败模式有自己的错误：

| 规则 | 失败 |
| - | - |
| 最多 **512 个字符** | `notify url exceeds maximum length of 512 characters` |
| 必须以 `http://` 或 `https://` 开头 | `invalid notify url format` |
| URL 中任何位置**仅 ASCII 字符，无空白** | `invalid notify url format` |
| 必须能解析为同时带 scheme 和 host 的 URL | `invalid notify url format` |

两者都以 `A0003` 返回，具体原因如上所述
在信息中。

让人中招的是最后两条。含非 ASCII 字符的 URL
——国际化域名，或从文档粘贴的路径段——
即便浏览器能打开也会被拒绝：请先做
百分号编码。而复制时带上的一个尾部空格就足以让
空白检查失败，报错看起来却像是 URL 本身的问题。

允许 `notifyUrl` 留空；此时不运行校验，也不向其发送
任何通知。

## 我必须发送 `subscriptionManagementUrl` 吗？它最终去哪里？

它在创建订阅时**文档定义为必填**，上限
**256 个字符**——但注意创建调用目前只强制执行
长度：没有它的请求**不会被拒绝**。仍请把它当作必填，
因为在一种账户设置下（见下文）它是您客户
唯一能拿到的管理链接。它的用途，以及为什么应该是一个能在
桌面浏览器打开的页面而不是 App deeplink，见
[订阅 FAQ](/docs/zh/support/subscription-faq)。

那一页没有覆盖的是**您的客户实际收到哪个管理
链接**。那是一个有两个值的账户级设置：

| 设置 | 订阅邮件中的管理链接是 |
| - | - |
| `INTERNAL` | Waffo 托管的管理页面，按邮件生成 |
| `MERCHANT_API_URL` | 正是您创建时发送的 `subscriptionManagementUrl` |

两个后果：

* \*\*在 `MERCHANT_API_URL` 下，您的值就是链接。\*\*如果您没有发送，或
  发送的页面之后迁移了，您客户邮件中的链接就是坏的，
  没有任何东西补救。请在订阅查询中读回它以
  确认存储的值。
* \*\*在 `INTERNAL` 下，旧邮件中的链接会失效。\*\*每封新邮件
  生成新链接并使之前的失效，所以翻出上个月邮件的
  客户需要改用最新的那封。生成的
  链接本身也有时效。

无论哪种方式，管理页面都不是实时支付流程的一部分——它是
您在订阅支付成功*之后*引导客户去的地方。哪些事件
会发送邮件，见
[订阅通知](/docs/zh/support/subscription-notifications-faq)。

## 我的交易和退款导出中哪些列变了？

三处变化，其中一处容易误读：

| 列 | 位置 | 内容 |
| - | - | - |
| `Initiation Type` | 交易导出 | `CIT` 或 `MIT`——谁触发了卡交易 |
| `Pay Method Country/Region` | 交易导出 | 支付方式的国家。**替代原来的 `Country/Region` 列** |
| `Merchant Original Order ID` | **仅退款导出** | 在退款行上，您自己对原支付的订单 ID |

陷阱在第三行。`Merchant Original Order ID` 定义在共享
列集合上，但**有意从交易导出中排除**——它
只在退款行上有意义，用来区分您对退款的 ID 与
您对其所冲正支付的 ID。如果您的交易导出
解析器在找它，是找不到的。

关于 `Initiation Type`：它经常为空。原因以及什么会填充它，见
[交易与退款字段参考](/docs/zh/support/transaction-field-reference-faq)。

导出是排队的后台任务而不是即时下载——见
[导出与报表下载](/docs/zh/support/export-center-faq)。

## 我能把拒付或退款列表收窄到一个订阅或一笔订单吗？

可以，这些是人们最常错过的筛选：

| 列表 | 筛选 | 匹配 |
| - | - | - |
| 拒付 | `relatedSubscriptionId` | 源自某一订阅的所有拒付 |
| 退款 | `relatedSubscriptionId` | 源自某一订阅的所有退款 |
| 退款 | `merchantOriginalOrderId` | 按您自己对原支付的订单 ID **精确匹配** |
| 交易 | `relatedSubscriptionId` | 属于某一订阅的所有支付 |

当客户对某次购买提出争议而您只知道自己的订单引用时，
`merchantOriginalOrderId` 就是该用的：它直接从您的
订单 ID 到该支付的每一笔退款，无需先查找 Waffo 的
标识符。

注意命名。筛选是 `relatedSubscriptionId`，不是 `subscriptionId`——
"related"是因为被筛选的行是*来自*订阅的拒付、退款或支付，
不是订阅本身。要列出订阅，请改在订阅列表上按 `acqSubscriptionId` 或
`merchantSubscriptionId` 筛选。

## 客户重新打开了旧的收银台链接，他们会看到什么？

收银台链接是一个**会话**，会话不会永远持续。两个独立的
生命周期适用：

* 支付前，链接从创建起在有限期间内有效。超过后
  打开，它报告收银台已过期，而不是收款。
* 订单到达最终状态后，链接不再是支付页面，
  变为**结果**页，在完成后一段时间内可查看，之后
  不再可查看。

两个生命周期都不应作为您客户体验的基础。如果
客户需要查看已完成的购买，请从您自己的记录展示，或
给他们发送收据——见
[收据配置与下载](/docs/zh/support/receipt-configuration-and-download-faq)。
如果他们需要付款，请创建新订单而不是重发旧链接；
重新打开链接背后的订单会怎样，见
[收银台订单生命周期](/docs/zh/support/cashier-order-lifecycle-faq)。

## 接下来看哪里？

| 问题 | 页面 |
| - | - |
| Portal 中逐列展示的同一份配置 | [Payin 协议与交易限额](/docs/zh/support/payin-agreements-and-limits-faq) |
| Waffo 到底收录了什么，以及完整字段枚举 | [我能接受哪些支付方式和市场？](/docs/zh/support/payment-method-coverage-faq) |
| 每个错误码指哪个限额 | [限额、币种与配置错误](/docs/zh/support/error-codes-and-limits-supplement) |
| 某支付方式需要哪些订单字段 | [条件与必填字段](/docs/zh/support/conditional-required-fields-faq) |
| 退款窗口和各方式退款行为 | [支付方式退款与限制](/docs/zh/support/payment-method-refund-limits-faq) |
| 请求签名，以及签名的商户 ID 是什么 | [认证与签名](/docs/zh/support/auth-signature-faq) |
| 通知投递、重试和重发 | [Webhook 通知事件与重发](/docs/zh/support/webhook-events-and-resend-faq) |
| 子商户标识 | [多品牌与子商户](/docs/zh/support/multi-brand-and-sub-merchant-faq) |


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