- Payin 协议与交易限额—— Portal 在 Service → Payin 渲染的同一份配置:每一 列、费用标注、协议状态、筛选和导出。
- 限额、币种与配置错误——
A0008/A0020/A0021各指哪个限额,以及每日 上限如何计数。 - 条件与必填字段—— 哪些创建订单字段对哪类支付方式变为必填。
我怎么从代码得知我的账户能用哪些支付方式?
调用/api/v1/paymethodconfig/inquiry。它接受一个有意义的字段:
响应是您的商户 ID 加
payMethodDetails,一个数组,您账户上
当前生效的每个支付方式合同对应一个条目。
请把该接口当作您自己集成逻辑的事实来源——
提供哪些方式、接受哪些币种、创建订单前按什么金额范围
校验——而不是硬编码一份您曾从规范复制的
列表。
响应中每个字段是什么意思?
两条值得从一开始就纳入的解析规则:
- **金额是字符串,不是数字。**按十进制解析;不要让 JSON 库把它们变成浮点数。
- **
orderAmountMin/orderAmountMax可能缺失。**合同没有 配置范围时,该字段就不填充,该合同也不适用 金额范围检查。
为什么同一个支付方式出现多次?
因为数组以合同为键,不是以支付方式为键。每个生效合同 产生一个条目,而一个支付方式合理地可以 处于多个合同下:每币种一个,或每个 Payin 产品一个。 所以payMethodName 在此响应中不是唯一键。如果您在构建
查找表,请以您实际需要的组合为键——通常是
payMethodName + currency,或 productName + payMethodName + currency。
响应中没有任何内容会为您去重。
currentStatus 返回为空,支付方式挂了吗?
不——空的 currentStatus 表示**“目前未知”**,不是”不可用”。
合同数据和实时可用性来自两个不同的地方。
合同那一半始终存在。可用性那一半单独
查询,当该查询未覆盖某合同时,该条目的 currentStatus、
fixedMaintenanceRules 和 fixedMaintenanceTimezone 都保持未设置,
而不是猜测。
如何处理:
最后一行最重要:把”空”读作”关闭”的客户端,会在可用性
查询出问题的那一分钟隐藏完全正常的支付方式。
“这个方式能否接受这笔支付”的权威答案
始终是创建订单的响应。
响应包含已结束的合同吗?
不包含。该接口背后的查询只选择处于ACTIVE
状态 且有效期覆盖当前时刻的合同——开始日期
在现在或之前,且结束日期在现在或之后或没有结束日期。
后果:
- 处于
INIT、SUSPENDED、TERMINATED或ON_BOARDING状态的合同 不会出现。 - 尚未开始或结束日期已过的合同不会 出现。
- 因此支付方式从响应中消失是一个合同
事件,不是可用性抖动。已签约但暂时
不可用的方式仍留在响应中,
currentStatus为0。
currentStatus。不要用一个回答另一个。
Portal 显示的协议状态见
Payin 协议与交易限额。
四个 refundAllowed 值是什么意思?
它们描述支付方式允许的退款形态——不是某笔特定订单
现在能否退款。
Portal 将同样四个值渲染为 No、Only Full Refund、Full
Refund or One-time Partial Refund 和 Full Refund or Multiple Partial
Refunds。
该值不告诉您的两件事:
- **退款窗口是否仍开放。**那是单独的设置;见 支付方式退款与限制。
- **订单是否处于可退款状态。**未支付或已全额
退款的订单无论
refundAllowed如何都会被拒绝。
fixedMaintenanceRules 是什么?怎么读?
它们是支付方式的计划内不可用窗口:每条规则是
一对 cron 表达式 startRule 和 endRule,标记窗口的开始
和结束。fixedMaintenanceTimezone 是评估它们所用的时区
——通常不是您自己的,所以请读取它而不是假定。
典型形态:
这些是预先可知的,所以是可用性中您唯一能在 UI 里
有效预判的部分。非计划的故障则表现为
currentStatus 为
0,没有事先通知。
创建订单前我怎么检查金额范围?
从匹配的条目读取orderAmountMin 和 orderAmountMax——按
支付方式和币种匹配,因为范围是按合同的,同一方式下的两种
币种可能有不同的范围。
客户端校验能让您的客户免于一次被拒订单,但这不是
唯一的上限。有三个独立的限额,三个独立的错误码,
而该接口只暴露第一个:
它们相互独立:通过支付方式的范围不能说明
账户级限额,反之亦然。完整拆解,包括每日总额如何
计数以及额度何时恢复,见
限额、币种与配置错误。
我收到一个提到我商户 ID 的参数错误,怎么回事?
每个签名接口都会把您请求体中的merchantId 与
您签名所用 API key 所属的商户 ID 比对。如果不一致,
请求在任何其他处理之前被拒绝,原因为
mid in params is inconsistent with apiKey,以 A0003 返回。
这有意做成一条独立信息而不是通用参数错误,
因为其两个原因与其他所有参数问题都截然不同:
它从不表示商户 ID 不存在,也永远不会靠
重试修复。
返回了 A0003,我怎么知道哪个字段错了?
读信息,不只是错误码。具体对 A0003,具体
原因以括号附加在通用信息后:
A0003
以 HTTP 400 返回。
对您错误处理的两点启示:
- **记录完整信息,不只是错误码。**只记
A0003的日志行丢掉了唯一能定位 bug 的部分。 - **不要用程序解析括号内文本。**它是写给看日志的人的。 按错误码分支;展示文本。
A0003 以外的错误码返回其标准信息,不附加详情,
除非该特定失败被定义为携带额外上下文。
我的回调 URL 有什么规则?
notifyUrl——Waffo 推送支付通知的 URL——在
您配置时校验,每种失败模式有自己的错误:
两者都以
A0003 返回,具体原因如上所述
在信息中。
让人中招的是最后两条。含非 ASCII 字符的 URL
——国际化域名,或从文档粘贴的路径段——
即便浏览器能打开也会被拒绝:请先做
百分号编码。而复制时带上的一个尾部空格就足以让
空白检查失败,报错看起来却像是 URL 本身的问题。
允许 notifyUrl 留空;此时不运行校验,也不向其发送
任何通知。
我必须发送 subscriptionManagementUrl 吗?它最终去哪里?
它在创建订阅时文档定义为必填,上限
256 个字符——但注意创建调用目前只强制执行
长度:没有它的请求不会被拒绝。仍请把它当作必填,
因为在一种账户设置下(见下文)它是您客户
唯一能拿到的管理链接。它的用途,以及为什么应该是一个能在
桌面浏览器打开的页面而不是 App deeplink,见
订阅 FAQ。
那一页没有覆盖的是您的客户实际收到哪个管理
链接。那是一个有两个值的账户级设置:
两个后果:
- **在
MERCHANT_API_URL下,您的值就是链接。**如果您没有发送,或 发送的页面之后迁移了,您客户邮件中的链接就是坏的, 没有任何东西补救。请在订阅查询中读回它以 确认存储的值。 - **在
INTERNAL下,旧邮件中的链接会失效。**每封新邮件 生成新链接并使之前的失效,所以翻出上个月邮件的 客户需要改用最新的那封。生成的 链接本身也有时效。
我的交易和退款导出中哪些列变了?
三处变化,其中一处容易误读:
陷阱在第三行。
Merchant Original Order ID 定义在共享
列集合上,但有意从交易导出中排除——它
只在退款行上有意义,用来区分您对退款的 ID 与
您对其所冲正支付的 ID。如果您的交易导出
解析器在找它,是找不到的。
关于 Initiation Type:它经常为空。原因以及什么会填充它,见
交易与退款字段参考。
导出是排队的后台任务而不是即时下载——见
导出与报表下载。
我能把拒付或退款列表收窄到一个订阅或一笔订单吗?
可以,这些是人们最常错过的筛选:
当客户对某次购买提出争议而您只知道自己的订单引用时,
merchantOriginalOrderId 就是该用的:它直接从您的
订单 ID 到该支付的每一笔退款,无需先查找 Waffo 的
标识符。
注意命名。筛选是 relatedSubscriptionId,不是 subscriptionId——
“related”是因为被筛选的行是来自订阅的拒付、退款或支付,
不是订阅本身。要列出订阅,请改在订阅列表上按 acqSubscriptionId 或
merchantSubscriptionId 筛选。
客户重新打开了旧的收银台链接,他们会看到什么?
收银台链接是一个会话,会话不会永远持续。两个独立的 生命周期适用:- 支付前,链接从创建起在有限期间内有效。超过后 打开,它报告收银台已过期,而不是收款。
- 订单到达最终状态后,链接不再是支付页面, 变为结果页,在完成后一段时间内可查看,之后 不再可查看。