支付宝商家分账
商家分账,指资金在到达商家的支付宝账号后,支付宝根据商家传入的分账规则,将相应的资金从商家的支付宝账号划转至分账对象的支付宝账号。
分账成功后,资金实时转入收款方账号。目前分账分出金额最高不能超过订单金额的 30%。如果有更高分账金额诉求,可登录 [商家平台]> 账号中心 > 签约管理 > 商家分账 > 查看详情 > 修改信息 进行单独申请。
系统服务商在获得商家授权后,也可以代替商家进行分账。
名词 | 解释 |
---|---|
分账支出方 | 分账资金的转出方,即分账交易的收款方账户。分账金额默认从支出方支付宝账户余额出资,分账时请确保账户余额资金充足。 |
分账收入方 | 与实际收款商家有合作关系的第三方,比如服务商,软件供应商,供货商等,接收分账资金的商家或个人。 |
服务商 | 为实际收款商家提供各种产品,服务的提供方。 |
分账关系集 | 分账主体和分账收入方之间的关系,称为 “分账关系集” 。签约 “境内商家分账”,需要将分账收入方维护在 “分账关系集” 内,否则分账会被拦截。可以通过分账关系集维护接口来完成 “分账关系集” 的添加、删除和查询。 |
注意:需要签约分账功能
分账关系维护
分账关系绑定接口
package com.sin.demo.controller;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeRoyaltyRelationBindModel;
import com.alipay.api.domain.RoyaltyEntity;
import com.alipay.api.request.AlipayTradeRoyaltyRelationBindRequest;
import com.alipay.api.response.AlipayTradeRoyaltyRelationBindResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
/**
* @createTime 2024/4/22 14:42
* @createAuthor SIN
* @use 商户分账
*/
@RestController
public class AlipaySubAccountController {
// 从配置文件中获取参数值
@Value("${alipay.appId}")
private String appId; // 支付宝应用ID
@Value("${alipay.privateKey}")
private String privateKey; // 商户应用私钥
@Value("${alipay.publicKey}")
private String publicKey; // 支付宝公钥
@Value("${alipay.gatewayUrl}")
private String gatewayUrl; // 支付宝网关URL
/**
* 分账关系绑定接口
* @return API信息
* @throws AlipayApiException
*/
@GetMapping("/alipayTradeRoyaltyRelationBind")
public String alipayTradeRoyaltyRelationBind() throws AlipayApiException {
// 创建支付宝客户端
AlipayClient alipayClient = new DefaultAlipayClient(gatewayUrl, appId, privateKey, "json", "UTF-8", publicKey, "RSA2");
AlipayTradeRoyaltyRelationBindRequest request = new AlipayTradeRoyaltyRelationBindRequest();
// 分账关系绑定
AlipayTradeRoyaltyRelationBindModel model = new AlipayTradeRoyaltyRelationBindModel();
// 外部请求号,由商家自定义。32个字符以内,仅可包含字母、数字、下划线。需保证在商户端不重复。
model.setOutRequestNo("2019032200000001");
// 分账接收方列表,单次传入最多20个
List<RoyaltyEntity> receiverList = new ArrayList<RoyaltyEntity>();
// 分账主体信息
RoyaltyEntity receiverList0 = new RoyaltyEntity();
/**
* 分账接收方方类型。
* 支付宝账号对应的支付宝唯一用户号: userId
* 支付宝登录号: loginName
* 支付宝openId: openId
*/
receiverList0.setType("loginName");
/**
* 作为查询返回结果
* 分账收款方绑定时的支付宝登录号。分账关系绑定(alipay.trade.royalty.relation.bind)时,通过type为loginName绑定传入的支付宝登录号,若使用userId绑定则不返回。
*/
receiverList0.setBindLoginName("1824368***@qq.com");
/**
* 分账接收方真实姓名。
* 绑定分账关系时: 当分账方类型是userId时,本参数可以不传,若上传则进行校验不上传不会校验。
* 当分账方类型是loginName时,本参数必传。
* 解绑分账关系时:作为请求参数可不填,分账关系查询时不作为返回结果返回
*/
receiverList0.setName("黄**");
/**
* 作为查询返回结果:
* 当前userId对应的支付宝登录号。
* 当login_name与bind_login_name不相等时,表明该支付宝账户发生了登录号变更。
*/
receiverList0.setLoginName("1824368***@qq.com");
/**
* 分账接收方账号。
* 当分账方类型是userId时,本参数为用户的支付宝账号对应的支付宝唯一用户号,以2088开头的纯16位数字;
* 当分账方类型是loginName时,本参数为用户的支付宝登录号;
* 当分账方类型是openId时,本参数传递支付宝openId信息。
*/
receiverList0.setAccount("1824368***@qq.com");
// 分账关系描述
receiverList0.setMemo("分账给测试商户");
// 将关系添加到集合中
receiverList.add(receiverList0);
// 分账接收方列表,单次传入最多20个
model.setReceiverList(receiverList);
request.setBizModel(model);
AlipayTradeRoyaltyRelationBindResponse response = alipayClient.execute(request);
System.out.println(response.getBody());
if (response.isSuccess()) {
System.out.println("调用成功");
} else {
System.out.println("调用失败");
// sdk版本是"4.38.0.ALL"及以上,可以参考下面的示例获取诊断链接
// String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response);
// System.out.println(diagnosisUrl);
}
return response.getBody();
}
}
请求参数
参数 | 参数值 | 必选 | 描述 |
---|---|---|---|
receiver_list | RoyaltyEntity[] | 必选 | 分账接收方列表,单次传入最多20个 |
name | string(256) | 可选 | 分账接收方真实姓名。 绑定分账关系时: 当分账方类型是userId时,本参数可以不传,若上传则进行校验不上传不会校验。 当分账方类型是loginName时,本参数必传。 解绑分账关系时:作为请求参数可不填,分账关系查询时不作为返回结果返回 |
type | string(16) | 可选 | 支付宝账号对应的支付宝唯一用户号: userId;支付宝登录号: loginName;支付宝openId: openId |
account | string(32) | 可选 | 分账接收方账号。 当分账方类型是userId时,本参数为用户的支付宝账号对应的支付宝唯一用户号,以2088开头的纯16位数字; 当分账方类型是loginName时,本参数为用户的支付宝登录号;当分账方类型是openId时,本参数传递支付宝openId信息。 |
memo | string(256) | 可选 | 分账关系描述 |
login_name | string(150) | 可选 | 作为查询返回结果:当前userId对应的支付宝登录号。当login_name与bind_login_name不相等时,表明该支付宝账户发生了登录号变更。 |
bind_login_name | string(150) | 可选 | 作为查询返回结果:分账收款方绑定时的支付宝登录号。分账关系绑定(alipay.trade.royalty.relation.bind)时,通过type为loginName绑定传入的支付宝登录号,若使用userId绑定则不返回。 |
out_request_no | string(32) | 可选 | 外部请求号,由商家自定义。32个字符以内,仅可包含字母、数字、下划线。需保证在商户端不重复。 |
分账关系查询接口
/**
* 分账关系查询接口
* @return
* @throws AlipayApiException
*/
@GetMapping("/alipayTradeRoyaltyRelationBatchquery")
public String alipayTradeRoyaltyRelationBatchquery() throws AlipayApiException {
// 创建支付宝客户端
AlipayClient alipayClient = new DefaultAlipayClient(gatewayUrl, appId, privateKey, "json", "UTF-8", publicKey, "RSA2");
AlipayTradeRoyaltyRelationBatchqueryRequest request = new AlipayTradeRoyaltyRelationBatchqueryRequest();
// 分账关系查询
AlipayTradeRoyaltyRelationBatchqueryModel model = new AlipayTradeRoyaltyRelationBatchqueryModel();
// 页面大小。每页记录数,取值范围是(0,100]。不填默认为20
model.setPageSize(20L);
// 外部请求号,由商家自定义。32个字符以内,仅可包含字母、数字、下划线。需保证在商户端不重复。
model.setOutRequestNo("2019032200000001");
// 几页,起始页为 1。不填默认为 1。
model.setPageNum(1L);
request.setBizModel(model);
AlipayTradeRoyaltyRelationBatchqueryResponse response = alipayClient.execute(request);
System.out.println(response.getBody());
if (response.isSuccess()) {
System.out.println("调用成功");
} else {
System.out.println("调用失败");
// sdk版本是"4.38.0.ALL"及以上,可以参考下面的示例获取诊断链接
// String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response);
// System.out.println(diagnosisUrl);
}
return response.getBody();
}
请求参数
参数 | 参数值 | 必选 | 描述 |
---|---|---|---|
out_request_no | string(32) | 必选 | 外部请求号,由商家自定义。32个字符以内,仅可包含字母、数字、下划线。需保证在商户端不重复。 |
page_num | number(4) | 可选 | 几页,起始页为 1。不填默认为 1。 |
page_size | number(4) | 可选 | 页面大小。每页记录数,取值范围是(0,100]。不填默认为20 |
响应参数
{
"alipay_trade_royalty_relation_batchquery_response": {
"code": "10000",
"msg": "Success",
"current_page_num": 1, // 当前页数
"current_page_size": 20, // 当前页面大小
"receiver_list": [ // 分账收款方列表
{
"account": "2088432233600322", // 分账接收方账号
"bind_login_name": "1824368***@qq.com", //分账收款方绑定时的支付宝登录号
"login_name": "1824368***@qq.com", // 作为查询返回结果
"memo": "分账给测试商户", // 分账关系描述
"type": "userId" // 分账接收方方类型
}
],
"result_code": "SUCCESS", // 业务结果码
"total_page_num": 1, // 总页数
"total_record_num": 1 // 分账关系记录总数
},
"sign": "iTa/gV4v59ct/W6bPAoZEr/IPgyBE3P0dpQsr8senflaJyXODoVeCBKzXU8Y1cd4gISlZInTFSdA9TOkmkFvzNUOGIMwzpmC8o2UxCbLFMnBhnxXbcf1+DjtSKlDtXqLdgxpv*****ir3u1Nm9fWRlp2QP92ihGe+P+5V4ngPfp6bCEjQ35bomP4SyD7Yyb0BWb56FojrqMF1WEvVswDVIhoLWgngZRamXOOR+Njf86co5+0dI4ItSf8GVBQ=="
}
分账关系解除接口
/**
* 分账关系接触接口
* @return
* @throws AlipayApiException
*/
@GetMapping("/alipayTradeRoyaltyRelationUnbind")
public String alipayTradeRoyaltyRelationUnbind() throws AlipayApiException {
// 创建支付宝客户端
AlipayClient alipayClient = new DefaultAlipayClient(gatewayUrl, appId, privateKey, "json", "UTF-8", publicKey, "RSA2");
AlipayTradeRoyaltyRelationUnbindRequest request = new AlipayTradeRoyaltyRelationUnbindRequest();
AlipayTradeRoyaltyRelationUnbindModel model = new AlipayTradeRoyaltyRelationUnbindModel();
model.setOutRequestNo("2019032200000001");
List<RoyaltyEntity> receiverList = new ArrayList<RoyaltyEntity>();
RoyaltyEntity receiverList0 = new RoyaltyEntity();
/**
* 分账接收方方类型。
* 支付宝账号对应的支付宝唯一用户号: userId
* 支付宝登录号: loginName
* 支付宝openId: openId
*/
receiverList0.setType("loginName");
/**
* 作为查询返回结果
* 分账收款方绑定时的支付宝登录号。分账关系绑定(alipay.trade.royalty.relation.bind)时,通过type为loginName绑定传入的支付宝登录号,若使用userId绑定则不返回。
*/
receiverList0.setBindLoginName("1824368***@qq.com");
/**
* 分账接收方真实姓名。
* 绑定分账关系时: 当分账方类型是userId时,本参数可以不传,若上传则进行校验不上传不会校验。
* 当分账方类型是loginName时,本参数必传。
* 解绑分账关系时:作为请求参数可不填,分账关系查询时不作为返回结果返回
*/
receiverList0.setName("黄**");
/**
* 作为查询返回结果:
* 当前userId对应的支付宝登录号。
* 当login_name与bind_login_name不相等时,表明该支付宝账户发生了登录号变更。
*/
receiverList0.setLoginName("1824368***@qq.com");
/**
* 分账接收方账号。
* 当分账方类型是userId时,本参数为用户的支付宝账号对应的支付宝唯一用户号,以2088开头的纯16位数字;
* 当分账方类型是loginName时,本参数为用户的支付宝登录号;
* 当分账方类型是openId时,本参数传递支付宝openId信息。
*/
receiverList0.setAccount("1824368***@qq.com");
// 分账关系描述
receiverList0.setMemo("分账给测试商户");
receiverList.add(receiverList0);
model.setReceiverList(receiverList);
request.setBizModel(model);
AlipayTradeRoyaltyRelationUnbindResponse response = alipayClient.execute(request);
System.out.println(response.getBody());
if (response.isSuccess()) {
System.out.println("调用成功");
} else {
System.out.println("调用失败");
// sdk版本是"4.38.0.ALL"及以上,可以参考下面的示例获取诊断链接
// String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response);
// System.out.println(diagnosisUrl);
}
return response.getBody();
}
请求参数
参数 | 参数值 | 必选 | 描述 |
---|---|---|---|
receiver_list | RoyaltyEntity[] | 必选 | 分账接收方列表,单次传入最多20个 |
name | string(256) | 可选 | 分账接收方真实姓名。 绑定分账关系时: 当分账方类型是userId时,本参数可以不传,若上传则进行校验不上传不会校验。 当分账方类型是loginName时,本参数必传。 解绑分账关系时:作为请求参数可不填,分账关系查询时不作为返回结果返回 |
type | string(16) | 可选 | 支付宝账号对应的支付宝唯一用户号: userId;支付宝登录号: loginName;支付宝openId: openId |
account | string(32) | 可选 | 分账接收方账号。 当分账方类型是userId时,本参数为用户的支付宝账号对应的支付宝唯一用户号,以2088开头的纯16位数字; 当分账方类型是loginName时,本参数为用户的支付宝登录号;当分账方类型是openId时,本参数传递支付宝openId信息。 |
memo | string(256) | 可选 | 分账关系描述 |
login_name | string(150) | 可选 | 作为查询返回结果:当前userId对应的支付宝登录号。当login_name与bind_login_name不相等时,表明该支付宝账户发生了登录号变更。 |
bind_login_name | string(150) | 可选 | 作为查询返回结果:分账收款方绑定时的支付宝登录号。分账关系绑定(alipay.trade.royalty.relation.bind)时,通过type为loginName绑定传入的支付宝登录号,若使用userId绑定则不返回。 |
out_request_no | string(32) | 可选 | 外部请求号,由商家自定义。32个字符以内,仅可包含字母、数字、下划线。需保证在商户端不重复。 |
分账请求
统一收单交易结算接口
/**
* 分账统一收单交易结算接口
* @return
* @throws AlipayApiException
*/
@GetMapping("/alipayTradeOrderSettle")
public String alipayTradeOrderSettle() throws AlipayApiException {
// 创建支付宝客户端
AlipayClient alipayClient = new DefaultAlipayClient(gatewayUrl, appId, privateKey, "json", "UTF-8", publicKey, "RSA2");
// 构造请求参数以调用接口
AlipayTradeOrderSettleRequest request = new AlipayTradeOrderSettleRequest();
AlipayTradeOrderSettleModel model = new AlipayTradeOrderSettleModel();
// 结算请求流水号,由商家自定义。32个字符以内,仅可包含字母、数字、下划线。需保证在商户端不重复
model.setOutRequestNo("2019032200000001");
// 设置支付宝订单号
model.setTradeNo("2024042222001400321445612359");
// 设置分账明细信息
List<OpenApiRoyaltyDetailInfoPojo> royaltyParameters = new ArrayList<OpenApiRoyaltyDetailInfoPojo>();
// 增加资产类型
OpenApiRoyaltyDetailInfoPojo royaltyParameters0 = new OpenApiRoyaltyDetailInfoPojo();
/**
* 分账类型
* 分账: transfer
* 营销补差: replenish
*
*/
royaltyParameters0.setRoyaltyType("transfer");
/**
* 收入方类型
* 支付宝账号对应的支付宝唯一用户号: userId
* 支付宝登录号: loginName
* 卡编号: cardAliasNo
*/
royaltyParameters0.setTransInType("loginName");
/**
* 收入方账户。
* 如果收入方账户类型为userId,本参数为收入方的支付宝账号对应的支付宝唯一用户号,以2088开头的纯16位数字;
* 如果收入方类型为cardAliasNo,本参数为收入方在支付宝绑定的卡编号;
* 如果收入方类型为loginName,本参数为收入方的支付宝登录号;
*/
royaltyParameters0.setTransIn("1824368699@qq.com");
/**
* 分账的金额,单位为元
*/
royaltyParameters0.setAmount("0.3");
/**
* 分账的描述
*/
royaltyParameters0.setDesc("分账给2088101126708402");
royaltyParameters.add(royaltyParameters0);
model.setRoyaltyParameters(royaltyParameters);
request.setBizModel(model);
AlipayTradeOrderSettleResponse response = alipayClient.execute(request);
System.out.println(response.getBody());
if (response.isSuccess()) {
System.out.println("调用成功");
} else {
System.out.println("调用失败");
// sdk版本是"4.38.0.ALL"及以上,可以参考下面的示例获取诊断链接
// String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response);
// System.out.println(diagnosisUrl);
}
return response.getBody();
}
注意:必须支付成功,再将订单号导入进去进行分销(不是商户订单)
请求参数
参数 | 参数值 | 必选 | 描述 |
---|---|---|---|
out_request_no | string(64) | 必选 | 结算请求流水号,由商家自定义。32个字符以内,仅可包含字母、数字、下划线。需保证在商户端不重复。 |
trade_no | string(64) | 必选 | 支付宝订单号 |
royalty_parameters | OpenApiRoyaltyDetailInfoPojo[] | 必选 | 分账明细信息。单独调用分账完结时,可以不传此参数。其他场景必传。 注意:商家分账场景下分账收入方 trans_in 只支持支付宝账户,不支持使用 cardAliasNo 卡编号。 |
trans_in | string(16) | 必选 | 收入方账户。如果收入方账户类型为userId,本参数为收入方的支付宝账号对应的支付宝唯一用户号,以2088开头的纯16位数字;如果收入方类型为cardAliasNo,本参数为收入方在支付宝绑定的卡编号;如果收入方类型为loginName,本参数为收入方的支付宝登录号; |
royalty_type | 分账: transfer;分账: transfer | 可选 | 分账类型. |
trans_out | string(16) | 可选 | 支出方账户。如果支出方账户类型为userId,本参数为支出方的支付宝账号对应的支付宝唯一用户号,以2088开头的纯16位数字;如果支出方类型为loginName,本参数为支出方的支付宝登录号。 泛金融类商户分账时,该字段不要上送。 |
trans_out_type | string(64) | 可选 | 支付宝账号对应的支付宝唯一用户号: userId;支付宝登录号: loginName |
trans_in_type | string(64) | 可选 | 收入方账户类型。 |
amount | price(9) | 可选 | 分账的金额,单位为元 |
desc | string(1000) | 可选 | 分账描述 |
royalty_scene | string(256) | 可选 | 可选值:达人佣金、平台服务费、技术服务费、其他 |
trans_in_name | string(64) | 可选 | 分账收款方姓名,上送则进行姓名与支付宝账号的一致性校验,校验不一致则分账失败。不上送则不进行姓名校验 |
operator_id | string(64) | 可选 | 操作员 ID,商家自定义操作员编号 |
extend_params | SettleExtendParam | 可选 | 分账结算业务扩展参数 |
royalty_finish | string(64) | 可选 | 冻结分账场景下生效,其他场景传入无效。 代表该交易分账是否完结,可选值:true/false,不传默认为false。 true:代表分账完结,则本次分账处理完成后会把该笔交易的剩余冻结金额全额解冻。 false:代表分账未完结。 |
royalty_mode | string(32) | 可选 | 同步执行: sync;同步执行: sync |
分账查询
分账比例查询接口
/**
* 分账比例查询接口
* @return
* @throws AlipayApiException
*/
@GetMapping("/alipayTradeRoyaltyRateQuery")
public String alipayTradeRoyaltyRateQuery() throws AlipayApiException {
// 创建支付宝客户端
AlipayClient alipayClient = new DefaultAlipayClient(gatewayUrl, appId, privateKey, "json", "UTF-8", publicKey, "RSA2");
AlipayTradeRoyaltyRateQueryRequest request = new AlipayTradeRoyaltyRateQueryRequest();
AlipayTradeRoyaltyRateQueryModel model = new AlipayTradeRoyaltyRateQueryModel();
// 外部请求号,由商家自定义。32个字符以内,仅可包含字母、数字、下划线。需保证在商户端不重复
model.setOutRequestNo("2019032200000001");
request.setBizModel(model);
AlipayTradeRoyaltyRateQueryResponse response = alipayClient.execute(request);
System.out.println(response.getBody());
if (response.isSuccess()) {
System.out.println("调用成功");
} else {
System.out.println("调用失败");
// sdk版本是"4.38.0.ALL"及以上,可以参考下面的示例获取诊断链接
// String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response);
// System.out.println(diagnosisUrl);
}
return response.getBody();
}
请求参数
参数 | 参数值 | 必填 | 说明 |
---|---|---|---|
out_request_no | string(32) | 必填 | 外部请求号,由商家自定义。32个字符以内,仅可包含字母、数字、下划线。需保证在商户端不重复。 |
响应参数
{
"alipay_trade_royalty_rate_query_response": {
"code": "10000",
"msg": "Success",
"max_ratio": 30, // 最大分账比例,百分比整数
"user_id": "208893214561*****" // 当前商户userId
},
"sign": "qHN4KT8rHfHyBZOe2QI0tqyU5jV1jGo2q0*******wwPtVlH+Rinrlgb8d9Sg8P4AtVou3LCpJ7MGIumUH751RcVUVNlLByhi0wLqysNQi4vRpWNopBe2RsSLFtZS6eoVbOYM4q4Ha5qPCg=="
}