PAYATHON 2026

Alipay Easy SDK 如何调用周期扣款签约接口

支付老李

结论

如果当前版本的 Alipay Easy SDK 没有封装 alipay.user.agreement.page.sign,就无法像调用付款接口那样,通过 Factory.Payment... 直接发起周期扣款签约。

这是一个页面类接口。服务端需要生成带签名的支付宝跳转地址或表单,再由用户在浏览器中完成授权。可以在项目中同时引入支付宝通用 Java SDK,通过 AlipayClient.pageExecute() 调用该接口。Easy SDK 不必移除,其他已经封装的接口仍可继续使用。

为什么 Easy SDK 中找不到该接口

Easy SDK 只封装了一部分常用的开放平台接口,并不覆盖支付宝开放平台的所有 API。

alipay.user.agreement.page.sign 是页面签约接口,调用结果需要交给浏览器跳转或渲染,处理方式与普通的服务端 JSON 接口不同。即使某个版本的 Easy SDK 提供了通用调用能力,也需要确认它是否支持页面接口所需的 pageExecute 行为,不能直接把这个接口当作普通接口提交。

使用通用 SDK 发起签约

以下使用 Java 演示。依赖版本应根据项目现有的依赖管理,以及支付宝开放平台提供的版本确定,避免同时引入多个不兼容的版本。

<dependency>
    <groupId>com.alipay.sdk</groupId>
    <artifactId>alipay-sdk-java</artifactId>
    <version>${alipay-sdk.version}</version>
</dependency>

初始化 AlipayClient:

import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;

AlipayClient alipayClient = new DefaultAlipayClient(
    "https://openapi.alipay.com/gateway.do",
    appId,
    appPrivateKey,
    "json",
    "UTF-8",
    alipayPublicKey,
    "RSA2"
);

使用沙箱环境时,需要配置对应的沙箱网关、应用 ID 和密钥,不能与正式环境的配置混用。

调用 alipay.user.agreement.page.sign

import com.alipay.api.AlipayClient;
import com.alipay.api.request.AlipayUserAgreementPageSignRequest;
import com.alibaba.fastjson.JSON;

import java.util.LinkedHashMap;
import java.util.Map;

public String createAgreementSignForm(
        AlipayClient alipayClient,
        String externalAgreementNo,
        String returnUrl,
        String signNotifyUrl) throws Exception {

    AlipayUserAgreementPageSignRequest request =
            new AlipayUserAgreementPageSignRequest();

    request.setReturnUrl(returnUrl);

    Map<String, Object> bizContent = new LinkedHashMap<>();
    bizContent.put("external_agreement_no", externalAgreementNo);
    bizContent.put("personal_product_code", "CYCLE_PAY_AUTH");

    // sign_scene 必须使用应用实际签约产品允许的场景值。
    bizContent.put("sign_scene", "YOUR_SIGN_SCENE");

    Map<String, Object> accessParams = new LinkedHashMap<>();
    accessParams.put("channel", "ALIPAYAPP");
    bizContent.put("access_params", accessParams);

    Map<String, Object> periodRuleParams = new LinkedHashMap<>();
    periodRuleParams.put("period_type", "MONTH");
    periodRuleParams.put("period", 1);
    periodRuleParams.put("execute_time", "2026-10-01");
    periodRuleParams.put("single_amount", 99.00);
    bizContent.put("period_rule_params", periodRuleParams);

    bizContent.put("sign_notify_url", signNotifyUrl);

    request.setBizContent(JSON.toJSONString(bizContent));

    // 返回支付宝签约页面的 HTML form。
    return alipayClient.pageExecute(request).getBody();
}

控制器可以把生成的表单直接返回给浏览器:

@GetMapping(value = "/agreement/sign", produces = "text/html;charset=UTF-8")
@ResponseBody
public String sign() throws Exception {
    String externalAgreementNo = generateUniqueAgreementNo();

    return createAgreementSignForm(
        alipayClient,
        externalAgreementNo,
        "https://example.com/alipay/agreement/return",
        "https://example.com/alipay/agreement/notify"
    );
}

浏览器收到 HTML 后,会显示或自动提交支付宝签约表单。根据所用 SDK 提供的重载方法,也可以生成 GET 跳转地址,例如:

String redirectUrl = alipayClient
        .pageExecute(request, "GET")
        .getBody();

不同 SDK 版本返回的内容可能不同。需要先确认结果是完整 URL 还是 HTML 表单,再选择使用 HTTP 重定向或直接输出页面。

参数需要按已开通产品配置

示例参数只用于说明调用结构,不能直接作为所有商户的通用配置:

  • external_agreement_no:商户侧唯一的签约编号,需要持久化并避免重复。
  • personal_product_code:周期扣款产品通常使用 CYCLE_PAY_AUTH,具体取值仍以应用实际开通的产品为准。
  • sign_scene:必须填写签约产品允许的业务场景值,不能保留示例中的占位符。
  • access_params.channel:表示签约入口渠道,需要根据实际接入方式填写。
  • period_rule_params:用于定义扣款周期、间隔、执行时间和单次金额等规则。
  • sign_notify_url:支付宝异步通知地址,支付宝服务器必须能通过公网访问。
  • return_url:用户完成签约后的同步跳转地址,不能替代异步通知。

字段是否必填、可用的枚举值以及金额限制,可能因商户签约产品和开放平台规则而异,应以应用控制台中对应产品的接口文档为准。

签约完成后的处理

同步跳转只适合用于页面展示,不能仅凭 return_url 判断签约是否成功。服务端还需要处理异步通知:

  1. 使用支付宝公钥验证通知签名。
  2. 校验应用 ID、商户签约编号等关键字段。
  3. 根据通知中的协议号更新本地签约状态。
  4. 对通知做幂等处理,避免重复更新。
  5. 必要时调用协议查询接口,再次确认签约状态。

完成周期扣款签约,只表示用户授予了代扣权限,并不会自动执行后续扣款。实际扣款仍需要按照已开通产品的扣款接口、协议号和周期规则另行发起。

注意事项

不要自行拼接支付宝网关 URL,也不要在前端生成签名。应用私钥只能保存在服务端。

如果准备继续使用 Easy SDK 的通用调用功能,需要先确认当前语言和版本明确支持页面类 API。普通的 generic execute 调用通常无法代替 pageExecute 生成页面跳转地址或表单。因此,调用 alipay.user.agreement.page.sign 时,使用支付宝通用 SDK 提供的 AlipayClient.pageExecute() 更合适。

备注:内容仅供参考。