PAYATHON 2026

支付宝H5支付中签约及扫码签约应使用哪个接口?

支付小周

结论

alipay.trade.wap.pay 不支持”支付中签约”,追加自定义参数也无法实现这一能力。

H5 场景需要把支付和签约分成两个流程:

  • H5 支付仍使用 alipay.trade.wap.pay。
  • 代扣或周期扣款签约使用 alipay.user.agreement.page.sign。
  • 用户扫码后可以直接进入签约页,但这仍是独立的签约流程,并非通过 WAP 支付接口完成支付中签约。

如果业务要求一次完成付款和签约,只能使用支付宝明确支持该能力的产品和支付接口。具体是否可用,取决于商户已经签约的支付宝产品,不能通过增加接口参数自行开启。

为什么 WAP 支付不能直接实现

支付和协议签约属于两类不同的能力:

  • alipay.trade.wap.pay 用于创建手机网站支付交易。
  • alipay.user.agreement.page.sign 用于创建用户协议签约页面。
  • 后续代扣通常还需要开通相应的协议支付产品并取得接口权限。

有些客户端支付产品可能支持支付和签约的组合流程,但这不表示 WAP 支付支持相同参数。接口文档未声明的参数,即使提交,也不会让接口获得支付中签约能力。

爱奇艺等业务还可能使用需要单独准入或定制的产品能力,不能只根据页面表现判断其调用了哪个公开接口。

推荐实现流程

方案一:先签约,再支付

这种方案适合必须先取得代扣授权的业务:

  1. 服务端生成唯一的 external_agreement_no。
  2. 调用 alipay.user.agreement.page.sign。
  3. 把返回的签约页面输出到浏览器,由用户在支付宝侧确认。
  4. 服务端接收异步通知,并主动查询签约结果。
  5. 确认协议生效后,再调用 alipay.trade.wap.pay 发起首笔支付。

方案二:先支付,再引导签约

如果首笔支付不依赖代扣协议,可以采用这种流程:

  1. 使用 alipay.trade.wap.pay 完成首笔付款。
  2. 在支付成功页提示用户开通自动续费。
  3. 调用 alipay.user.agreement.page.sign,进入独立签约流程。
  4. 服务端确认签约成功后,再开通自动续费权益。

这种方式通常更容易接入现有的 H5 支付流程,但页面必须清楚展示扣款规则,不能把签约授权隐藏在普通支付按钮之后。

服务端调用示例

下面的代码只展示调用结构。personal_product_code、sign_scene、周期规则等参数必须填写商户已签约产品对应的实际值,不能直接使用示例中的占位符。

AlipayClient alipayClient = new DefaultAlipayClient(
    gatewayUrl,
    appId,
    merchantPrivateKey,
    "json",
    "UTF-8",
    alipayPublicKey,
    "RSA2"
);

AlipayUserAgreementPageSignRequest request =
    new AlipayUserAgreementPageSignRequest();

request.setBizContent("""
{
  "external_agreement_no": "AGREEMENT_202609090001",
  "personal_product_code": "<以已签约产品为准>",
  "sign_scene": "<以产品配置为准>",
  "sign_notify_url": "https://merchant.example.com/alipay/agreement/notify",
  "return_url": "https://merchant.example.com/alipay/agreement/result",
  "access_params": {
    "channel": "<以当前产品支持的访问方式为准>"
  },
  "period_rule_params": {
    "<按所签约产品的规则填写>": "<value>"
  }
}
""");

AlipayUserAgreementPageSignResponse response =
    alipayClient.pageExecute(request);

if (response.isSuccess()) {
    // pageExecute 返回的 body 通常用于输出签约页面或跳转表单。
    String pageBody = response.getBody();
} else {
    throw new IllegalStateException(
        response.getCode() + ": " + response.getSubMsg()
    );
}

H5 页面不能直接使用商户私钥调用支付宝接口。服务端应先生成签约页面,再把页面内容返回给浏览器:

response.setContentType("text/html;charset=UTF-8");
response.getWriter().write(pageBody);

扫码签约如何处理

扫码签约也应基于 alipay.user.agreement.page.sign 设计,具体接入方式则取决于已经开通的产品是否支持二维码访问渠道。

一般流程如下:

  1. 服务端创建签约请求。
  2. 通过产品支持的二维码访问方式生成签约入口。
  3. 把签约入口转换成二维码并展示。
  4. 用户使用支付宝扫码并确认协议。
  5. 服务端结合异步通知和签约查询,确认最终状态。

不要直接把 SDK 返回的自动提交 HTML 表单全文编码成二维码。二维码应包含可访问的签约地址,也可以指向商户自己的中转页,再由中转页通过服务端重新生成并输出签约表单。

如果当前产品文档没有列出二维码渠道参数,就不能自行猜测 access_params.channel 的枚举值。接入前需要确认商户签约的产品是否支持扫码签约,以及支付宝为该产品提供了哪种接入方式。

签约结果必须由服务端确认

用户跳回 return_url,只能说明浏览器完成了跳转,不能证明协议已经生效。业务系统需要:

  • 验证异步通知签名。
  • 检查应用、商户和协议编号是否匹配。
  • 使用 external_agreement_no 保证请求幂等。
  • 必要时调用协议查询接口核实状态。
  • 确认协议有效后,才能开启自动续费或代扣权益。

前端显示”签约成功”,不能作为后续扣款的唯一依据。

注意事项

  • 能调用签约接口,不等于商户已经取得代扣权限。相关产品需要单独签约和准入。
  • personal_product_code、sign_scene 和周期规则都与具体产品绑定,应以商户后台和当前官方接口文档为准。
  • H5 页面不能传递商户私钥,也不能由前端自行拼接支付宝签名。
  • 签约编号应由服务端生成并持久化,避免重复签约。
  • 页面应明确展示扣款金额或计算方式、扣款周期、服务内容和取消方式等信息。
  • 如果业务要求真正的一步式”支付并签约”,应先确认目标支付接口是否明确支持组合签约参数。alipay.trade.wap.pay 不支持时,需要采用独立签约流程,不能通过尝试未声明的参数来实现。

备注:内容仅供参考。