支付宝 A2M 生产支付失败排查
适用场景
402-buyer-pay 在生产环境持续返回 SYSTEM_ERROR / 系统异常,支付失败,但沙箱能跑通,
无法判断是商户自己配置错了还是支付宝平台的问题。
环境准备(首次使用)
- 安装依赖:在本 Skill 目录执行
npm install alipay-sdk(需 Node.js ≥ 18)。 - 准备配置:复制
references/alipay.example.json为scripts/config/alipay.json,填入真实值。
字段说明:appId应用 ID;privateKey应用私钥(原始字符串,不带 PEM 头尾,Java 用 PKCS#8、其他语言用 PKCS#1);alipayPublicKey支付宝公钥;gateway网关(生产https://openapi.alipay.com/gateway.do);serviceId服务市场真实服务 ID;sellerId2088 开头的收款商户 ID;realOutTradeNo可选,上次失败支付的真实订单号(用于反查)。 - 私钥安全:
config/alipay.json含应用私钥,严禁提交到 Git、上传或分享;请将其加入.gitignore。 - 验证就绪:
node scripts/probe-production-gateway.js
核心方法:错误形态判据
不要猜,用生产密钥打一个只读接口,看它报什么错。 支付宝网关的错误码本身就是判据:
| 返回 | 含义 | 结论 |
|---|---|---|
aop.invalid-signature / 签名错误 |
私钥与支付宝公钥不匹配 | 商户侧问题 → 查密钥配置 |
40006 Insufficient Permissions |
该应用未绑定此产品 | 属正常(未开通产品),同时证明签名已被接受 |
40002 / 参数校验类错误 |
已通过鉴权,参数不对 | 商户侧参数问题 |
40004 Business Failed + subCode |
已通过鉴权,进入业务层 | 产品权限正常,业务数据问题 |
TRADE_PROGRESS_FAILED + 买家和卖家不能相同 |
买家钱包绑定账号 = 收款账号 | 最常见根因,见下方「买卖同号」 |
SYSTEM_ERROR / 系统异常,支付失败 |
笼统错误,可能是任何原因 | 不要直接判定为平台故障,先把本地可查项全部走完 |
| 返回 HTML 错误页 | 该接口不存在 | 不要在这个接口上浪费时间 |
> 重要教训:同一个根因在不同时机可能抛出不同错误。SYSTEM_ERROR 与
> 买家和卖家不能相同 可能指向同一问题——不要因为错误文案"像平台故障"就下结论,
> 也不要因为换过一次账号就认定该项已排除(换绑可能根本没生效)。
>
> ⚠️ 实测确认:「买家和卖家不能相同」按实名主体(身份证/企业主体)判断,不是按登录账号。
> 换绑到同一个人名下的另一个支付宝账号后,错误依然一模一样。
> 必须使用不同实名主体的账号(家人/朋友实名开通的账号)才能通过。
关键推论:只要拿到的是正常的 JSON 业务响应(而非签名/权限错误),就说明 appId + 私钥 +
支付宝公钥三者一致且有效,且该产品已绑定。 此时若收银台仍失败,责任在支付宝侧。
执行步骤
1. 跑隔离探针
node scripts/probe-production-gateway.js --config <path-to-alipay.json>
或在项目内直接复制 scripts/probe-production-gateway.js 后运行(需同目录有 config/alipay.json)。
脚本会依次探测:
- alipay.aipay.agent.payment.verify(主判据:40004 = 权限正常)
- alipay.trade.query(对照:预期 40006,用于确认签名有效)
- 若干疑似查询接口(返回 HTML 即说明不存在)
必须输出完整原始响应,包含 subCode / subMsg / traceId——traceId 是提交官方工单的唯一凭据。
2. 逐项排除本地原因
按此顺序核对,每项都要有实测依据,不要凭印象:
| 怀疑点 | 核对方法 | 常见错因 |
|---|---|---|
| 买卖同号(最高优先级) | 买家钱包绑定的账号是否就是收款 PID?直接比对账号,不要听信"换过了" | 以为是同一个账号;换绑操作实际没生效 |
| 账单签名 | 本地按 key 字典序拼接后 RSA-SHA256 重算比对 | 字段顺序错、漏字段 |
| 账单字段层级 | 解码 Payment-Needed,确认 goods_name / seller_id / service_id 在 method 层而非 protocol 层 |
最容易搞错的一项 |
pay_before 时区 |
检查是否为 +08:00 且晚于当前时间 |
用 UTC 生成导致"已过期" |
| 密钥一致性 | 见上方错误形态判据 | 应用私钥 / 支付宝公钥混用 |
| 买家钱包 | alipay-bot check-wallet 应返回 已开启支付宝支付功能 / status: bound |
未绑定或未激活 |
| 商户服务可用 | curl -i <服务地址> 应返回 HTTP 402 + Payment-Needed 头 |
服务挂了 |
| serviceId 一致性 | 比对账单、配置文件、控制台三处 | 用了沙箱的 api_mock_service_id |
3. 确认根因后:换绑买家账号的完整流程
若根因是「买家和卖家不能相同」,换绑流程如下(顺序不能乱):
alipay-bot close-wallet --json→ 拿到data.access_url(支付宝官方链接 + 二维码)- 用当前绑定的那个账号在手机支付宝打开该链接 → 关闭 AI 支付
- 清理本机凭据缓存:
close-wallet明确说明 "without deleting local credentials",
关闭后本机~/.alipay-bot-cli/claws/workbuddy/wallet.json里的 token 仍在,
apply-wallet会一直返回alreadyExists: true。必须把wallet.json和wallet.json.bak
都备份后移开,apply-wallet才会生成全新链接(实测:只移wallet.json不够,
CLI 会从wallet.json.bak恢复旧的待绑定申请,导致拿到一个已过期的链接)。 alipay-bot apply-wallet -a "<agent名>"→ 返回全新授权链接(注意核对 accessUrl 是否真的变了)- 用另一个实名主体的支付宝账号打开授权链接 → 开通 AI 支付 → 拿到 6 位授权码
(⚠️ 授权链接有效期很短,实测约 3-4 分钟,过期就让用户说一声,重新生成) alipay-bot bind-wallet -c <6位授权码>(若报授权失败但check-wallet已返回 bound,
以 check-wallet 为准,并用wallet.json的credentialMd5是否变化来确认真的换了账号)- 重新取新账单 →
alipay-bot 402-buyer-pay ...
判断是否真的换绑成功:对比 wallet.json 里的 credentialMd5 是否变化。
identityFingerprint 是本机 Agent 身份,不会随账号变化,不要拿它判断。
4. 支付成功后的验收(避免把正常现象当故障)
402-query-payment-status -t <交易号> -r <资源URL>成功时会自动发送履约回执,
输出里会写「履约回执:已发送」。- 因此再单独执行
402-buyer-fulfillment-ack -t <交易号>会返回
FULFILLMENT_FAILED / 履约失败——这是幂等保护,属正常,不要当成故障去排查。 - 复核时可再查一次:若资源体里
already_fulfilled: true,说明履约早已完成,链路闭环。 - 完整通过标准:资源响应状态 200 +
fulfillment_confirmed: true+ 拿到交易号。
5. 确认根因在平台侧后
排除完本地项仍失败,则集中核查两处(都在控制台,代码层面无解):
- 服务是否在生产收银台「已生效」——注意"审核通过"≠"已生效"。收银台需把
service_id
解析为收款配置,配置不完整时只返回笼统的SYSTEM_ERROR。 - 应用是否已签约 AI 支付收款能力——API 调用权限与实际收款能力是两套开关,
前者可通过探针验证,后者只能控制台确认。
补充:若沙箱畅通、生产必挂、更换买家账号无效、跨小时错误完全一致,符合灰度放量特征,
需官方确认商户与买家账号是否在开放名单内。但只有在「买卖同号」等本地原因全部真正排除后,
才能归结为平台侧问题。
硬性纪律
- 支付前不得先执行
check-wallet,第一条支付命令必须是402-buyer-pay(官方文档要求)。 - 每次重试必须重新取新账单,禁止复用旧
Payment-Needed文件、旧tradeNo/outShakeNo/paymentProof。 - A2M 生产环境没有订单反查接口,无法从商户侧确认买家支付记录——不要在这上面耗时间。
- 探针必须只读:用假交易号、假凭证,绝不创建订单或触发扣款。
- 报告里给出的每个结论都要能指到一条实测证据,不做无依据推断。
官方渠道
- 客服电话:95188(转商户 / 开放平台技术支持)
- 提交工单时必带:appId、商户 PID、serviceId、
traceId、失败时间点、已排除项清单