PAYATHON 2026

签约支付能否通过接口完成并接收异步通知?

支付阿杰

结论

首次签约通常不能完全绕过支付宝客户端或支付宝收银台,直接由服务端接口代替用户完成。

签约涉及用户授权,一般需要跳转到支付宝提供的签约页面,由用户确认协议、身份和扣款授权。签约成功后,商户才能在产品权限及协议约定的范围内,通过服务端接口发起后续支付或代扣,并通过异步通知获取处理结果。

如果支付宝明确提供了”免页面签约”或类似能力,且商户已经签约并开通相应产品,才有可能全程通过接口完成。具体是否支持,不能只看接口名称,需要结合对应产品文档、商户后台权限以及支付宝技术支持的确认结果来判断。

推荐实现流程

1. 完成产品签约与权限开通

先确认商户账号已开通目标产品,例如周期扣款、协议支付或其他签约支付能力。不同产品使用的签约入口、支付接口和通知字段可能不同,不能直接套用普通支付接口的参数。

2. 发起用户签约

服务端调用对应的签约接口,生成签约页面或跳转地址,再引导用户进入支付宝完成确认。

签约请求通常需要包含:

  • 商户协议号
  • 用户标识或业务场景参数
  • 签约产品码
  • 签约成功后的同步跳转地址
  • 异步通知地址 notify_url

实际使用的接口名称和必填参数,以商户已开通产品的官方文档为准。

3. 接收并验证签约通知

收到支付宝发送的异步通知后,商户服务端需要:

  1. 使用支付宝公钥验证通知签名。
  2. 校验 app_id、商户协议号等业务字段。
  3. 确认签约状态是否成功。
  4. 保存支付宝协议号、商户协议号和协议状态。
  5. 返回支付宝要求的成功响应。

不要只根据浏览器的同步跳转结果更新签约状态。用户可能在跳转前关闭页面,同步请求也可能因网络问题丢失。

4. 发起支付或代扣

首次签约成功后,使用有效协议号调用该产品对应的支付或扣款接口。支付时是否仍需用户操作,由产品类型决定:

  • 普通支付通常仍需用户进入支付宝确认。
  • 已授权的协议支付或代扣,在符合协议约定和风控条件时,可以由服务端发起。
  • 如果超出协议范围、协议已经失效或触发风控,用户可能需要重新授权或接受额外验证。

5. 处理支付异步通知

支付接口返回成功,只表示请求已被受理,并不一定代表资金已经支付成功。最终结果需要结合以下信息确认:

  • 支付异步通知
  • 主动查询接口
  • 对账结果

异步通知处理示例

以下代码以 Java Servlet 风格展示通用处理方式。验签方法和 SDK 类名需要根据项目实际使用的支付宝 Java SDK 调整。

@PostMapping("/alipay/notify")
public String handleNotify(HttpServletRequest request) throws Exception {
    Map<String, String> params = new HashMap<>();

    request.getParameterMap().forEach((key, values) -> {
        if (values != null && values.length > 0) {
            params.put(key, String.join(",", values));
        }
    });

    boolean verified = AlipaySignature.rsaCheckV1(
        params,
        ALIPAY_PUBLIC_KEY,
        "UTF-8",
        "RSA2"
    );

    if (!verified) {
        return "failure";
    }

    // 防止其他应用或错误配置的通知进入当前业务。
    if (!EXPECTED_APP_ID.equals(params.get("app_id"))) {
        return "failure";
    }

    String outTradeNo = params.get("out_trade_no");
    String tradeNo = params.get("trade_no");
    String tradeStatus = params.get("trade_status");

    // 根据实际签约产品读取协议号和签约状态字段。
    String externalAgreementNo = params.get("external_agreement_no");
    String agreementNo = params.get("agreement_no");

    // 使用本地订单或协议记录校验金额、商户协议号等信息。
    // 更新操作应保证幂等,避免重复通知造成重复记账或重复履约。
    processNotifyIdempotently(
        outTradeNo,
        tradeNo,
        tradeStatus,
        externalAgreementNo,
        agreementNo,
        params
    );

    return "success";
}

使用其他语言时,处理原则相同:读取全部表单参数,按照支付宝规则验签,校验业务字段,执行幂等更新,并在处理完成后返回纯文本 success。

注意事项

不要在服务端模拟用户确认

不得通过保存用户密码、模拟客户端点击或伪造授权结果绕过签约页面。这种做法既不可靠,也可能违反产品规则和安全要求。

接口响应不等于业务成功

签约或支付接口返回请求成功,只能说明支付宝已经收到请求。业务状态应以验签通过的异步通知或主动查询结果为准。

异步通知可能重复或乱序

通知处理必须具备幂等性。可以使用商户订单号、商户协议号或支付宝交易号建立唯一约束,并按照合法的状态迁移规则更新数据。

必须核对通知内容

即使验签成功,也需要继续检查:

  • app_id 是否属于当前应用
  • 商户订单号或协议号是否存在
  • 支付金额和币种是否与本地记录一致
  • 当前状态是否允许变更
  • 通知中的卖家身份是否符合预期

通知失败时主动查询

网络、网关或服务异常都可能导致异步通知延迟。对于长时间停留在处理中状态的订单,应调用相应的签约查询或交易查询接口进行补偿,不能一直等待通知。

常见且可靠的方案是:用户通过页面完成首次授权签约,服务端根据协议发起后续支付,再结合异步通知和主动查询确认最终结果。不要试图完全跳过用户授权页面。

备注:内容仅供参考。