支付宝API支付是否按笔收费及实际到账金额说明
结论
支付宝不会因为商户”调用一次 API”就固定收取一笔费用。交易手续费是否收取、费率是多少、如何结算,要看商户签约的支付产品、所属行业、费率协议、优惠政策和结算规则。API 调用次数和交易手续费是两回事。
异步通知中的 receipt_amount 指”商家在交易中实际收到的款项”,也就是商家在该笔交易支付环节实际收取的金额。它不一定是扣除支付宝逐笔手续费后的净到账金额。交易服务费可能单独记账、汇总扣收,或按照协议结算,因此不能只看 receipt_amount 来判断最终净收益。
金额字段如何理解
支付宝交易通知中常见的金额字段有:
total_amount:订单总金额。buyer_pay_amount:买家实际支付金额。receipt_amount:商家在该笔交易中实际收到的款项。point_amount:使用积分支付的金额。invoice_amount:可开具发票的金额。
这些字段描述的是交易本身的资金构成,不等于商户最终的财务结算结果。
例如,一笔订单金额为 100 元。如果买家使用了平台优惠、商家优惠或积分,total_amount、buyer_pay_amount 和 receipt_amount 可能并不相同。即使 receipt_amount 是 100 元,也不能据此认定支付宝没有收取服务费。反过来,也不能直接把 total_amount - receipt_amount 当作手续费。
是否按每笔交易收费,应以支付宝商家平台中的产品签约信息和费率协议为准。常见的计费方式可能是交易金额乘以约定费率,但具体规则仍要结合商户合同判断。
正确的核对方法
可以按以下顺序核对:
- 登录支付宝商家平台,检查当前应用对应的支付产品及签约状态。
- 查看签约协议中约定的费率、免费额度、优惠期、计费范围和手续费扣收方式。
- 保存异步通知中的
trade_no、out_trade_no、total_amount、buyer_pay_amount和receipt_amount。 - 下载支付宝账单或调用账单下载接口,核对交易明细、业务明细和资金明细。
- 根据账单中的服务费记录、资金收支记录和实际结算记录,计算净到账金额。
财务上的净到账金额通常要按账务记录计算,不能只根据通知字段推算:
净到账金额 = 交易收入 - 服务费 - 退款支出 - 其他调整项
具体应包含哪些项目,以商户签约协议和支付宝账单的统计口径为准。
异步通知处理示例
下面的 Java 示例演示了如何验签并保存通知中的金额字段。其中,receipt_amount 只作为交易金额信息保存,不直接标记为”已扣手续费金额”。
Map<String, String> params = new HashMap<>();
for (Map.Entry<String, String[]> entry : request.getParameterMap().entrySet()) {
String value = String.join(",", entry.getValue());
params.put(entry.getKey(), value);
}
boolean verified = AlipaySignature.rsaCheckV1(
params,
ALIPAY_PUBLIC_KEY,
"UTF-8",
"RSA2"
);
if (!verified) {
response.getWriter().write("failure");
return;
}
String appId = params.get("app_id");
String outTradeNo = params.get("out_trade_no");
String tradeNo = params.get("trade_no");
String tradeStatus = params.get("trade_status");
BigDecimal totalAmount =
new BigDecimal(params.getOrDefault("total_amount", "0"));
BigDecimal buyerPayAmount =
new BigDecimal(params.getOrDefault("buyer_pay_amount", "0"));
BigDecimal receiptAmount =
new BigDecimal(params.getOrDefault("receipt_amount", "0"));
if (!EXPECTED_APP_ID.equals(appId)) {
response.getWriter().write("failure");
return;
}
Order order = orderService.findByOutTradeNo(outTradeNo);
if (order == null || totalAmount.compareTo(order.getOrderAmount()) != 0) {
response.getWriter().write("failure");
return;
}
if ("TRADE_SUCCESS".equals(tradeStatus)
|| "TRADE_FINISHED".equals(tradeStatus)) {
orderService.markPaid(
outTradeNo,
tradeNo,
totalAmount,
buyerPayAmount,
receiptAmount
);
}
response.getWriter().write("success");
不要使用下面的方式计算手续费:
BigDecimal fee = totalAmount.subtract(receiptAmount);
两者的差额可能来自优惠、积分或其他资金构成,不一定是支付宝服务费。手续费应从支付宝账单或明确的计费明细中获取。
注意事项
异步通知用于传递交易状态和相关交易数据,不能代替财务对账。接收通知时还要注意:
- 必须验证支付宝签名。
- 必须校验
app_id、out_trade_no和订单金额。 - 通知可能重复发送,业务处理必须保证幂等。
- 金额应使用
BigDecimal,不要使用float或double。 - 不要根据单个通知字段自行推算费率。
- 退款、部分退款和后续调账会改变最终的资金结果。
- 如果合同约定汇总扣收服务费,单笔通知中的
receipt_amount更不能视为净到账金额。
receipt_amount 可以用来记录商家在该笔交易中的实收金额,但商户最终实际到账金额和手续费金额,仍应以签约规则、资金流水及支付宝账单为准。
备注:内容仅供参考。
