PAYATHON 2026

免密支付API、商户权限开通及沙箱环境操作咨询

支付阿杰

结论

如果这里的“免密支付”是指支付宝商户在用户授权后主动扣款,那么通常不存在一个独立的“免密支付 API”。整个流程由以下环节组成:

  1. 使用 alipay.user.agreement.page.sign 引导用户签署代扣协议。
  2. 使用 alipay.user.agreement.query 查询签约状态。
  3. 取得有效协议号后,通过相应代扣产品支持的支付接口发起扣款。常见场景使用 alipay.trade.pay,具体仍要以商户已开通产品的官方接入文档为准。
  4. 用户解约时调用 alipay.user.agreement.unsign,同时更新业务系统中的协议状态。

免密代扣是一项受控支付能力。商户通常要先申请相应的产品权限,再将该能力绑定到实际使用的应用和商户账号,而不是在后台为某件商品打开一个“免密”开关。

沙箱可以验证接口签名、请求格式、协议状态流转和异步通知,但沙箱测试通过不等于生产权限已经开通。部分代扣产品、签约渠道或真实扣款链路无法在沙箱中完整模拟,需要按平台要求申请生产联调,或采用官方提供的测试方案。

以下内容以支付宝开放平台的“签约后代扣”模式为前提。如果接入的是微信支付、银联或其他支付平台,API 名称和准入流程会有所不同。

应调用哪些 API

完整链路一般包括签约、查询、扣款和解约四个部分。

1. 用户签约

调用:

alipay.user.agreement.page.sign

该接口用于生成签约页面。用户需要在支付宝提供的页面中阅读并确认协议,商户不能自行把用户标记为已签约。

业务系统应为每次签约生成唯一的外部协议号,例如:

external_agreement_no = AGR_20260913_100001

签约请求中的产品码、签约场景等参数由商户申请的代扣产品决定,不能自行猜测或混用。

2. 查询协议状态

调用:

alipay.user.agreement.query

收到页面跳转或异步通知后,建议主动查询一次协议状态。只有平台确认协议有效,业务系统才能启用后续代扣。

不能只根据前端跳转页面中的“签约成功”提示直接扣款。

3. 发起扣款

常见的签约代扣产品会通过以下接口发起支付:

alipay.trade.pay

请求中还要提交有效的协议标识。具体使用 agreement_no、外部协议号还是其他凭据,以及 product_code 应填写什么值,取决于商户实际开通的产品。

因此,不能简单地认为“调用 alipay.trade.pay 就能免密扣款”。扣款请求要成功,通常需要同时满足以下条件:

  • 商户已取得相应代扣产品的权限;
  • 发起请求的应用、签约应用和商户主体相互匹配;
  • 用户协议当前有效;
  • 请求中的产品码和场景参数与已开通产品一致;
  • 金额、频率和业务用途符合签约协议及平台风控要求。

4. 用户解约

调用:

alipay.user.agreement.unsign

解约成功后,系统必须停止扣款。业务系统还应保存解约时间、协议状态和平台返回结果,防止本地状态更新延迟造成重复扣款。

商户是否需要开通权限

需要。免密代扣通常按照商户主体、应用、行业场景和产品能力进行审核,不是针对某件商品单独配置权限。

准入条件会随代扣产品和行业变化,常见审核内容包括:

  • 企业主体及经营资质;
  • 网站、App 或小程序已有真实业务;
  • 使用场景属于连续服务、周期性服务或其他允许代扣的场景;
  • 用户可以清楚了解扣款规则、金额或计算方式、扣款周期和解约入口;
  • 商户具有退款、投诉及异常扣款处理机制;
  • 商品或服务不在平台限制或禁止范围内;
  • 应用已经创建,并完成必要的签约、密钥和回调地址配置。

具体入口名称和审核材料可能调整,请以支付宝开放平台控制台当前显示的产品申请页面为准。

推荐的开通流程

  1. 在开放平台创建应用,确认应用所属的商户账号和签约主体。
  2. 在产品中心查找符合实际业务的代扣产品,例如周期扣款或其他签约代扣能力。
  3. 阅读产品准入规则,确认所在行业、商品类型和扣款模式是否符合要求。
  4. 提交业务说明、用户签约页面、服务协议、解约路径及必要资质。
  5. 审核通过后,把产品能力添加到应用。
  6. 配置应用公钥或证书、支付宝公钥、网关地址和异步通知地址等信息。
  7. 对签约、协议查询、扣款、退款、解约和异常处理进行完整测试。
  8. 上线前检查生产应用的 app_id、密钥、网关和产品权限,不能继续使用沙箱配置。

如果控制台中没有相应产品,或者添加接口后仍返回“无权限”,问题通常不在代码,而在商户主体、应用或产品权限尚未开通。此时应根据返回的 code、sub_code 和 sub_msg 排查权限,必要时联系平台技术支持确认准入情况。

代码示例

下面的 Java 示例只展示调用结构。product_code、sign_scene、协议参数名称及取值必须从当前已开通产品的官方文档中获取,不能把示例中的占位值直接用于生产环境。

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

