支付宝App支付加入商家扣款签约参数后提示系统繁忙
结论
问题很可能不在 App 支付本身,而是商家扣款的签约场景配置不匹配。
请求中的以下参数:
sign_scene=INDUSTRY|PLAYENJOY_VIP_7
personal_product_code=CYCLE_PAY_AUTH_P
product_code=GENERAL_WITHHOLDING
必须与支付宝为当前商户和当前 app_id 实际开通、配置的扣款场景完全一致。sign_scene 不是商户可以自行命名的业务标识。如果 PLAYENJOY_VIP_7 未经支付宝配置,或者与进件时的场景码不一致,客户端可能只会显示“系统繁忙,请您稍后再试”。
开通“App 支付”和“商家扣款”两个产品,也不一定意味着当前应用支持“App 支付携带签约参数”。还要确认签约场景、应用绑定关系和周期扣款规则均已配置完成。
需要重点检查的参数
1. sign_scene
当前值为:
INDUSTRY|PLAYENJOY_VIP_7
请在支付宝商家平台、开放平台或产品签约资料中查找实际分配的签约场景码。传参时要保持原样,包括大小写、前缀和分隔符。
不要把自己的会员套餐编码直接拼接成 sign_scene。如果支付宝分配的场景码并非当前值,应替换为实际配置值。
2. personal_product_code
当前使用:
CYCLE_PAY_AUTH_P
该值代表周期扣款签约。只有当前商户开通了对应的周期扣款能力,且签约场景允许周期扣款时,才能使用这个值。
如果商户开通的是其他类型的商家扣款能力,就不能直接套用 CYCLE_PAY_AUTH_P。具体参数应以产品签约页面或支付宝提供的接入资料为准。
3. product_code
签约参数中的:
GENERAL_WITHHOLDING
与 App 支付业务参数中的:
QUICK_MSECURITY_PAY
用途不同,同时出现并不冲突:
QUICK_MSECURITY_PAY:App 支付产品码。GENERAL_WITHHOLDING:商家扣款签约产品码。
需要确认的是,GENERAL_WITHHOLDING 已经对当前商户和应用生效,不能只看商户账号下是否显示“已开通”。
4. period_rule_params
当前规则是:
{
"period": 7,
"execute_time": "2024-02-08",
"single_amount": 0.01,
"period_type": "DAY"
}
请逐项检查:
execute_time是否符合yyyy-MM-dd格式,并处于首次扣款日期的有效范围内。- 调用时该日期是否已经过期。
period_type=DAY和period=7是否符合当前签约场景允许的扣款周期。single_amount是否符合产品规定的金额范围。- 周期规则是否与商户进件或场景报备的内容一致。
示例请求时间是 2024-02-01,首次执行日期是 2024-02-08,在当时属于未来日期。如果现在直接复用这组参数,日期已经失效,需要动态生成新的有效日期。
5. 应用和商户绑定关系
以下配置必须属于同一套主体:
- 调用使用的
app_id - App 支付签约商户
- 商家扣款签约商户
- RSA2 应用私钥
- 支付宝公钥
- 签约场景码
一种常见情况是,商家扣款虽然已经开通在商户账号下,却没有授权或绑定到当前开放平台应用。此时普通 App 支付仍可成功,但加入签约参数后便会失败。
6. sign_notify_url
当前地址是:
http://m.g.wearewinner.cn:8989/notify/alin
这是签约结果的异步通知地址,与外层 App 支付的 notify_url 含义不同。
请确认:
- 地址可从公网访问。
- 地址没有登录、Cookie 或 IP 白名单等限制。
- 服务可以接收支付宝发送的 POST 请求。
- 防火墙和网关允许访问
8989端口。 - 服务会返回支付宝要求的成功响应。
- 生产环境优先使用合法的 HTTPS 地址。
通知地址无法访问通常只会影响异步通知。不过,部分产品也可能校验地址格式或安全性,因此这一项同样需要排查。
建议的处理步骤
- 在支付宝商家平台确认“商家扣款”产品已经生效,而不只是审核通过或完成签约。
- 核对该产品对应的扣款类型,确认开通的确实是周期扣款。
- 查询支付宝实际分配的
sign_scene,不要自行构造。 - 确认扣款能力已经关联到
app_id=2021004133632060。 - 确认当前签约场景支持
ALIPAYAPP渠道,并允许支付时携带agreement_sign_params。 - 按照场景允许的周期重新设置
period_rule_params。 - 使用新的
external_agreement_no和out_trade_no再次测试,避免旧编号已经产生签约或支付记录。 - 检查支付宝 SDK 返回结果,以及客户端
payV2结果中的resultStatus、memo和result,不要只根据页面显示的“系统繁忙”判断原因。 - 如果问题仍未解决,将支付宝返回的错误码、
sub_code、调用时间和支付宝侧trace_id提交给支付宝技术支持查询。
推荐的业务参数结构
以下内容只展示参数结构。sign_scene 必须替换为支付宝实际分配的值:
{
"out_trade_no": "唯一支付订单号",
"total_amount": "0.01",
"subject": "享看",
"product_code": "QUICK_MSECURITY_PAY",
"agreement_sign_params": {
"personal_product_code": "CYCLE_PAY_AUTH_P",
"product_code": "GENERAL_WITHHOLDING",
"sign_scene": "支付宝实际分配的签约场景码",
"external_agreement_no": "唯一签约协议号",
"sign_notify_url": "https://example.com/alipay/agreement/notify",
"access_params": {
"channel": "ALIPAYAPP"
},
"period_rule_params": {
"period_type": "DAY",
"period": 7,
"execute_time": "有效的首次执行日期",
"single_amount": 0.01
}
}
}
Java SDK 可以按下面的方式组织参数:
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setOutTradeNo(outTradeNo);
model.setTotalAmount("0.01");
model.setSubject("享看");
model.setProductCode("QUICK_MSECURITY_PAY");
AccessParams accessParams = new AccessParams();
accessParams.setChannel("ALIPAYAPP");
PeriodRuleParams periodRuleParams = new PeriodRuleParams();
periodRuleParams.setPeriodType("DAY");
periodRuleParams.setPeriod(7L);
periodRuleParams.setExecuteTime(executeDate);
periodRuleParams.setSingleAmount("0.01");
AgreementSignParams agreement = new AgreementSignParams();
agreement.setProductCode("GENERAL_WITHHOLDING");
agreement.setPersonalProductCode("CYCLE_PAY_AUTH_P");
agreement.setSignScene(actualSignScene);
agreement.setExternalAgreementNo(externalAgreementNo);
agreement.setSignNotifyUrl("https://example.com/alipay/agreement/notify");
agreement.setAccessParams(accessParams);
agreement.setPeriodRuleParams(periodRuleParams);
model.setAgreementSignParams(agreement);
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
request.setBizModel(model);
request.setNotifyUrl("https://example.com/alipay/payment/notify");
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
String orderString = response.getBody();
不同版本的 Java SDK 对金额、周期等属性使用的 Java 类型可能不同,应以当前 SDK 生成的 setter 定义为准,不要为了照搬示例手工修改类型。
注意事项
external_agreement_no 是商户侧签约协议号,out_trade_no 是支付订单号。两者在技术上可以使用相同的字符串,但业务含义不同。建议分别生成并持久化,同时保证各自唯一。
同时保留外层 notify_url 和签约参数中的 sign_notify_url 是合理的。前者用于接收支付结果,后者用于接收签约结果,服务端应分别验签并更新相应状态。
排查时应优先确认 sign_scene 与当前 app_id 的场景绑定关系。如果 INDUSTRY|PLAYENJOY_VIP_7 只是自行定义的值,基本可以判定需要将其改为支付宝审核并配置的真实场景码。
备注:内容仅供参考。
