PAYATHON 2026

支付宝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 地址。

通知地址无法访问通常只会影响异步通知。不过,部分产品也可能校验地址格式或安全性,因此这一项同样需要排查。

建议的处理步骤

  1. 在支付宝商家平台确认“商家扣款”产品已经生效,而不只是审核通过或完成签约。
  2. 核对该产品对应的扣款类型,确认开通的确实是周期扣款。
  3. 查询支付宝实际分配的 sign_scene,不要自行构造。
  4. 确认扣款能力已经关联到 app_id=2021004133632060。
  5. 确认当前签约场景支持 ALIPAYAPP 渠道,并允许支付时携带 agreement_sign_params。
  6. 按照场景允许的周期重新设置 period_rule_params。
  7. 使用新的 external_agreement_no 和 out_trade_no 再次测试,避免旧编号已经产生签约或支付记录。
  8. 检查支付宝 SDK 返回结果,以及客户端 payV2 结果中的 resultStatus、memo 和 result,不要只根据页面显示的“系统繁忙”判断原因。
  9. 如果问题仍未解决,将支付宝返回的错误码、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 只是自行定义的值,基本可以判定需要将其改为支付宝审核并配置的真实场景码。

备注:内容仅供参考。