Web端对接支付宝支付,如何实现15天后自动下款?
结论
支付宝 Web 支付接口无法直接完成“支付成功后冻结订单款项 15 天,再自动下发给用户”的完整流程。
一般需要分三部分实现:
- 使用
alipay.trade.page.pay完成网页支付。 - 由业务系统记录支付时间,通过定时任务判断是否已满 15 天。
- 到期后,根据业务性质调用支付宝的转账、分账或结算类产品下款。
“将款项保存 15 天”并不等于由支付宝替商户托管资金。普通网页支付成功后,支付宝会按照商户签约产品的规则结算资金,商户不能通过支付接口自行指定冻结期限。如果业务属于平台代收,再向入驻用户结算,还需要申请适用于该场景的支付宝平台型产品,不能只靠普通转账接口绕过资质或资金合规要求。
推荐实现流程
1. 创建网页支付订单
服务端先生成唯一的商户订单号,并将订单保存到数据库:
CREATE TABLE payment_order (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
out_trade_no VARCHAR(64) NOT NULL UNIQUE,
amount DECIMAL(18, 2) NOT NULL,
payee_id VARCHAR(128) NOT NULL,
status VARCHAR(32) NOT NULL,
paid_at DATETIME NULL,
release_at DATETIME NULL,
transfer_no VARCHAR(64) NULL,
created_at DATETIME NOT NULL,
updated_at DATETIME NOT NULL
);
然后调用支付宝网页支付接口:
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
request.setReturnUrl("https://example.com/payment/return");
request.setNotifyUrl("https://example.com/payment/notify");
AlipayTradePagePayModel model = new AlipayTradePagePayModel();
model.setOutTradeNo(outTradeNo);
model.setTotalAmount("100.00");
model.setSubject("订单支付");
model.setProductCode("FAST_INSTANT_TRADE_PAY");
request.setBizModel(model);
String form = alipayClient.pageExecute(request).getBody();
商户系统应自行记录订单创建时间,不要使用浏览器页面传入的时间。
2. 根据异步通知确认支付结果
用户跳转回商户页面,并不能证明支付已经成功。支付结果应以支付宝异步通知为主,同时验证签名、金额、商户身份和订单状态。
Map<String, String> params = getNotifyParams(request);
boolean verified = AlipaySignature.rsaCheckV1(
params,
alipayPublicKey,
"UTF-8",
"RSA2"
);
if (!verified) {
return "failure";
}
String outTradeNo = params.get("out_trade_no");
String tradeStatus = params.get("trade_status");
String totalAmount = params.get("total_amount");
if ("TRADE_SUCCESS".equals(tradeStatus)
|| "TRADE_FINISHED".equals(tradeStatus)) {
// 在事务中完成以下操作:
// 1. 查询本地订单并核对金额、商户身份等信息
// 2. 通过状态条件防止重复处理
// 3. 记录实际支付成功时间
// 4. 计算15天后的下款时间
markPaid(outTradeNo, totalAmount);
}
return "success";
下款时间可由业务系统计算:
OffsetDateTime paidAt = OffsetDateTime.now(ZoneId.of("Asia/Shanghai"));
OffsetDateTime releaseAt = paidAt.plusDays(15);
还要提前明确“15 天”的计算口径,例如按精确的 15 × 24 小时计算,还是在第 15 个自然日的固定时间执行。最好在订单表中直接保存计算后的 release_at,以免定时任务每次都重新解释规则。
3. 定时扫描到期订单
支付宝支付接口通常不能充当“15 天后自动执行”的任务调度器。延迟执行需要由商户自己的定时任务或消息队列负责。
@Scheduled(fixedDelay = 60000)
public void releaseDuePayments() {
List<PaymentOrder> orders =
orderRepository.findDueOrdersForUpdate(100);
for (PaymentOrder order : orders) {
try {
transferService.transfer(order);
} catch (Exception e) {
// 记录失败原因,进入受控重试或人工审核流程
}
}
}
查询条件可以按以下思路设计:
SELECT *
FROM payment_order
WHERE status = 'PAID'
AND release_at <= CURRENT_TIMESTAMP
ORDER BY release_at
LIMIT 100;
在生产环境中,还需要使用数据库行锁、乐观锁或任务状态抢占机制,防止多台服务器重复下款。
4. 调用适合业务场景的资金接口
如果业务允许商户向支付宝账户转账,可以申请支付宝的资金转账类产品。部分接入方案使用的接口名称是:
alipay.fund.trans.uni.transfer
该接口是否仍适用于当前账户、支持哪些收款方标识、是否需要额外资质,以及各字段如何定义,都应以商户开放平台后台可签约的产品和当前官方文档为准。
调用结构示例如下:
AlipayFundTransUniTransferRequest request =
new AlipayFundTransUniTransferRequest();
AlipayFundTransUniTransferModel model =
new AlipayFundTransUniTransferModel();
model.setOutBizNo(transferNo);
model.setTransAmount("100.00");
model.setProductCode("TRANS_ACCOUNT_NO_PWD");
model.setBizScene("DIRECT_TRANSFER");
model.setOrderTitle("订单结算");
Participant payee = new Participant();
payee.setIdentity(userAlipayIdentity);
payee.setIdentityType(payeeIdentityType);
payee.setName(userRealName);
model.setPayeeInfo(payee);
request.setBizModel(model);
AlipayFundTransUniTransferResponse response =
alipayClient.certificateExecute(request);
if (response.isSuccess()) {
markTransferred(orderId, transferNo);
} else {
markTransferFailed(
orderId,
response.getCode(),
response.getSubCode(),
response.getSubMsg()
);
}
这段代码只用于说明调用结构,不能作为当前接口字段和产品权限的最终依据。identityType、收款方标识、实名信息要求和证书调用方式,都必须根据实际签约产品的文档进行配置。
如果资金需要在平台、商家或服务提供方之间分配,应优先咨询支付宝的分账、结算或平台型资金产品。这类业务在合同关系、资金流和接口能力上,与普通的“商户向个人转账”并不相同。
必须注意的问题
资金并不等于被支付宝冻结 15 天
在本地将订单标记为“待下款”,只能控制商户何时发起后续转账,无法改变支付宝对原支付交易的清算和结算规则。
如果要求商户在 15 天内不能支配这笔资金,需要向支付宝确认是否有符合该业务类型的担保、分账、延迟结算或平台资金管理方案。不能将普通支付和普通转账组合后,当作资金托管使用。
不要只保存支付宝登录账号
收款方标识必须符合具体资金产品的要求。不同产品可能要求支付宝用户标识、登录账号、会员标识或其他身份字段,不能默认手机号一定是有效的收款账号。
用户绑定账户时,还应完成必要的身份校验,并保存支付宝返回的稳定标识,避免用户修改手机号或邮箱后无法下款。
下款必须做到幂等
每次下款都应生成全局唯一的业务流水号,例如:
SETTLE_20260909_000001
如果发生网络超时,不要立即更换流水号再次转账,否则可能重复付款。应先使用原业务流水号查询处理结果,再判断是否需要重试。
下款前要重新检查订单
15 天到期后,至少需要检查:
- 订单是否支付成功;
- 是否已经退款或发生争议;
- 是否已取消结算;
- 收款人是否仍然有效;
- 下款金额是否被调整;
- 是否已经成功下款;
- 商户账户余额和接口权限是否正常。
订单状态可以设计为:
CREATED
PAYING
PAID
RELEASE_PENDING
TRANSFERRING
TRANSFERRED
TRANSFER_FAILED
CANCELLED
REFUNDED
需要处理退款与转账的关系
原支付订单的退款和后续转账是两笔不同的资金操作。如果款项已经转给用户,商户随后又向消费者全额退款,就可能承担额外损失。因此,业务规则需要明确以下事项:
- 15 天内是否允许退款;
- 退款后是否取消下款;
- 部分退款后如何计算下款金额;
- 下款后发生售后由谁承担;
- 争议订单是否自动暂停下款。
先确认业务资质
如果平台先收取消费者款项,15 天后再结算给平台用户、供应商或入驻商家,业务可能涉及平台资金结算、二清风险、实名校验和反洗钱要求。能否接入不能只看某个 API 是否存在。商户需要向支付宝服务商或官方渠道说明完整的资金链路,并以审核和签约结果为准。
技术上可以采用“网页支付 + 本地订单和定时任务 + 已签约的转账、分账或结算接口”这一方案。业务能否在支付宝上线,最终取决于实际经营场景、收款对象、账户类型和商户获批的产品权限。
备注:内容仅供参考。