AlipayUserAgreementPageSignRequest request =
    new AlipayUserAgreementPageSignRequest();

request.setReturnUrl(returnUrl);
request.setNotifyUrl(notifyUrl);

request.setBizContent("""
{
  "external_agreement_no": "AGR_20260913_100001",
  "product_code": "<以已开通产品文档为准>",
  "sign_scene": "<以已开通场景为准>"
}
""");

AlipayUserAgreementPageSignResponse response =
    alipayClient.pageExecute(request);

if (response.isSuccess()) {
    String signPage = response.getBody();
    // 将表单或跳转内容返回给浏览器,由用户完成签约。
} else {
    System.err.println(response.getCode());
    System.err.println(response.getSubCode());
    System.err.println(response.getSubMsg());
}

查询协议时,需要校验平台返回的状态,并将平台协议号与本地用户、业务合同绑定:

AlipayUserAgreementQueryRequest request =
    new AlipayUserAgreementQueryRequest();

request.setBizContent("""
{
  "external_agreement_no": "AGR_20260913_100001"
}
""");

AlipayUserAgreementQueryResponse response =
    alipayClient.execute(request);

if (response.isSuccess()) {
    // 读取并保存协议号、协议状态及有效期。
    // 只有协议有效时才允许进入代扣流程。
} else {
    System.err.println(response.getCode());
    System.err.println(response.getSubCode());
    System.err.println(response.getSubMsg());
}

不同 SDK 版本生成的类名或字段封装方式可能不同,应以项目实际使用的官方 SDK 和相应接口模型为准。

沙箱环境配置方法

1. 创建沙箱应用

在开放平台沙箱控制台获取以下测试信息:

  • 沙箱 app_id;
  • 沙箱支付宝账号;
  • 沙箱网关地址;
  • 应用私钥;
  • 支付宝公钥或平台证书。

沙箱与生产环境的账号、密钥和 app_id 相互隔离,不能混用。

2. 切换沙箱网关

调用接口时,将网关设置为控制台当前提供的沙箱网关。例如:

String gatewayUrl = "<沙箱控制台提供的网关地址>";

不要按照旧示例硬编码网关地址。上线时要切换到生产网关,并同时更换生产环境的 app_id 和密钥。

3. 配置回调地址

notify_url 必须是支付平台能够访问的地址。本机的 localhost 或内网地址通常无法接收平台通知。

调试时可以使用支持 HTTPS 的测试域名,或经过安全控制的内网穿透地址。收到通知后必须:

  • 验证签名;
  • 校验 app_id、商户身份和业务订单号;
  • 校验金额和币种;
  • 根据通知标识进行幂等处理;
  • 按接口要求返回确认内容。

页面返回地址 return_url 只影响用户体验,不能用来判断最终的支付或签约结果。

4. 验证完整状态流转

测试至少应覆盖以下场景:

未签约 → 发起签约 → 签约成功 → 查询协议有效
协议有效 → 发起扣款 → 查询订单结果
协议有效 → 用户解约 → 查询协议失效
重复通知 → 业务系统只处理一次
重复扣款请求 → 相同 out_trade_no 不重复入账
协议失效或无权限 → 扣款被拒绝

每次请求都应保存:

app_id
method
out_trade_no
external_agreement_no
agreement_no
code
sub_code
sub_msg
trade_no
notify_time

日志中的用户标识、协议号及其他敏感信息需要脱敏。

沙箱无法完成代扣时怎么办

如果普通支付接口可以在沙箱中使用,但签约或代扣接口返回产品不存在、权限不足、场景不支持等错误,应依次检查:

  1. 当前沙箱应用中是否显示相应的产品能力;
  2. 使用的 product_code 是否属于已经申请的产品;
  3. SDK 请求是否发送到了沙箱网关;
  4. app_id、密钥和支付宝公钥是否来自同一个沙箱应用;
  5. 测试账号是否为沙箱账号;
  6. 该产品是否明确支持沙箱测试。

如果产品无法在沙箱中完整模拟,不能通过修改参数绕过权限。可以先在本地模拟测试签名、幂等、状态机和通知验签,再按照平台提供的生产联调流程,使用受控金额和测试账号验证真实链路。

注意事项

  • 用户明确授权是免密支付的前提,不能把普通支付授权视为代扣授权。
  • 除用户 ID 外,还要保存平台协议号、协议状态和有效期。
  • 每笔扣款都要使用唯一的 out_trade_no,并在服务端实现幂等。
  • 扣款结果不明确时,应调用订单查询接口确认,不能立即创建新订单并再次扣款。
  • 退款不能替代解约。退款完成后,协议可能仍然有效。
  • 用户解约、协议过期或平台暂停协议后,必须立即停止扣款。
  • 生产环境需要提供扣款提醒、账单查询、退款、投诉处理和清晰的解约入口。
  • API 调用失败时,应根据 sub_code 和 sub_msg 定位问题,不能只记录最外层的 code。
  • 产品权限、准入行业和沙箱支持范围可能变化,最终应以商户控制台当前可申请的产品及相应官方接口文档为准。

备注:内容仅供参考。