微信支付服务商分账流程解析
以下是具体流程
第一部分 必读:核心概念与角色说明
1.1 什么是服务商分账
微信支付「服务商分账」是指:服务商(即平台方)代替其旗下的特约商户(即子商户)发起支付交易后,把这笔订单的部分资金,按指定金额分给一个或多个『分账接收方』的能力。
典型场景:
● 平台抽佣:子商户收款后,平台从中抽取服务费。
● 供应链分账:把交易款分给上游供应商、下游达人、合作伙伴等。
● 多门店结算:连锁品牌总部向各分店或加盟商分账。
|
⚠️ 注意:微信支付『只接受按金额分账,不接受按比例分账』。若需按比例分账,请自行计算好比例对应的金额后再调用接口。比例的作用是限制『最多能分多少』,不是分账方式。 |
【分账业务流程图】以下为微信支付官方业务流程:

▲ 微信支付特约商户进件 + 分账全流程图(来源:官方文档 4012062375)
流程图官方说明:https://pay.weixin.qq.com/doc/v3/partner/4012062375
1.2 四大角色说明
【分账产品模型图】以下为微信支付官方产品模型图:

▲ 分账产品模型图:分账发起方 → 分账方 → 接收方(来源:官方文档 4015870957)
产品模型官方说明:https://pay.weixin.qq.com/doc/v3/partner/4015870957
|
角色 |
说明 |
注意 |
示例标识 |
|
服务商(分账发起方) |
即您自己。已认证的企业服务号申请成为微信支付服务商。替子商户发起交易,并由其调用分账接口。 |
无独立商户号无法收款 |
商户号 19xxxxxxxx |
|
特约商户(分账方/子商户) |
在服务商旗下入驻的商户。每笔订单的实际收款方,分账资金从其订单中扣除。 |
服务商必须先有子商户才能交易 |
子商户号 16xxxxxxxx |
|
分账接收方 |
接收分账资金的一方。可以是微信支付商户号,也可以是微信用户的个人零钱账户。 |
分账前必须先建立接收方关系 |
商户号 / openid |
|
微信支付平台 |
提供分账能力、资金清算与冻结/解冻。 |
服务商不直接接触资金 |
— |
【角色关系图解】
● 服务商 → 替子商户发起交易 → 资金进入子商户账户(被冻结)
● 服务商 → 调用分账接口 → 把冻结资金的一部分分给接收方
● 剩余资金 → 自动解冻给子商户
● 分账接收方 → 收到资金后手动提现到银行账户
1.3 整体流程总览
从 0 到代码跑通,需要依次完成下面 6 步:
1. 成为微信支付服务商(注册服务号 → 微信认证 → 申请服务商)
2. 开通『服务商分账』产品(服务商平台一键开通)
3. 添加子服务商/特约商户(手动进件或商家扫码入驻)
4. 配置分账接收方(接口添加或商户平台手动添加)
5. 设置分账比例(子商户在商户平台设置,默认最大 30%)
6. 代码开发(下单传 profit_sharing=true → 调请求分账 → 查询结果 → 完结)
|
ℹ️ 提示:本文档接下来按这 6 步顺序展开,每一步都标注『入口网址』『页面路径』『填写内容』『对应截图』。非技术人员请按顺序操作,遇到截图请对照屏幕找位置。 |
第二部分 第一步:成为微信支付服务商
|
⚠️ 注意:前提条件:你已经是『通过微信认证的企业类型服务号』。个体户、未认证的服务号无法申请。 |
【服务商申请全流程图】

▲ 服务商申请流程图(来源:微信支付官方文档 4012062375)
流程图官方说明:https://pay.weixin.qq.com/doc/v3/partner/4012062375
2.1 注册企业类型服务号
【什么是服务号?】服务号是微信公众平台上的一种账号类型,类似企业的『官方微信』,可以让企业在微信里推送消息、提供服务、接通微信支付。
【为什么必须是服务号?】订阅号不能开通微信支付,只有服务号才能申请服务商资格。
访问入口:https://mp.weixin.qq.com/
步骤 1:打开微信公众平台
7. 在浏览器地址栏输入:https://mp.weixin.qq.com/
8. 页面右上角点击『立即注册』蓝色按钮。

▲ 操作路径:打开浏览器 → 输入网址 → 点击立即注册
|
ℹ️ 提示:注册页实际显示请直接访问 https://mp.weixin.qq/ 点击右上角『立即注册』查看,按页面提示选择『服务号』类型。 |
步骤 2:选择账号类型
9. 在弹出的账号类型选择页,点击『服务号』图标。
10. 注意:必须选『服务号』,不要选订阅号。订阅号无法开通微信支付。
11. 为什么必须服务号?因为微信支付的功能模块只对接服务号(或小程序),订阅号没有支付接口。

▲ 操作路径:账号类型页 → 找到服务号图标 → 点击选择
步骤 3:填写邮箱密码
12. 填写一个『未绑定过任何微信产品』的邮箱作为登录账号。
13. 【重要】这个邮箱不能绑定过任何个人微信、公众号、小程序、开放平台账号。建议用公司新注册的企业邮箱。
14. 密码:8 位以上,含字母数字,区分大小写。
15. 点击『注册』按钮。

▲ 操作路径:填写邮箱 → 设置密码 → 点击注册
步骤 4:邮箱激活
16. 登录刚才填写的邮箱,查收来自 weixin-team@tencent.com 的激活邮件。
17. 【如果没收到邮件】检查垃圾邮件、广告邮件文件夹;或登录 mp.weixin.qq.com 重新发送激活邮件。
18. 点击邮件中的激活链接,链接会自动跳回微信公众平台继续填写资料。
19. 【链接有效期】激活链接 24 小时内有效,过期需重新发送。

▲ 操作路径:登录邮箱 → 查收激活邮件 → 点击激活链接
步骤 5:选择主体类型与注册方式
20. 主体类型选择『企业』(不要选个体工商户或政府机关)。
21. 注册方式选择『微信认证』(注册并立即申请认证)。
22. 企业全称:与营业执照上『名称』完全一致,含括号、全角字符。
23. 营业执照注册号:18 位统一社会信用代码。

▲ 操作路径:选企业 → 选微信认证 → 填写企业信息

▲ 分账产品模型图:您即将成为『分账发起方』(来源:4015870957)
步骤 6:提交主体信息登记
▲ 步骤三:安装证书工具,选择存储路径,点击申请证书

▲ 步骤四:将商户号和商户名称粘贴到证书工具
步骤 5-6:复制证书请求串,粘贴到商户平台
253. 在证书工具中,复制证书请求串
254. 回到商户平台
255. 将证书工具中复制的请求串粘贴到商户平台文本框中
256. 点击『下一步』

▲ 步骤五:在证书工具中复制证书请求串

▲ 步骤六:将请求串粘贴到商户平台文本框
步骤 7-8:安全验证,复制证书串
257. 安全验证:输入操作密码 + 短信验证码
258. 点击『确定』
259. 在商户平台『复制证书串』环节,点击『复制证书串』

▲ 步骤七:安全验证,输入操作密码和短信验证码

▲ 步骤八:在商户平台复制证书串
步骤 9-10:粘贴证书串到工具,完成申请
260. 将商户平台复制的证书串粘贴到证书工具中
261. 点击『下一步』
262. 申请商户API证书成功
263. 点击『查看证书文件夹』,查看已生成的证书文件

▲ 步骤九:将证书串粘贴到证书工具

▲ 步骤十:申请成功,查看证书文件夹
【证书文件说明】生成后的证书文件为压缩包,解压后有 4 个文件:

▲ 证书文件解压后的4个文件:p12格式、pem格式、私钥pem格式、说明文件
● apiclient_cert.p12:p12 格式证书(APIv2 用)
● apiclient_cert.pem:pem 格式证书
● apiclient_key.pem:证书私钥(APIv3 签名用,最重要!)
● README.md:说明文件
|
❌ 重要:请将生成的证书文件转交给技术人员,由技术人员将证书部署到服务器上。私钥文件 apiclient_key.pem 只能通过证书工具导出,若丢失无法找回,只能作废重新申请。 |
证书申请完整官方文档:https://pay.weixin.qq.com/doc/v3/partner/4013058924
7.2 业务流程
完整分账流程(来自微信支付官方业务流程图):
264. 下单时传 profit_sharing=true(标识为分账订单)。
265. 用户支付成功,资金进入『冻结池』(默认冻结期 30 天,电商分账 180 天)。
266. 调用『添加分账接收方』接口建立接收方关系(一次性,已添加可跳过)。
267. 调用『请求分账』接口发起分账(接口异步受理,返回 order_id 不代表成功)。
268. 调用『查询分账结果』接口轮询/查询分账最终结果。
269. (可选)调用『完结分账』接口把剩余资金解冻给分账方。
270. (如退款)先调用『请求分账回退』把已分资金回退,再处理退款。
7.3 接口清单
|
接口名称 |
方法 |
路径 |
用途 |
|
添加分账接收方 |
POST |
/v3/profitsharing/receivers/add |
建立分账关系 |
|
删除分账接收方 |
POST |
/v3/profitsharing/receivers/delete |
解除分账关系 |
|
请求分账 |
POST |
/v3/profitsharing/orders |
发起分账,异步受理 |
|
查询分账结果 |
GET |
/v3/profitsharing/orders/{out_order_no} |
查询分账最终结果 |
|
完结分账 |
POST |
/v3/profitsharing/orders/{out_order_no}/finish |
解冻剩余资金给分账方 |
|
查询订单剩余待分金额 |
GET |
/v3/profitsharing/transactions/{transaction_id}/amounts |
查可分余额 |
|
请求分账回退 |
POST |
/v3/profitsharing/returns |
已分资金回退 |
|
查询分账回退结果 |
GET |
/v3/profitsharing/returns/{out_return_no} |
查回退结果 |
|
分账动账通知 |
POST(回调) |
商户配置的 notify_url |
分账/回退结果异步通知 |
7.4 完整 Java 代码示例
以下代码基于微信支付 APIv3 + Apache HttpClient,可直接放进 Spring Boot 项目。参数需替换为您自己的商户号、证书路径等。
|
ℹ️ 提示:代码来源:微信支付官方示例 https://pay.weixin.qq.com/doc/v3/partner/4015870957,已整理为可执行片段。 |

▲ 分账产品模型图:分账发起方 → 分账方 → 接收方(来源:官方文档 4015870957)

▲ 代码对接全流程时序图(来源:微信支付官方文档 4012062375)
7.4.1 创建 HttpClient(带签名验证)
|
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder; import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner; import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials; import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator; import com.wechat.pay.contrib.apache.httpclient.util.PemUtil; import org.apache.http.impl.client.CloseableHttpClient;
import java.io.FileInputStream; import java.security.PrivateKey;
public class WxPayClient { // ===== 替换成自己的参数 ===== private static final String MCH_ID = "1900000108"; // 服务商商户号 private static final String MCH_SERIAL = "xxxxxxxxxxxx"; // 商户API证书序列号 private static final String API_V3_KEY = "xxxxxxxxxxxx"; // APIv3 密钥 private static final String KEY_PATH = "C:/cert/apiclient_key.pem"; // 商户私钥文件
private static CloseableHttpClient httpClient;
static { try { PrivateKey privateKey = PemUtil.loadPrivateKey( new FileInputStream(KEY_PATH)); httpClient = WechatPayHttpClientBuilder.create() .withMerchant(MCH_ID, MCH_SERIAL, privateKey) .withValidator(new WechatPay2Validator( // 自动获取并校验微信支付平台证书 CertManagerSingleton.getCertManager(API_V3_KEY).getVerifier())) .build(); } catch (Exception e) { throw new RuntimeException("初始化微信支付 HttpClient 失败", e); } }
public static CloseableHttpClient getClient() { return httpClient; } } |
7.4.2 添加分账接收方
添加接收方接口文档:https://pay.weixin.qq.com/doc/v3/partner/4012477758

▲ 接收方添加成功后可在商户平台查看(来源:官方文档 4013058924)
|
import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpResponse; import org.apache.http.util.EntityUtils;
public class AddReceiver { /** * 添加分账接收方 * 接口:POST /v3/profitsharing/receivers/add * 文档:https://pay.weixin.qq.com/doc/v3/partner/4012690944 */ public static String addReceiver(String subMchid, String receiverAccount) throws Exception { String url = "https://api.mch.weixin.qq.com/v3/profitsharing/receivers/add";
// 请求体 JSON String reqdata = "{" + "\"sub_mchid\":\"" + subMchid + "\"," + "\"appid\":\"wx8888888888888888\"," // 服务商 AppID + "\"receivers\":[{" + "\"type\":\"MERCHANT_ID\"," // 接收方类型:商户号 + "\"account\":\"" + receiverAccount + "\"," // 接收方商户号 + "\"name\":\"某某合作公司\"," // 接收方名称(需用微信支付公钥加密) + "\"relation_type\":\"PARTNER\" // 关系类型:合作伙伴 + "}]" + "}";
HttpPost httpPost = new HttpPost(url); httpPost.addHeader("Accept", "application/json"); httpPost.addHeader("Content-Type", "application/json"); // Wechatpay-Serial 头:填微信支付公钥ID或平台证书序列号 httpPost.addHeader("Wechatpay-Serial", "PUB_KEY_ID_xxx"); httpPost.setEntity(new StringEntity(reqdata, "utf-8"));
try (CloseableHttpResponse response = WxPayClient.getClient().execute(httpPost)) { int code = response.getStatusLine().getStatusCode(); String body = EntityUtils.toString(response.getEntity()); if (code == 200) { System.out.println("添加分账接收方成功:" + body); return body; } else { throw new RuntimeException("添加失败:" + code + " " + body); } } } } |
7.4.3 请求分账
请求分账接口文档:https://pay.weixin.qq.com/doc/v3/partner/4012691594

▲ 分账产品模型图:请求分账对应图中『分账发起方 → 接收方』的资金流向(来源:4015870957)
|
public class CreateProfitSharing { /** * 请求分账 * 接口:POST /v3/profitsharing/orders * 文档:https://pay.weixin.qq.com/doc/v3/partner/4012692975 */ public static String create(String subMchid, String transactionId, String outOrderNo, String receiverAccount, int amount) throws Exception { String url = "https://api.mch.weixin.qq.com/v3/profitsharing/orders";
// 关键:分账金额单位是「分」,100 = 1 元 // receivers.amount 总和 ≤ 订单金额 × 子商户设置的最大分账比例 String reqdata = "{" + "\"sub_mchid\":\"" + subMchid + "\"," + "\"appid\":\"wx8888888888888888\"," + "\"transaction_id\":\"" + transactionId + "\"," // 微信支付订单号 + "\"out_order_no\":\"" + outOrderNo + "\"," // 商户分账单号,商户系统内唯一 + "\"receivers\":[{" + "\"type\":\"MERCHANT_ID\"," + "\"account\":\"" + receiverAccount + "\"," // 接收方商户号 + "\"amount\":" + amount + "," // 分账金额,单位:分 + "\"description\":\"订单" + transactionId + "分账给" + receiverAccount + "\"" + "}]," + "\"unfreeze_unsplit\":false" // false=不解冻剩余;true=完结分账 + "}";
HttpPost httpPost = new HttpPost(url); httpPost.addHeader("Accept", "application/json"); httpPost.addHeader("Content-Type", "application/json"); httpPost.addHeader("Wechatpay-Serial", "PUB_KEY_ID_xxx"); httpPost.setEntity(new StringEntity(reqdata, "utf-8"));
try (CloseableHttpResponse response = WxPayClient.getClient().execute(httpPost)) { int code = response.getStatusLine().getStatusCode(); String body = EntityUtils.toString(response.getEntity()); // 202 = 受理成功(不是最终分账结果!需后续查询) if (code == 200 || code == 202) { System.out.println("分账受理成功:" + body); return body; } else { throw new RuntimeException("分账失败:" + code + " " + body); } } } } |
7.6.7 查询分账结果
查询分账结果接口文档:https://pay.weixin.qq.com/doc/v3/partner/4012477734

▲ 查询分账结果对应流程图中『查询』环节(来源:4012062375)
|
import org.apache.http.client.methods.HttpGet;
public class QueryProfitSharing { /** * 查询分账结果 * 接口:GET /v3/profitsharing/orders/{out_order_no}?sub_mchid=xxx * 文档:https://pay.weixin.qq.com/doc/v3/partner/4012467002 */ public static String query(String subMchid, String outOrderNo) throws Exception { String url = "https://api.mch.weixin.qq.com/v3/profitsharing/orders/" + outOrderNo + "?sub_mchid=" + subMchid;
HttpGet httpGet = new HttpGet(url); httpGet.addHeader("Accept", "application/json");
try (CloseableHttpResponse response = WxPayClient.getClient().execute(httpGet)) { int code = response.getStatusLine().getStatusCode(); String body = EntityUtils.toString(response.getEntity()); if (code == 200) { // 解析 receivers[i].result 字段: // SUCCESS = 分账成功 // CLOSED = 已关闭(看 receivers[i].fail_reason) // PENDING = 处理中 System.out.println("查询分账结果:" + body); return body; } else { throw new RuntimeException("查询失败:" + code + " " + body); } } } } |
7.6.8 完结分账(解冻剩余资金)
完结分账接口文档:https://pay.weixin.qq.com/doc/v3/partner/4012477745

▲ 完结分账:剩余资金自动解冻给分账方(来源:4015870957)
|
public class FinishProfitSharing { /** * 完结分账 * 接口:POST /v3/profitsharing/orders/{out_order_no}/finish * 文档:https://pay.weixin.qq.com/doc/v3/partner/4012467016 * 用途:把剩余未分资金一次性解冻给分账方(子商户) */ public static String finish(String subMchid, String transactionId, String outOrderNo) throws Exception { String url = "https://api.mch.weixin.qq.com/v3/profitsharing/orders/" + outOrderNo + "/finish";
String reqdata = "{" + "\"sub_mchid\":\"" + subMchid + "\"," + "\"transaction_id\":\"" + transactionId + "\"," // 微信支付订单号 + "\"out_order_no\":\"" + outOrderNo + "\"," // 完结用的分账单号,不能与请求分账时相同 + "\"sub_appid\":\"wx8888888888888889\"" // 子商户 AppID(如有) + "}";
HttpPost httpPost = new HttpPost(url); httpPost.addHeader("Accept", "application/json"); httpPost.addHeader("Content-Type", "application/json"); httpPost.addHeader("Wechatpay-Serial", "PUB_KEY_ID_xxx"); httpPost.setEntity(new StringEntity(reqdata, "utf-8"));
try (CloseableHttpResponse response = WxPayClient.getClient().execute(httpPost)) { int code = response.getStatusLine().getStatusCode(); String body = EntityUtils.toString(response.getEntity()); if (code == 200 || code == 202) { System.out.println("完结分账受理成功:" + body); return body; } else { throw new RuntimeException("完结失败:" + code + " " + body); } } } } |
7.4.6 下单时传分账标识(关键步骤)
下单时必须在 settle_info 里传 profit_sharing=true,否则后续无法分账。示例(JSAPI 统一下单):
|
// 统一下单接口:POST /v3/pay/transactions/jsapi // 关键字段:settle_info.profit_sharing = true String reqdata = "{" + "\"sub_mchid\":\"1900000109\"," // 子商户号 + "\"appid\":\"wx8888888888888888\"," // 服务商 AppID + "\"sub_appid\":\"wx8888888888888889\"," // 子商户 AppID(如有) + "\"out_trade_no\":\"ORDER20260914001\"," + "\"description\":\"测试商品\"," + "\"amount\":{\"total\":1000,\"currency\":\"CNY\"}," // 1000 分 = 10 元 + "\"payer\":{\"openid\":\"oUpF8xxxxxx\"}," // 用户 openid(子商户 AppID 下的) + "\"settle_info\":{\"profit_sharing\":true}" // ★ 关键:分账标识 + "}"; |
|
❌ 重要:profit_sharing=true 必须在下单时传,已支付订单不能补传。如果忘了,该订单无法分账。 |
7.5 常见错误码速查
来源:https://pay.weixin.qq.com/doc/v3/merchant/4020807103
|
错误码 |
含义 |
排查步骤 |
|
271643173 |
超过分账限制的最大比例 |
子商户在商户平台 → 产品中心 → 授权的产品 → 分账授权 中提高比例,或减少本次分账金额。 |
|
271645722 |
无分账权限 |
1) 检查服务商是否开通分账;2) 检查子商户是否已授权;3) 检查请求参数是否用了普通商户文档(应该用服务商文档)。 |
|
271643175 |
不是分账订单 |
下单时未传 settle_info.profit_sharing=true,或 transaction_id 写错。 |
|
271643176 |
剩余可分金额为 0 |
1) 已全额退款;2) 已被解冻;3) 已分完。调用『查询订单剩余待分金额』接口确认。 |
|
271644678 |
分账关系非法 |
未先调用『添加分账接收方』建立关系,或商户接收方未『同意分账』。 |
|
271644831 |
订单未结算,交易投诉冻结 |
登录商户平台 → 交易中心/消费者投诉 2.0,处理投诉后等资金解冻。 |
|
268588428 |
分账单已完结 |
已经调过完结分账(unfreeze_unsplit=true),不能再次分账。 |
|
268588427 |
分账单已逾期解冻 |
超过 180 天冻结期,剩余资金已自动解冻给分账方,无法再分。 |
|
271644182 |
回退方没有开通分账回退功能 |
接收方商户登录商户平台 → 交易中心 → 分账 → 分账接收设置 → 开启『同意分账回退』。 |
|
271644737 |
微信用户没有实名 |
接收方是个人零钱时,用户未实名认证。请用户在微信 → 我 → 服务 → 右上角三点 → 实名认证。 |
7.6 完整工程实践(Spring Boot 项目结构)
本节给出一个可直接放进 Spring Boot 项目的完整分账对接方案,包含:
● Maven 依赖(pom.xml 片段)
● application.yml 配置参数
● WxPayConfig 配置类(自动初始化 HttpClient)
● WxPayUtil 工具类(V3 请求 + 签名 + 验签)
● ProfitSharingService 完整业务 Service(含所有分账接口)
● ProfitSharingController 回调接收 Controller(验签 + 解密 + 业务处理)
● SensitiveDataUtil 敏感字段加密(name 字段必须用微信支付公钥加密)
● 定时任务 QueryScheduler(异步查询分账最终结果)

▲ 完整工程实践对应业务时序图(来源:微信支付官方文档 4012062375)
7.6.1 Maven 依赖(pom.xml)
|
<!-- ============ 微信支付 APIv3 官方 SDK ============ --> <dependency> <groupId>com.github.wechatpay-apiv3</groupId> <artifactId>wechatpay-java</artifactId> <version>0.2.14</version> </dependency>
<!-- 兼容老版本 Apache HttpClient 风格(如果用 wechatpay-java 就不需要下面这个) --> <dependency> <groupId>com.github.wechatpay-apiv3</groupId> <artifactId>wechatpay-apache-httpclient</artifactId> <version>0.4.18</version> </dependency>
<!-- JSON 处理 --> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.10.1</version> </dependency>
<!-- Spring Boot Web(接收回调) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
<!-- Lombok(可选) --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> |
7.6.2 application.yml 配置
|
# ============ 微信支付服务商参数 ============ wxpay: # 服务商商户号 mch-id: "1900000108" # 服务商 AppID appid: "wx8888888888888888" # 商户 API 证书序列号(40 位十六进制) mch-serial: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # APIv3 密钥(32 位字符串,自己设置的) api-v3-key: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # 商户私钥文件路径(apiclient_key.pem) key-path: "C:/cert/apiclient_key.pem" # 微信支付公钥 ID(2025 年后新商户号用公钥模式) wechatpay-serial: "PUB_KEY_ID_xxxxxxxx" # 回调地址(必须 https,公网可访问) notify-url: "https://your-domain.com/api/wxpay/profit-sharing/notify"
# 子商户默认值(可被订单覆盖) sub: default-sub-mchid: "1900000109" default-sub-appid: "wx8888888888888889" |
|
ℹ️ 提示:代码使用 wechatpay-java 官方 SDK(推荐方式),底层自动处理签名、证书、平台证书自动更新。比手写 HttpClient 更安全、更省心。 |
7.6.3 WxPayConfig 配置类(自动初始化 SDK)
|
package com.example.wxpay.config;
import com.wechat.pay.java.core.Config; import com.wechat.pay.java.core.RSAAutoUpdateConfig; import com.wechat.pay.java.service.profitsharing.ProfitSharingService; import com.wechat.pay.java.service.profitsharing.ProfitSharingService.Builder; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
@Slf4j @Configuration public class WxPayConfig {
@Value("${wxpay.mch-id}") private String mchId; @Value("${wxpay.appid}") private String appid; @Value("${wxpay.mch-serial}") private String mchSerial; @Value("${wxpay.api-v3-key}") private String apiV3Key; @Value("${wxpay.key-path}") private String keyPath; @Value("${wxpay.wechatpay-serial}") private String wechatpaySerial;
/** * 自动更新微信支付平台证书的 Config * SDK 内部会定时下载并缓存平台证书,无需手动管理 */ @Bean public Config wxPayConfig() { log.info("初始化微信支付 Config,商户号={}, 证书序列号={}", mchId, mchSerial); return new RSAAutoUpdateConfig.Builder() .merchantId(mchId) .privateKeyFromPath(keyPath) .merchantSerialNumber(mchSerial) .apiV3Key(apiV3Key) .build(); }
/** * 分账 Service(官方 SDK 封装) */ @Bean public ProfitSharingService profitSharingService(Config wxPayConfig) { return new ProfitSharingService.Builder().config(wxPayConfig).build(); }
public String getMchId() { return mchId; } public String getAppid() { return appid; } public String getWechatpaySerial() { return wechatpaySerial; } } |
7.6.4 下单接口(必须传 profit_sharing=true)

▲ 下单传分账标识对应流程图中的『下单』环节(来源:4012062375)
下单使用服务商模式 JSAPI 统一下单:POST /v3/pay/partner/transactions/jsapi
|
❌ 重要:下单时必须传 settle_info.profit_sharing=true,否则后续无法分账。已支付订单不能补传。 |
|
package com.example.wxpay.service;
import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.wechat.pay.java.core.Config; import com.wechat.pay.java.service.payments.jsapi.JsapiService; import com.wechat.pay.java.service.payments.jsapi.model.*; import com.wechat.pay.java.service.payments.model.Payer; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service;
@Slf4j @Service public class PartnerPayService {
@Autowired private Config wxPayConfig; @Value("${wxpay.mch-id}") private String mchId; @Value("${wxpay.appid}") private String appid;
/** * 服务商模式 JSAPI 下单(带分账标识) * 接口:POST /v3/pay/partner/transactions/jsapi * 文档:https://pay.weixin.qq.com/doc/v3/partner/4012741851 */ public PrepayWithRequestJsapiResponse createOrderWithProfitSharing( String subMchid, String subAppid, String openid, String outTradeNo, String description, int totalAmount) {
JsapiService jsapiService = new JsapiService.Builder().config(wxPayConfig).build();
PrepayWithRequestJsapiRequest request = new PrepayWithRequestJsapiRequest(); request.setSubMchid(subMchid); request.setSubAppid(subAppid); request.setAppid(appid); request.setMchid(mchId); request.setDescription(description); request.setOutTradeNo(outTradeNo);
Amount amount = new Amount(); amount.setTotal(totalAmount); // 单位:分,1000=10 元 amount.setCurrency("CNY"); request.setAmount(amount);
Payer payer = new Payer(); payer.setSubOpenid(openid); // 子商户 AppID 下的 openid request.setPayer(payer);
// ★ 关键:分账标识,必须传 true SettleInfo settleInfo = new SettleInfo(); settleInfo.setProfitSharing(true); request.setSettleInfo(settleInfo);
log.info("下单参数:{}", new Gson().toJson(request)); return jsapiService.prepayWithRequestJsapi(request); } } |
7.6.5 添加分账接收方(含敏感字段加密)
添加接收方接口文档:https://pay.weixin.qq.com/doc/v3/partner/4012477758

▲ 添加接收方对应产品模型中『建立接收方列表』(来源:4015870957)
name 字段是个人姓名或商户全称,必须用微信支付公钥加密后传输。
|
package com.example.wxpay.service;
import com.wechat.pay.java.core.Config; import com.wechat.pay.java.service.profitsharing.ProfitSharingService; import com.wechat.pay.java.service.profitsharing.model.*; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service;
@Slf4j @Service public class ProfitSharingService {
@Autowired private ProfitSharingService profitSharingService; @Autowired private Config wxPayConfig; @Value("${wxpay.appid}") private String appid;
/** * 添加分账接收方 * 接口:POST /v3/profitsharing/receivers/add * 文档:https://pay.weixin.qq.com/doc/v3/partner/4012690944 */ public AddReceiverResponse addReceiver(String subMchid, String receiverType, String receiverAccount, String receiverName, String relationType) {
AddReceiverRequest request = new AddReceiverRequest(); request.setSubMchid(subMchid); request.setAppid(appid);
ReceiverDetail receiver = new ReceiverDetail(); receiver.setType(receiverType); // MERCHANT_ID / PERSONAL_OPENID / PERSONAL_SUB_OPENID receiver.setAccount(receiverAccount);
// ★ name 字段处理: // - MERCHANT_ID 类型必填商户全称(小微/个体户填开户人姓名) // - 个人类型选填(如填,必须用微信支付公钥加密,且校验实名一致) if (receiverName != null && !receiverName.isEmpty()) { // SDK 会自动用微信支付公钥加密敏感字段 receiver.setName(receiverName); } receiver.setRelationType(relationType); // PARTNER / DISTRIBUTOR / SUPPLIER / OTHERS 等
request.setReceivers(java.util.Collections.singletonList(receiver));
log.info("添加分账接收方:subMchid={}, account={}", subMchid, receiverAccount); return profitSharingService.addReceiver(request); }
/** * 删除分账接收方 * 接口:POST /v3/profitsharing/receivers/delete */ public DeleteReceiverResponse deleteReceiver(String subMchid, String receiverType, String receiverAccount) { DeleteReceiverRequest request = new DeleteReceiverRequest(); request.setSubMchid(subMchid); request.setAppid(appid);
ReceiverDetail receiver = new ReceiverDetail(); receiver.setType(receiverType); receiver.setAccount(receiverAccount); request.setReceivers(java.util.Collections.singletonList(receiver));
log.info("删除分账接收方:account={}", receiverAccount); return profitSharingService.deleteReceiver(request); } } |
7.6.6 请求分账(核心接口)
请求分账接口文档:https://pay.weixin.qq.com/doc/v3/partner/4012691594

▲ 分账产品模型图:请求分账是整个流程的核心(来源:4015870957)
|
/** * 请求分账 * 接口:POST /v3/profitsharing/orders * 文档:https://pay.weixin.qq.com/doc/v3/partner/4012692975 * * 关键规则: * 1. 分账金额单位是「分」,100=1 元 * 2. receivers.amount 总和 ≤ 订单金额 × 子商户设置的最大分账比例 * 3. 接口是异步受理,返回 order_id 不代表分账成功,需后续查询 * 4. 同一笔订单最多分账 50 次,每次最多 50 个接收方 * 5. unfreeze_unsplit=true 表示本次是最后一次分账并解冻剩余资金 */ public CreateOrderResponse createProfitSharing( String subMchid, String transactionId, String outOrderNo, List<Receiver> receivers, boolean unfreezeUnsplit) {
CreateOrderRequest request = new CreateOrderRequest(); request.setSubMchid(subMchid); request.setAppid(appid); request.setTransactionId(transactionId); // 微信支付订单号 request.setOutOrderNo(outOrderNo); // 商户分账单号,商户系统内唯一,6-64 位 request.setReceivers(receivers); request.setUnfreezeUnsplit(unfreezeUnsplit); // true=本次分账同时完结,false=不解冻
log.info("请求分账:outOrderNo={}, receivers={}", outOrderNo, receivers.size()); return profitSharingService.createOrder(request); }
/** * 构造分账接收方列表(示例:分给商户) */ public List<Receiver> buildReceivers(String receiverAccount, int amountFen, String desc) { Receiver r = new Receiver(); r.setType("MERCHANT_ID"); r.setAccount(receiverAccount); // 接收方商户号 r.setAmount(amountFen); // 分账金额,单位:分 r.setDescription(desc); // 分账描述,最多 80 字 r.setName("某某合作公司"); // 商户类型必填全称 return java.util.Collections.singletonList(r); }
/** * 构造分账给个人零钱的接收方 */ public List<Receiver> buildPersonalReceivers(String openid, int amountFen, String desc, String userName) { Receiver r = new Receiver(); r.setType("PERSONAL_OPENID"); // 或 PERSONAL_SUB_OPENID r.setAccount(openid); // 用户 openid r.setAmount(amountFen); r.setDescription(desc); // 个人类型 name 选填,填了会校验实名一致性 if (userName != null) r.setName(userName); return java.util.Collections.singletonList(r); } |
7.6.7 查询分账结果
|
/** * 查询分账结果 * 接口:GET /v3/profitsharing/orders/{out_order_no}?sub_mchid=xxx * 文档:https://pay.weixin.qq.com/doc/v3/partner/4012467002 * * receivers[i].result 取值: * SUCCESS = 分账成功 * CLOSED = 已关闭(看 receivers[i].fail_reason) * PENDING = 处理中 */ public QueryOrderResponse queryProfitSharing(String subMchid, String outOrderNo) { QueryOrderRequest request = new QueryOrderRequest(); request.setSubMchid(subMchid); request.setOutOrderNo(outOrderNo);
QueryOrderResponse response = profitSharingService.queryOrder(request); log.info("查询分账结果:outOrderNo={}, state={}", outOrderNo, response.getState());
// 遍历每个接收方的分账结果 if (response.getReceivers() != null) { for (ReceiverResult r : response.getReceivers()) { log.info("接收方 {} 分账结果:{},失败原因:{}", r.getAccount(), r.getResult(), r.getFailReason()); } } return response; }
/** * 查询订单剩余待分金额 * 接口:GET /v3/profitsharing/transactions/{transaction_id}/amounts?sub_mchid=xxx */ public QueryOrderAmountsResponse queryUnsplitAmount(String subMchid, String transactionId) { QueryOrderAmountsRequest request = new QueryOrderAmountsRequest(); request.setSubMchid(subMchid); request.setTransactionId(transactionId); return profitSharingService.queryOrderAmounts(request); } |
7.6.8 完结分账(解冻剩余资金)
|
/** * 完结分账 * 接口:POST /v3/profitsharing/orders/{out_order_no}/finish * 文档:https://pay.weixin.qq.com/doc/v3/partner/4012467016 * * 用途:把剩余未分资金一次性解冻给分账方(子商户) * 注意:out_order_no 必须与请求分账时的 out_order_no 不同! */ public FinishOrderResponse finishProfitSharing(String subMchid, String transactionId, String outOrderNo, String subAppid) { FinishOrderRequest request = new FinishOrderRequest(); request.setSubMchid(subMchid); request.setTransactionId(transactionId); request.setOutOrderNo(outOrderNo); // 完结用的单号,必须不同于请求分账的单号 if (subAppid != null) request.setSubAppid(subAppid);
log.info("完结分账:transactionId={}, outOrderNo={}", transactionId, outOrderNo); return profitSharingService.finishOrder(request); } |
7.6.9 请求分账回退(已分资金回退)
分账回退接口文档:https://pay.weixin.qq.com/doc/v3/partner/4012477747

▲ 分账回退:已分资金回退给分账方(来源:4015870957)
退款流程:先调用本接口把已分资金回退给分账方 → 再调用普通退款接口退款。
|
/** * 请求分账回退 * 接口:POST /v3/profitsharing/returns * 文档:https://pay.weixin.qq.com/doc/v3/partner/4012467097 * * 前置条件:接收方商户登录商户平台 → 交易中心 → 分账 → 分账接收设置 → 开启『同意分账回退』 * 否则报错 271644182 */ public ReturnResponse createReturn(String subMchid, String orderId, String outReturnNo, String outOrderNo, String receiverAccount, String receiverType, int returnAmount, String description) { CreateReturnRequest request = new CreateReturnRequest(); request.setSubMchid(subMchid); request.setOrderId(orderId); // 微信分账单号(请求分账返回的 order_id) request.setOutReturnNo(outReturnNo); // 商户回退单号,商户系统内唯一 request.setOutOrderNo(outOrderNo); // 原分账单号 request.setReturnAccountType(receiverType); // MERCHANT_ID request.setReturnAccount(receiverAccount); request.setReturnAmount(returnAmount); request.setDescription(description);
log.info("请求分账回退:outReturnNo={}, amount={}", outReturnNo, returnAmount); return profitSharingService.createReturn(request); }
/** * 查询分账回退结果 * 接口:GET /v3/profitsharing/returns/{out_return_no} * ?sub_mchid=xxx&out_order_no=xxx */ public QueryReturnResponse queryReturn(String subMchid, String outReturnNo, String outOrderNo) { QueryReturnRequest request = new QueryReturnRequest(); request.setSubMchid(subMchid); request.setOutReturnNo(outReturnNo); request.setOutOrderNo(outOrderNo); return profitSharingService.queryReturn(request); } |
7.6.10 回调 Controller(核心:验签 + 解密 + 业务处理)
分账动账通知官方文档:https://pay.weixin.qq.com/doc/v3/partner/4012467002

▲ 回调通知在流程图中的位置:分账成功后异步通知商户(来源:4012062375)
微信支付在分账/回退成功后会主动 POST 通知商户,需要:
● 1) 验签(确认请求来自微信支付,防伪造)
● 2) 解密 resource.ciphertext(AES-256-GCM 解密,密钥是 APIv3 密钥)
● 3) 业务处理(更新订单状态)
● 4) 返回 200 + {code: SUCCESS},否则微信会重试
|
package com.example.wxpay.controller;
import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.wechat.pay.java.core.notification.NotificationParser; import com.wechat.pay.java.service.profitsharing.model.*; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*;
@Slf4j @RestController @RequestMapping("/api/wxpay/profit-sharing") public class ProfitSharingController {
@Autowired private NotificationParser notificationParser; @Autowired private OrderService orderService;
/** * 分账动账通知回调 * 路径需与下单时 notify_url 一致(https://your-domain.com/api/wxpay/profit-sharing/notify) * 文档:https://pay.weixin.qq.com/doc/v3/partner/4012075400 * * SDK 自动完成: * - 验签(用微信支付平台证书) * - 解密(AES-256-GCM,密钥=APIv3 密钥) * - 反序列化为 ProfitSharingNotifySource 对象 */ @PostMapping("/notify") public String profitSharingNotify(@RequestBody String body, @RequestHeader("Wechatpay-Timestamp") String timestamp, @RequestHeader("Wechatpay-Nonce") String nonce, @RequestHeader("Wechatpay-Signature") String signature, @RequestHeader("Wechatpay-Serial") String serial) { log.info("收到分账回调:serial={}", serial);
try { // 构造 RequestParam com.wechat.pay.java.core.notification.RequestParam requestParam = new com.wechat.pay.java.core.notification.RequestParam.Builder() .serialNumber(serial) .nonce(nonce) .timestamp(timestamp) .signature(signature) .body(body) .build();
// SDK 自动验签 + 解密,得到通知内容 ProfitSharingNotifySource notify = notificationParser.parse(requestParam, ProfitSharingNotifySource.class);
log.info("分账回调解析成功:outOrderNo={}, state={}", notify.getOutOrderNo(), notify.getState());
// ===== 业务处理 ===== // notify.getState():FINISHED / PROCESSING // notify.getReceivers():每个接收方的最终结果 for (ReceiverResult r : notify.getReceivers()) { if ("SUCCESS".equals(r.getResult())) { // 分账成功:更新订单状态、给接收方加余额、触发下游业务 orderService.markReceiverSuccess( notify.getOutOrderNo(), r.getAccount(), r.getAmount()); } else if ("CLOSED".equals(r.getResult())) { // 分账失败:记录失败原因、通知运营处理 log.error("分账失败:account={}, reason={}", r.getAccount(), r.getFailReason()); orderService.markReceiverFailed( notify.getOutOrderNo(), r.getAccount(), r.getFailReason()); } }
// 必须返回 SUCCESS,否则微信会重试 8 次 return "{\"code\": \"SUCCESS\", \"message\": \"成功\"}";
} catch (Exception e) { log.error("分账回调处理失败", e); // 返回失败,微信会重试 return "{\"code\": \"FAIL\", \"message\": \"" + e.getMessage() + "\"}"; } } } |
|
⚠️ 注意:回调必须返回 200 + {"code":"SUCCESS"}。否则微信会按 15s/15s/30s/3m/10m/20m/30m/30m/30m/60m 节奏重试 8 次。 |
7.6.11 NotificationParser Bean 配置
在 WxPayConfig 里追加:
|
@Bean public NotificationParser notificationParser(Config wxPayConfig) { // SDK 自动用 APIv3 密钥解密 + 用平台证书验签 return new NotificationParser(wxPayConfig); } |
7.6.12 定时任务:异步查询分账结果(兜底)
回调可能丢失,所以定时任务定期主动查询未完成的分账单:
|
package com.example.wxpay.scheduler;
import com.example.wxpay.service.ProfitSharingService; import com.example.wxpay.entity.ProfitSharingOrder; import com.example.wxpay.repository.ProfitSharingOrderRepository; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component;
import java.time.LocalDateTime; import java.util.List;
@Slf4j @Component public class ProfitSharingQueryScheduler {
@Autowired private ProfitSharingService profitSharingService; @Autowired private ProfitSharingOrderRepository orderRepository;
/** * 每 5 分钟查询一次状态为 PENDING 的分账单 * 兜底回调丢失的情况 */ @Scheduled(fixedRate = 5 * 60 * 1000) public void queryPendingProfitSharing() { LocalDateTime deadline = LocalDateTime.now().minusMinutes(10); // 只查 10 分钟前发起的 List<ProfitSharingOrder> pendingOrders = orderRepository.findByStateAndUpdateTimeBefore("PENDING", deadline);
log.info("定时查询分账结果,待查单数:{}", pendingOrders.size());
for (ProfitSharingOrder order : pendingOrders) { try { QueryOrderResponse response = profitSharingService.queryProfitSharing( order.getSubMchid(), order.getOutOrderNo());
// 更新订单状态 order.setState(response.getState()); if (response.getReceivers() != null) { for (ReceiverResult r : response.getReceivers()) { order.setReceiverResult(r.getAccount(), r.getResult(), r.getFailReason()); } } orderRepository.save(order);
log.info("定时查询完成:outOrderNo={}, state={}", order.getOutOrderNo(), response.getState());
} catch (Exception e) { log.error("查询分账结果失败:outOrderNo={}", order.getOutOrderNo(), e); } } } } |
7.6.13 完整业务调用示例

▲ 完整业务调用对应的全流程时序图(来源:4012062375)
一个完整的分账流程调用示例(用户支付成功后自动分账):
|
package com.example.wxpay.service;
import com.example.wxpay.entity.Order; import com.example.wxpay.repository.OrderRepository; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;
@Slf4j @Service public class ProfitSharingFacadeService {
@Autowired private ProfitSharingService profitSharingService; @Autowired private OrderRepository orderRepository;
/** * 完整分账流程(订单支付成功后调用) */ public void doProfitSharing(String outTradeNo) { // 1. 查订单信息 Order order = orderRepository.findByOutTradeNo(outTradeNo); if (order == null) throw new RuntimeException("订单不存在");
// 2. 查询订单剩余可分金额(重要!避免超额分账报错) QueryOrderAmountsResponse amounts = profitSharingService.queryUnsplitAmount( order.getSubMchid(), order.getTransactionId()); int unsplitAmount = amounts.getUnsplitAmount();
if (unsplitAmount <= 0) { log.warn("订单无可分金额:{}", outTradeNo); return; }
// 3. 计算本次分账金额 // 例:订单总额 100 元,服务商抽 10% = 10 元 = 1000 分 int profitAmount = order.getTotalAmount() / 10; // 服务商分 10% // 检查不超过剩余可分金额 if (profitAmount > unsplitAmount) { profitAmount = unsplitAmount; }
// 4. 构造分账接收方(分给服务商自己的商户号) List<Receiver> receivers = profitSharingService.buildReceivers( "1900000110", // 接收方商户号(服务商自己) profitAmount, // 分账金额(分) "订单" + outTradeNo + "分给服务商" // 描述 );
// 5. 请求分账 String outOrderNo = "PS" + System.currentTimeMillis(); CreateOrderResponse response = profitSharingService.createProfitSharing( order.getSubMchid(), order.getTransactionId(), outOrderNo, receivers, false // false=不解冻剩余,让子商户拿到大头;true=本次即完结 );
log.info("分账受理成功:orderId={}, outOrderNo={}", response.getOrderId(), outOrderNo);
// 6. 保存分账单到数据库(等回调或定时任务更新结果) orderRepository.saveProfitSharingOrder( outOrderNo, order.getTransactionId(), order.getSubMchid(), profitAmount, "PENDING");
// 注:剩余资金(订单金额-分账金额)默认自动解冻给子商户 // 如需主动解冻可调用 finishProfitSharing,但只有『最后一笔分账』才需要传 unfreeze_unsplit=true }
/** * 退款流程:先回退分账,再退款 */ public void refundWithProfitSharing(String outTradeNo, int refundAmount) { Order order = orderRepository.findByOutTradeNo(outTradeNo);
// 1. 先调用分账回退接口,把已分给服务商的资金回退给子商户 String outReturnNo = "RT" + System.currentTimeMillis(); profitSharingService.createReturn( order.getSubMchid(), order.getProfitSharingOrderId(), // 微信分账单号 outReturnNo, order.getOutOrderNo(), // 原分账单号 "1900000110", // 回退给谁(原分账接收方) "MERCHANT_ID", refundAmount, "退款回退分账资金" );
// 2. 等回退成功(可监听回调或定时查询)后,再调用普通退款接口 // ... 此处省略退款接口调用 } } |
7.6.14 敏感字段手动加密(如不用 SDK)
如果直接用 HttpClient 不用官方 SDK,name 字段必须手动用微信支付公钥 RSA-OAEP 加密:
|
import javax.crypto.Cipher; import javax.crypto.spec.OAEPParameterSpec; import javax.crypto.spec.PSource; import java.security.KeyFactory; import java.security.PublicKey; import java.security.spec.X509EncodedKeySpec; import java.util.Base64;
public class SensitiveDataUtil {
/** * 用微信支付公钥加密敏感字段 * 算法:RSA/ECB/OAEPWithSHA-1AndMGF1Padding */ public static String encrypt(String plaintext, String publicKeyBase64) throws Exception { byte[] keyBytes = Base64.getDecoder().decode(publicKeyBase64); X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes); KeyFactory kf = KeyFactory.getInstance("RSA"); PublicKey pubKey = kf.generatePublic(spec);
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding"); OAEPParameterSpec oaepParams = new OAEPParameterSpec( "SHA-1", "MGF1", java.security.spec.MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT ); cipher.init(Cipher.ENCRYPT_MODE, pubKey, oaepParams); byte[] encrypted = cipher.doFinal(plaintext.getBytes("UTF-8")); return Base64.getEncoder().encodeToString(encrypted); } }
// 调用示例: String encryptedName = SensitiveDataUtil.encrypt("某某公司", wxPayPublicKeyBase64); // 然后传给接口的 receivers[i].name 字段 |
7.6.15 项目目录结构建议

▲ 项目结构对应分账产品模型(来源:4015870957)
|
src/main/java/com/example/wxpay/ ├── config/ │ └── WxPayConfig.java # SDK 配置 + Bean 注入 ├── controller/ │ ├── PartnerPayController.java # 下单 + 支付回调 │ └── ProfitSharingController.java # 分账回调(验签+解密+业务) ├── service/ │ ├── PartnerPayService.java # 下单(含 profit_sharing=true) │ ├── ProfitSharingService.java # 分账接口封装 │ │ ├── addReceiver() │ │ ├── deleteReceiver() │ │ ├── createProfitSharing() │ │ ├── queryProfitSharing() │ │ ├── finishProfitSharing() │ │ ├── createReturn() # 分账回退 │ │ └── queryReturn() │ ├── ProfitSharingFacadeService.java # 业务编排(完整流程) │ └── OrderService.java # 订单状态管理 ├── scheduler/ │ └── ProfitSharingQueryScheduler.java # 定时查询兜底 ├── entity/ │ ├── Order.java │ └── ProfitSharingOrder.java ├── repository/ │ ├── OrderRepository.java │ └── ProfitSharingOrderRepository.java └── util/ └── SensitiveDataUtil.java # 敏感字段加密
src/main/resources/ ├── application.yml # 微信支付参数 └── cert/ └── apiclient_key.pem # 商户私钥文件(保密) |
7.6.16 测试用例(小额跑通)

▲ 测试用例覆盖的完整流程(来源:4012062375)
上线前用 1 元跑通一笔分账:
|
// 1. 下单(带分账标识) PrepayWithRequestJsapiResponse resp = partnerPayService.createOrderWithProfitSharing( "1900000109", // 子商户号 "wx8888888888888889", // 子商户 AppID "oUpF8xxxxxx", // 用户 openid "TEST" + System.currentTimeMillis(), // 商户订单号 "测试商品", 100 // 100 分 = 1 元 ); String transactionId = ... // 等支付成功回调获取
// 2. 查询可分金额 QueryOrderAmountsResponse amounts = profitSharingService.queryUnsplitAmount("1900000109", transactionId); // 应返回 unsplitAmount ≈ 100(扣手续费后约 99)
// 3. 添加接收方(一次性,已添加可跳过) profitSharingService.addReceiver( "1900000109", "MERCHANT_ID", "1900000110", // 接收方商户号(服务商自己) "某某公司", "PARTNER" );
// 4. 请求分账(分 10 分 = 0.1 元 给服务商) List<Receiver> receivers = profitSharingService.buildReceivers( "1900000110", 10, "测试分账" ); CreateOrderResponse resp = profitSharingService.createProfitSharing( "1900000109", transactionId, "PS" + System.currentTimeMillis(), receivers, false ); // 返回 orderId,state=ACCEPTED(已受理)
// 5. 查询分账结果(约 1 分钟后变 SUCCESS) Thread.sleep(60 * 1000); QueryOrderResponse query = profitSharingService.queryProfitSharing( "1900000109", outOrderNo ); // query.getReceivers()[0].getResult() = "SUCCESS"
// 6. 完结分账(剩余 89 分解冻给子商户) profitSharingService.finishProfitSharing( "1900000109", transactionId, "FIN" + System.currentTimeMillis(), "wx8888888888888889" ); |
|
ℹ️ 提示:测试建议金额 1 元(100 分),避免大额分账出错。先跑通单接口,再跑通完整流程。最后接入回调处理。 |
第八部分 验收清单与官方资源
8.1 上线前检查清单(非技术人员对照打勾)
请逐项打勾,全部完成才可上线:

▲ 完整流程回顾图(来源:微信支付官方文档 4012062375)
|
已做 |
检查项 |
|
□ |
已注册企业服务号且通过微信认证 |
|
□ |
已申请成为微信支付服务商,获得服务商商户号 |
|
□ |
服务商平台 → 产品中心 → 特约商户授权产品 → 服务商分账 已开通 |
|
□ |
已发起分账授权邀请给每个子商户 |
|
□ |
每个子商户已在商户平台 → 产品中心 → 我授权的产品 中确认授权 |
|
□ |
所有子商户已完成进件(含打款验证) |
|
□ |
子商户已关联小程序/公众号 AppID(如使用) |
|
□ |
已通过接口或商户平台添加了分账接收方 |
|
□ |
子商户已在商户平台 → 产品中心 → 授权的产品 → 分账授权 设置最大分账比例 |
|
□ |
服务商平台 → 账户中心 → API 安全 已下载 API 证书、设置 APIv3 密钥 |
|
□ |
已记录服务商商户号、AppID、证书序列号、子商户号等开发参数 |
|
□ |
代码已实现:下单传 profit_sharing=true |
|
□ |
代码已实现:请求分账、查询分账结果、完结分账 |
|
□ |
已用小额(如 1 元)跑通一笔分账测试 |
|
□ |
分账动账通知回调地址(notify_url)已配置并能正确接收 |
8.2 关键客服与咨询渠道

▲ 全流程回顾:从服务商申请到分账完成(来源:4012062375)
|
渠道 |
联系方式 / 网址 |
用途 |
|
微信支付客服 |
95017 |
提高分账比例申请、其他业务咨询 |
|
服务商 BD 邮箱 |
weixinpayBD@tencent.com |
大客户合作 |
|
官方文档总站 |
https://pay.weixin.qq.com/ |
所有产品文档入口 |
|
服务商平台 |
https://pay.weixin.qq.com/index.php/partner/public/home |
服务商登录与操作 |
|
商户平台 |
https://pay.weixin.qq.com/ |
子商户登录与操作 |
|
公众平台 |
https://mp.weixin.qq.com/ |
服务号、小程序后台 |
附录 A 全部官方文档链接
本文档所有截图、步骤、参数均来自以下官方文档页面:
● 开发接入准备:https://pay.weixin.qq.com/doc/v3/partner/4012072589
● 对接步骤(V2):https://pay.weixin.qq.com/doc/v2/partner/4011984375
● 开发指引(连锁品牌):https://pay.weixin.qq.com/doc/v3/partner/4012072637
● 添加分账接收方接口:https://pay.weixin.qq.com/doc/v3/partner/4012690944
● 请求分账接口:https://pay.weixin.qq.com/doc/v3/partner/4012692975
● 查询分账结果接口:https://pay.weixin.qq.com/doc/v3/partner/4012467002
● 完结分账接口:https://pay.weixin.qq.com/doc/v3/partner/4012467016
● 查询订单剩余待分金额:https://pay.weixin.qq.com/doc/v3/partner/4012457927
● 分账动账通知:https://pay.weixin.qq.com/doc/v3/partner/4012075400
● 分账失败处理指引:https://pay.weixin.qq.com/doc/v3/partner/4015504918
● 分账常见问题:https://pay.weixin.qq.com/doc/v3/partner/4014547107
● 分账错误码:https://pay.weixin.qq.com/doc/v3/merchant/4020807103
● 业务示例代码:https://pay.weixin.qq.com/doc/v3/partner/4015870957
● 商家注册小程序指引:https://pay.weixin.qq.com/static/help_guide/business_registration.shtml
● 微信支付服务商接入指引 PDF:https://gtimg.wechatpay.cn/resource/xres/mmpaydoc/static/attachment/d7ed63166bac0051d3b2c13ea0fc36dc/服务商接入指引-大交通中心(2020新版).pdf
● 服务商申请入口:https://pay.weixin.qq.com/index.php/partner/public/home
● 公众平台:https://mp.weixin.qq.com/
● 微信支付商户平台:https://pay.weixin.qq.com/
24. 按要求填写营业执照信息、法人/经营者身份证等信息。
25. 管理员信息:姓名、身份证号、手机号(管理员需绑定本人实名微信)。
26. 等待审核,一般 1-5 个工作日。
27. 审核结果会通过邮件和管理员微信通知。

▲ 操作路径:填营业执照 → 填法人信息 → 填管理员信息 → 提交等待
2.2 完成微信认证
【为什么必须认证?】服务号只有通过微信认证后,才能申请微信支付服务商资格。未认证的服务号只能做基础信息展示,不能开通任何支付功能。
如果注册时没有立即做认证,需要单独发起:
访问入口:https://mp.weixin.qq.com/
步骤 1:发起认证
28. 使用服务号账号登录 mp.weixin.qq.com。
29. 左侧菜单:『设置』 → 『微信认证』 → 点击『开通』。
30. 按页面指引填写认证资料,缴纳 300 元/次审核费。
31. 【费用说明】300 元是第三方审核公司收的审核服务费,不退(无论是否通过)。腾讯不收此费。
32. 等待第三方审核公司来电回访,一般 3-5 个工作日出结果。
33. 审核公司会电话核对填写的资料是否真实,请保持手机畅通。

▲ 操作路径:登录 → 设置 → 微信认证 → 开通 → 缴费
|
ℹ️ 提示:认证通过后,服务号才具备申请微信支付服务商的资格。请务必完成。 |

▲ 认证完成后签署各类协议(示意)
2.3 申请成为微信支付服务商
服务号认证通过后,即可发起服务商申请:
访问入口:https://mp.weixin.qq.com/
步骤 1:进入服务商申请页
34. 登录 mp.weixin.qq.com。
35. 左侧菜单:『微信支付』 → 『服务商申请』。
36. (如果没有此菜单,说明服务号还没通过认证,请回到 2.2 完成。)
37. 【提示】部分新账号可能没有『微信支付』菜单,请先点击『添加功能插件』找到『微信支付』并开通。

▲ 操作路径:登录 → 微信支付菜单 → 服务商申请
步骤 2:填写服务商资料
38. 公司联系方式:联系人姓名、联系手机、联系邮箱(建议用企业邮箱)。
39. 客服电话:对外服务的客服座机或手机(消费者可拨打)。
40. 公司对公账户信息:开户行省市、开户账号。
41. 【重要】对公账户户名必须与服务商主体(营业执照上的公司名)完全一致,不能用个人账户。
42. 营业执照信息:营业执照号、有效期、高清扫描件(PDF/JPG/PNG,单张 ≤2M)。
43. 组织机构代码证:组织机构代码、有效期、高清扫描件(已三证合一的提供统一社会信用代码即可)。
44. 业务经办人或法人证件:身份证或护照正反面。
45. 【常见坑】身份证照片要清晰,4 个角都要露出来,不能有反光、阴影。

▲ 操作路径:填联系方式 → 填对公账户 → 上传营业执照 → 上传法人证件
步骤 3:提交并等待审核
46. 资料填写完成后点击『提交』。
47. 等待 1-5 个工作日审核。
48. 审核通过后会收到邮件和公众号通知,同时获得『服务商商户号』(10 位数字)。
49. 【服务商商户号】请妥善保存,后续代码开发会用到,登录服务商平台也用它。

▲ 操作路径:提交 → 等待审核 → 收到通知 → 获得商户号

▲ 服务商申请全流程图(来源:4012062375)
步骤 4:账户验证(打款验证)
50. 微信支付会向您填写的对公账户打一笔随机金额(0.01~1 元)的款项。
51. 财付通在 T+1 日原路退回。
52. 登录服务商平台 pay.weixin.qq.com/index.php/partner/public/home,在『待办事项』中回填收款金额。
53. 【操作位置】登录后页面顶部会显示红色提示『待办事项:1 项』,点击进入回填页面。
54. 数额正确即通过验证。
55. 【如果金额填错】有 3 次机会,3 次都错会被冻结,需要联系微信支付客服 95017 解冻。

▲ 操作路径:收到打款 → 登录平台 → 点击待办事项 → 回填金额 → 验证通过
步骤 5:在线签署协议
56. 验证通过后,在服务商平台点击『签署协议』。
57. 在线阅读并同意《微信支付服务商合作协议》。
58. 签约完成,正式成为微信支付服务商。
59. 【签约完成后】服务号会收到微信支付发来的『服务商入驻成功』通知,请保存好。

▲ 操作路径:点击签署协议 → 阅读协议 → 同意 → 成为服务商
|
✓ 建议:完成以上步骤后,您将拥有:1) 服务号 + 2) 服务商商户号 + 3) 服务商平台登录权限。这是后续所有操作的基础。 |
第三部分 第二步:开通服务商分账产品
成为服务商后,分账功能不是默认开通的,需要单独在服务商平台开通『服务商分账』产品。
【什么是分账?】消费者在您的平台下单支付 100 元后,资金先进入子商户的微信支付账户,但被『冻结』。您作为服务商可按约定比例,将其中一部分(如 10 元)自动分到您的商户号,剩余 90 元解冻给子商户。这就是分账。
【为什么要单独开通?】微信支付把分账作为独立产品,需要服务商和子商户分别开通并互相授权后才能用,目的是保护商户资金安全。
|
✓ 建议:好消息:现在分账产品已支持『后台直接开通,即时生效』,无需再像早年那样发邮件审核。但前提是您已是合规服务商且已绑定子商户。 |
3.1 开通前的5个前置条件(缺一不可)
【自检方法】对照下表逐条确认,全部满足才能继续下一步。任何一条不满足,开通按钮会是灰色或不可点。
|
序号 |
条件 |
如何确认已满足 |
|
1 |
服务商商户号已申请成功 |
在 pay.weixin.qq.com/index.php/partner/public/home 能正常登录 |
|
2 |
已绑定至少一个子商户 |
在『服务商功能 → 特约商户管理』能看到子商户列表 |
|
3 |
子商户已完成打款验证 |
子商户状态为『已验证』而非『待验证』 |
|
4 |
子商户已关联 AppID(如使用) |
在『AppID 账号管理』里能看到绑定记录 |
|
5 |
服务商已配置 APIv3 密钥与证书 |
用于后续接口调用,分账产品开通不强制,但代码阶段必须 |
3.2 服务商侧开通分账产品(官方5步流程)
微信支付官方文档(https://pay.weixin.qq.com/doc/v2/partner/4011984344)明确的5步流程:
|
步骤 |
动作 |
备注 |
|
1 |
服务商在产品中心-特约商户授权产品中开通服务商分账 |
点击后即时生效,无需审核 |
|
2 |
(产品已开通,此步为确认) |
状态显示『已开通』 |
|
3 |
服务商邀请特约商户授权:①邀请特约商户授权 ②填写功能使用场景及上传资料 |
需上传分账场景说明 |
|
4 |
特约商户授权:①收到通知后,在产品中心授权 ②签署协议 ③设置允许服务商分账的最大比例 |
默认30% |
|
5 |
添加分账接收方 |
通过 API 接口添加 |
访问入口:https://pay.weixin.qq.com/index.php/partner/public/home
|
⚠️ 注意:登录角色:请用『超级管理员』扫码登录。普通操作员看不到产品中心开通入口。 |
【如何确认谁是超级管理员?】登录服务商平台后,在右上角账号信息里能看到『超级管理员』标识。如果显示『操作员』,需要联系超级管理员扫码登录,或让超管给操作员开通权限。
3.2.1 详细操作截图指引
【操作路径】服务商平台首页 → 左侧菜单『产品中心』 → 『特约商户授权产品』 → 找到『服务商分账』 → 点击『开通』。
步骤 1:登录服务商平台
60. 浏览器打开 https://pay.weixin.qq.com/index.php/partner/public/home
61. 使用超级管理员微信扫码登录。
62. 【扫码没反应?】请确认微信已更新到最新版本,且该微信号是服务商平台的超级管理员或操作员。

▲ 操作路径:打开浏览器 → 输入 pay.weixin.qq.com/partner/public/home → 超级管理员扫码登录
步骤 2:进入产品中心
63. 登录后,在页面左侧菜单找到『产品中心』,点击展开。
64. 在产品中心下找到『特约商户授权产品』分类。
65. 继续找到『服务商分账』子项。
66. 完整路径:产品中心 → 特约商户授权产品 → 服务商分账(位于『资金解决方案』分组下)。
67. 【找不到?】如果产品中心下没有『特约商户授权产品』分类,请确认账号已通过服务商审核;如果是新账号,开通入口可能直接显示在产品中心首页。

▲ 操作路径:左侧菜单产品中心 → 找到特约商户授权产品 → 找到服务商分账

▲ 官方文档截图:服务商平台 → 产品中心 → 特约商户授权产品 → 服务商分账
开通入口官方说明:https://pay.weixin.qq.com/doc/v3/partner/4012072589
步骤 3:点击开通
68. 在『服务商分账』右侧点击蓝色『开通』按钮。
69. 弹出协议窗口,阅读《分账产品服务协议》。
70. 【建议】把协议从头到尾读一遍,重点关注『资金责任』『退款责任』『违约条款』。
71. 勾选『我已阅读并同意』。
72. 点击『确认开通』。
73. 开通成功后,状态会从『未开通』变为『已开通』,按钮变为『管理』。

▲ 操作路径:找到服务商分账 → 点击开通 → 阅读协议 → 勾选同意 → 确认开通
|
ℹ️ 提示:此步骤『即时生效』,不需要审核等待。开通后才能向子商户发起授权邀请。 |
3.2.2 子商户侧开通分账(同步动作)
子商户也需要在自己的商户平台开通分账产品(与服务商侧开通同步进行)。
【为什么要子商户也开通?】因为分账涉及子商户的资金,子商户必须主动开通并授权,否则服务商无权操作子商户的资金。
子商户访问入口:https://pay.weixin.qq.com/
步骤 1:子商户登录商户平台
74. 打开 https://pay.weixin.qq.com/,扫码登录。
75. 【登录角色】子商户的超级管理员微信扫码,操作员可能无权限开通产品。
76. 左侧菜单:『产品中心』。
77. 找到『分账』产品项。
78. 点击『开通』,按提示签署协议。
79. 完整路径:产品中心 → 分账 → 开通。
80. 【如果看不到『分账』】可能是子商户还没被服务商绑定,请先完成第四部分『添加子服务商』。

▲ 操作路径:子商户打开网址 → 超级管理员扫码登录 → 产品中心 → 找到分账 → 点击开通

▲ 子商户商户平台:产品中心 → 分账 → 开通
3.3 服务商邀请子商户授权绑定分账
服务商侧、子商户侧都开通分账产品后,还需要建立『授权关系』:服务商邀请 → 子商户同意。
【这一步是必须的!】即使服务商和子商户都开通了分账,没有授权关系,服务商调用接口时会报错『无分账权限』。
|
❌ 重要:这一步必须做!否则服务商无法代子商户调用分账接口,会报错『无分账权限』。 |
步骤 1:发起邀请
81. 在服务商分账开通成功页面(或『产品中心 → 服务商分账 → 管理』),点击『邀请子商户授权』按钮。
82. 在弹窗中勾选要邀请的子商户(即您旗下的特约商户),可多选。
83. 点击『下一步』。
84. 【找不到子商户?】子商户必须已完成打款验证,状态为『已验证』才能被邀请。请先在『特约商户管理』里确认状态。

▲ 操作路径:进入分账管理页 → 点击邀请子商户授权 → 勾选子商户 → 点击下一步
邀请授权官方说明:https://pay.weixin.qq.com/doc/v3/partner/4012072589
步骤 2:填写场景描述(重要,决定审核通过率)
85. 在『场景描述』输入框中,用一句话描述分账业务场景。
86. 示例填写内容(推荐模板):『我司作为平台方,为旗下餐饮门店提供订单系统服务,需将消费者支付金额按约定比例分给门店经营者,作为营业款结算。』
87. 字数建议:50~200 字。
88. 必须包含三要素:① 谁分给谁 ② 为什么分 ③ 资金用途。
89. 可选:上传业务证明资料(合同、平台与商户的协议截图等)。
90. 点击『提交邀请』。

▲ 操作路径:填写场景描述 → 写50-200字含三要素 → 可选上传资料 → 提交邀请
|
ℹ️ 提示:场景描述示例请参照官方文档:https://pay.weixin.qq.com/doc/v3/partner/4012072589 |
|
⚠️ 注意:场景描述是审核依据,请如实填写。写得太笼统(如『分账业务』『平台抽佣』)可能被驳回,重新提交会延误时间。建议参照官方模板详细写。 |
3.4 子商户侧确认授权
服务商发起邀请后,子商户需要在自己的商户平台主动确认授权,并设置最大分账比例。
【关键点】子商户不确认,授权就不会生效。请提前与子商户沟通好,让对方尽快操作。
子商户访问入口:https://pay.weixin.qq.com/
步骤 1:子商户登录商户平台
91. 子商户在浏览器打开 https://pay.weixin.qq.com/
92. 使用子商户的超级管理员微信扫码登录。
93. 【提示】子商户会收到微信支付公众号的『待办通知』,点开通知会自动跳转到授权页面。

▲ 操作路径:子商户打开网址 → 超级管理员扫码登录
步骤 2:进入授权列表
94. 左侧菜单:『产品中心』。
95. 在产品中心下找到『我授权的产品』(部分版本叫『授权管理』)。
96. 在列表中找到来自您(服务商)发起的『分账』授权邀请。
97. 完整路径:产品中心 → 我授权的产品 → 找到分账授权邀请。
98. 【如果列表是空的】可能是服务商没发起邀请(回 3.3 重新发起),或子商户登录的账号不是被邀请的账号。

▲ 操作路径:左侧产品中心 → 找到我授权的产品 → 找到分账授权邀请
授权确认官方说明:https://pay.weixin.qq.com/doc/v3/partner/4012072589
步骤 3:确认授权 + 签署协议
99. 点击对应邀请右侧的『查看详情』。
100. 阅读服务商信息、分账场景描述。
101. 点击『同意授权』。
102. 弹出《分账服务协议》,阅读后点击『签署协议』。
103. 【签署方式】部分协议需要法人微信扫码签署,部分直接点击『签署』即可。
104. 页面弹出『授权成功』提示。

▲ 操作路径:点击查看详情 → 阅读服务商信息 → 同意授权 → 阅读协议 → 签署协议

▲ 签署《微信支付商户号与APPID授权协议》
步骤 4:设置最大分账比例(关键)
105. 签署完成后,页面会跳转到『分账授权』设置页。
106. 在『允许服务商分账的最大比例』输入框填数字(0-30,单位 %)。
107. 【建议】填 30(默认上限),这样服务商有灵活空间,实际分账比例由代码控制。
108. 默认值 30,表示服务商最多能从每笔订单分走 30%。
109. 点击『保存』。
110. 完整路径:产品中心 → 授权的产品 → 分账授权 → 设置比例。

▲ 操作路径:跳转分账授权设置页 → 填写最大比例 → 建议填30 → 点击保存
|
ℹ️ 提示:30% 是『服务商最多能分走』的上限,不是『子商户只能拿 30%』。子商户默认自留 70%-100%。 |
【举例】订单金额 100 元,子商户设置最大比例 30%。您可以在代码中分 5%、10%、20%、30% 都可以,但不能超过 30%。如果想分 50%,需要子商户在第六部分介绍的方法中提高上限。
|
ℹ️ 提示:必须子商户确认后,分账产品才算真正生效。如果子商户长期不确认,可让子商户登录后按上述路径操作,或服务商重新发起邀请。 |
第四部分 第三步:添加子服务商(特约商户)
如果您还没有子商户,需要先添加。如果已经有子商户并已授权分账,可跳过本部分。
4.1 子商户进件的3种方式
微信支付提供3种添加子商户的方式,按业务量与开发能力选择:
|
方式 |
适用场景 |
推荐度 |
入口 |
|
服务商平台手动进件 |
免开发,单个/少量商户入驻 |
推荐新手 |
无 |
|
商家扫码自助入驻 |
免开发,批量商户入驻 |
推荐大批量 |
下载『渠道商拓展二维码』 |
|
进件 API 接口对接 |
有开发能力,批量+自动化 |
推荐中大型平台 |
https://pay.weixin.qq.com/doc/v3/partner/4012719997 |
|
ℹ️ 提示:无论哪种方式,都需准备子商户的『主体类型对应资料』。各主体类型所需资料见下表。 |
4.2 主体类型与所需资料(5类)
来源:微信支付官方文档 https://pay.weixin.qq.com/doc/v3/partner/4012062365
|
主体类型 |
定义 |
所需资料 |
|
小微 |
无营业执照、免办理工商注册登记的实体商户 |
小微经营者个人身份证、负责人身份证、辅助证明(门店场所或流动经营证明) |
|
个体工商户 |
营业执照主体为个体户、个体工商户、个体经营 |
营业执照、经营者身份证、结算银行卡 |
|
企业 |
营业执照主体为有限公司、有限责任公司 |
营业执照、法人身份证、组织机构代码证(未三证合一需提供)、结算银行账户 |
|
党政、机关及事业单位 |
政府机构、事业单位(公安/司法/医疗/教育等) |
登记证书、法人身份证、组织机构代码证(未三证合一需提供)、结算银行账户 |
|
其他组织 |
社会团体、民办非企业、基金会(需有组织机构代码证) |
登记证书(如民办非企业单位登记证书)、法人身份证、组织机构代码证 |
|
⚠️ 注意:资料要求:①所有材料原件拍照或复印件加盖公章;②身份证正反面均需加盖公章或财务章(部门章不支持);③影像资料不支持截图、翻拍或镜像照片。 |
4.3 方式一:服务商平台手动进件
访问入口:https://pay.weixin.qq.com/index.php/partner/public/home

▲ 特约商户进件流程图(来源:官方文档 4012062375)
进件流程官方说明:https://pay.weixin.qq.com/doc/v3/partner/4012062375
步骤 1:进入特约商户管理
111. 服务商平台左侧菜单:『服务商功能』 → 『特约商户管理』。
112. 页面右侧点击『添加特约商户』绿色按钮。
113. 完整路径:服务商功能 → 特约商户管理 → 添加特约商户。

▲ 操作路径:登录服务商平台 → 服务商功能 → 特约商户管理 → 添加特约商户
添加特约商户官方说明:https://pay.weixin.qq.com/doc/v3/partner/4012064824
步骤 2:选择主体类型
114. 在『主体类型』下拉框选择对应类型(个体工商户/企业/党政机关/其他组织)。
115. 注意:手动进件不支持小微商户,小微必须用扫码入驻或 API。
116. 对应资料按 4.2 准备。

▲ 操作路径:主体类型下拉框 → 选择对应类型
步骤 3:填写主体资料(详细字段)
117. 商户名称:与营业执照上『名称』完全一致(含括号、全角字符)。
118. 商户简称:用于账单显示,建议 4-16 字符。
119. 营业执照号:18 位统一社会信用代码。
120. 营业期限:按营业执照有效期填写,长期填『长期』。
121. 注册地址:营业执照上的注册地址(一字不差)。
122. 法人/经营者姓名:与营业执照一致。
123. 身份证号:法人/经营者身份证号。
124. 身份证有效期:按证件有效期填写,长期填『长期』。
125. 上传附件:营业执照照片、身份证正反面照片(JPG/PNG/单张 ≤2M)。

▲ 操作路径:填商户简称 → 填营业执照 → 填法人信息 → 上传营业执照扫描件
步骤 4:填写经营资料
126. 经营场景:勾选『线下门店』『公众号』『小程序』『网站』『APP』等(可多选)。
127. 经营类目:按主营选(如餐饮美食、零售超市、生活服务等),特殊类目需资质。
128. 门店名称:用于支付完成页显示。
129. 门店地址:实际经营地址。
130. 客服电话:对外服务的客服座机或手机。
131. 若使用小程序/公众号支付:填写要绑定的 AppID(一次性绑定,省去后续单独关联步骤)。

▲ 操作路径:填经营场景 → 填门店地址 → 上传门店照片
步骤 5:填写结算资料
132. 结算银行卡户名:必须与营业执照主体一致(小微可以是法人个人卡)。
133. 开户银行:选银行总行或分行(如『工商银行深圳福田支行』)。
134. 开户行省市:银行所在省市。
135. 银行账号:14-23 位数字。
136. 结算周期:T+1(次工作日到账)或 D+1(当天到账),按类目开放。
137. 费率:默认 0.6%,可与服务商商务洽谈降低。

▲ 操作路径:选择开户银行 → 填银行账号 → 确认户名=主体名称
步骤 6:提交审核与验证
138. 提交资料后等待审核(1-3 个工作日)。
139. 审核通过后,微信支付向子商户银行卡打一笔随机金额(0.01~1 元)。
140. 子商户登录商户平台 pay.weixin.qq.com 回填收款金额完成验证。
141. 若超级管理员为法人/经营者:可使用法人微信扫码验证,免打款。
142. 若为负责人:需法人微信扫码 或 汇款验证(二选一)。
143. 验证通过后,子商户号正式启用。

▲ 操作路径:检查资料 → 点击提交 → 等待1-3工作日 → 子商户完成打款验证
|
ℹ️ 提示:快捷验证:个体工商户、企业类型,若超级管理员为法人/经营者本人,无需账户验证;若为负责人,支持法人微信扫码验证或汇款验证。 |
4.4 方式二:商家扫码自助入驻(推荐批量)
服务商下载『渠道商拓展二维码』,让商家微信扫码自助提交资料。适合几十到几百个商家入驻。
官方文档:https://pay.weixin.qq.com/doc/v3/partner/4012064824

▲ 商家注册小程序流程图
步骤 1:服务商下载渠道二维码
144. 服务商平台左侧:『服务商功能』 → 『特约商户管理』。
145. 页面右上角点击『下载渠道商拓展二维码』。
146. 保存二维码图片,发给商家联系人。
147. 完整路径:服务商功能 → 特约商户管理 → 下载拓展二维码。

▲ 操作路径:登录服务商平台 → 服务商功能/特约商户管理 → 下载拓展二维码 → 保存图片

▲ 服务商平台:服务商功能 → 特约商户管理 → 下载拓展二维码
步骤 2:商家联系人扫码
148. 商家联系人(可以是店员、财务、业务负责人、法人本人)用微信扫一扫二维码。
149. 点击『启用该功能』。
150. 微信推送一条模板消息,点击进入『商家注册』小程序。
151. 点击『去提交』核实商家身份。
152. 注意:核实渠道码右上角 ID 是否与进件时一致。

▲ 操作路径:商家联系人微信扫一扫 → 扫描渠道二维码 → 进入商家入驻小程序

▲ 商家扫渠道码认证
步骤 3:选择主体类型 + 填写联系人
153. 在小程序中选择商家主体类型(小微/个体工商户/企业/党政机关/其他组织)。
154. 填写联系人姓名、手机号,接收短信验证码。
155. 点击『下一步』。

▲ 操作路径:选主体类型 → 填联系人姓名 → 填手机号 → 接收短信验证码

▲ 商家选择主体类型 + 填写联系人
步骤 4:提交商家资料
156. 按主体类型上传对应资料(参考 4.2)。
157. 上传营业执照、法人/经营者身份证正反面。
158. 上传行业资质(特殊行业,如医疗、教育等;非特殊行业可选『未涉及特殊行业,无需提交资质』)。
159. 所有材料原件拍照或复印件加盖公章,不支持截图、翻拍或镜像。
160. 点击『提交』。

▲ 操作路径:上传营业执照 → 上传法人身份证 → 上传门店照片 → 点击提交

▲ 商家提交资料示例
步骤 5:记录申请单号(备查)
161. 提交后会触发模板消息通知,生成『申请单编号』。
162. 建议记录单号,后续申请有问题可提供给微信支付工作人员协查。

▲ 操作路径:提交后生成申请单编号 → 记录单号备查

▲ 申请单编号示例
步骤 6:法人授权(重要)
163. 联系人提交资料后,需要法人本人确认授权。
164. 方式 a:联系人点击『向 XXX 发送验证邀请』,拉起微信消息列表,转发给法人。
165. 方式 b:法人微信扫码授权(已绑卡)。
166. 方式 c(仅企业):对公账户汇款验证。微信支付指定银行卡,汇 0.01~1 元,T+1 原路退回。
167. 法人授权后申请单进入『审核中』。

▲ 操作路径:法人收到通知 → 扫码进入授权页 → 确认商家资料 → 完成法人授权
|
⚠️ 注意:不同主体授权方式不同:①个体工商户=法人微信授权;②企业=法人微信 或 对公汇款;③小微=法人微信;④党政机关=微信客服回访;⑤其他组织=对公汇款。 |
步骤 7:商家预授权商户号(推荐)
168. 前置条件:商家申请单进入『审核中』或『待账户验证』状态。
169. 商家点击页面下方『进行预授权』,进入授权页。
170. 查看渠道商信息,勾选商户号,授权服务商提供服务。
171. 审核通过后无需再次授权。

▲ 操作路径:法人授权完成 → 进入预授权商户号页 → 设置商户号信息 → 完成预授权
|
ℹ️ 提示:只有商户全称与所注册商家名称一致的商户号才能进行授权。 |
4.5 方式三:进件 API 接口对接
适合有开发能力、需批量自动化入驻的服务商。
接口文档:https://pay.weixin.qq.com/doc/v3/partner/4012719997
进件 API 核心接口:
|
接口名称 |
方法 |
路径 |
用途 |
|
提交申请单 |
POST |
/v3/applyment4sub/applyment/ |
服务商提交特约商户进件资料 |
|
查询申请单状态 |
GET |
/v3/applyment4sub/applyment/{applyment_id} |
通过申请单号查审核结果 |
|
通过业务申请编号查询 |
GET |
/v3/applyment4sub/applyment/business_number/{business_code} |
通过业务编号反查 |
|
修改结算账户 |
POST |
/v3/applyment4sub/sub_merchants/{sub_mchid}/modify-settlement |
协助子商户改结算账户 |
|
ℹ️ 提示:小微主体进件仅对进件质量符合条件的服务商开放,属于该接口下的高级能力(需单独申请)。 |

▲ 超管核对联系信息(来源:官方文档 4012062375)

▲ 微信支付商家助手公众号推送申请进展通知

▲ 超管完成账户验证(来源:官方文档 4012062375)

▲ 超管完成签约(来源:官方文档 4012062375)
4.6 各主体类型资料详细对照(截图)
以下为官方文档中各主体类型的资料填写示意:

▲ 商家主体类型与所需资料总览
小微商户、个体工商户、企业资料填写示意请参考官方文档(含截图):
官方资料示意:https://pay.weixin.qq.com/doc/v3/partner/4012064824

▲ 商家注册全流程示意

▲ 商家主体类型与所需资料(旧版参考)
4.7 关联小程序/公众号 AppID
若子商户要在小程序/公众号里发起支付,必须把 AppID 关联到子商户号上。
方式一:在服务商后台关联(推荐)
步骤 1:进入开发参数配置
172. 服务商平台左侧:『合作伙伴功能』 → 『开发参数配置』 → 『开发配置』。
173. 找到『关联 AppID』或『AppID 账号管理』。
174. 点击『新增关联』。
175. 完整路径:合作伙伴功能 → 开发参数配置 → 开发配置 → 关联 AppID。

▲ 操作路径:登录服务商平台 → 产品中心 → 开发参数配置

▲ 服务商平台:合作伙伴功能 → 开发参数配置 → 关联 AppID

▲ 关联 AppID 操作页
步骤 2:填写 AppID
176. 输入要关联的小程序/公众号 AppID(如 wx 开头 18 位)。
177. 选择对应的子商户号。
178. AppID 类型:小程序/公众号/APP(按实际选)。
179. 点击『提交关联请求』。

▲ 操作路径:填入AppID → 点击提交 → 去小程序/公众号后台确认授权
方式二:在服务商后台添加子商户时,直接在『经营信息』里填写 AppID(一步到位)。

▲ 添加子商户时直接填写 AppID
方式三:通过 AppID 账号管理菜单单独关联(部分老版本入口)

▲ 产品中心 → AppID 账号管理 → 关联 AppID

▲ AppID 账号管理 - 关联操作
确认授权:小程序后台确认
步骤 1:小程序后台确认
180. 登录小程序/公众号后台 mp.weixin.qq.com。
181. 左侧菜单:『微信支付』。
182. 在『待关联商户号』列表中找到服务商发起的关联请求。
183. 点击『确认关联』。
184. 完整路径:mp.weixin.qq.com → 微信支付 → 待关联商户号 → 确认关联。

▲ 操作路径:登录mp.weixin.qq.com → 设置/基本配置 → 找到微信支付商户号 → 点击确认授权

▲ 小程序后台:微信支付 → 待关联商户号 → 确认

▲ 小程序后台确认关联
第五部分 第四步:配置分账接收方
『分账接收方』就是收钱的那一方。在调用分账接口之前,必须先建立『分账方 → 接收方』的关联关系。
|
⚠️ 注意:特别注意:每个子商户都要单独添加自己的接收方。即使服务商旗下有 b、c 两个子商户,b 要分给 c,c 也要在 b 这里被加为接收方,反过来也一样。 |
【分账接收方添加流程图】

▲ 分账接收方配置流程图(来源:微信支付官方文档 4012062375)
流程图官方说明:https://pay.weixin.qq.com/doc/v3/partner/4012062375
5.1 接收方类型
|
类型值 |
含义 |
适用场景 |
示例 |
|
MERCHANT_ID |
商户号 |
分账给微信支付商户(如平台方、供应商公司)。最常用。 |
1900000110 |
|
PERSONAL_OPENID |
个人 openid |
分账给个人微信零钱。需用『父商户 AppID』转换出的 openid。 |
oUpF8xxxxxx |
|
PERSONAL_SUB_OPENID |
个人 sub_openid |
分账给个人微信零钱。需用『子商户 AppID』转换出的 sub_openid。 |
oUpF8xxxxxx |
5.2 子商户在商户平台手动添加(无需开发)
子商户访问入口:https://pay.weixin.qq.com/
步骤 1:子商户登录商户平台
185. 子商户打开 https://pay.weixin.qq.com/,扫码登录。
186. 左侧菜单:『交易中心』。
187. 在交易中心下找到『管理分账接收方』。
188. 完整路径:交易中心 → 管理分账接收方。

▲ 操作路径:子商户打开网址 → 超级管理员扫码登录

▲ 子商户:交易中心 → 管理分账接收方
步骤 2:添加分账接收方
189. 点击页面右上角『添加分账接收方』按钮。
190. 选择对应的服务商(即您自己)。
191. 填写接收方类型:MERCHANT_ID 或 PERSONAL_OPENID。
192. 填写接收方账号(商户号或 openid)。
193. 填写接收方名称(与营业执照主体一致或个人实名)。
194. 点击『提交』。

▲ 操作路径:交易中心 → 分账接收设置 → 添加分账接收方 → 填写信息 → 保存
步骤 3:接收方确认(仅商户类型需要)
195. 提交后,被添加的接收方商户会收到一条『同意分账』的待办。
196. 接收方登录自己的商户平台 → 交易中心 → 分账接收设置 → 点击『同意』。
197. 同意后关系才正式生效。

▲ 操作路径:接收方收到通知 → 登录商户平台 → 交易中心/分账接收设置 → 点击同意

▲ 接收方在商户平台签署分账接收协议

▲ 接收方管理列表(已同意后的状态)
5.3 通过接口添加(推荐,适合批量)
接口地址:
官方文档:https://pay.weixin.qq.com/doc/v3/partner/4012690944
接口路径:POST /v3/profitsharing/receivers/add
请求体关键字段:
|
字段名称 |
是否必填 |
填写说明 |
示例值 |
|
sub_mchid |
是 |
子商户号(即特约商户号) |
1900000109 |
|
appid |
是 |
服务商 AppID(与 sub_mchid 有绑定关系) |
wx8888888888888888 |
|
receivers.type |
是 |
接收方类型:MERCHANT_ID/PERSONAL_OPENID/PERSONAL_SUB_OPENID |
MERCHANT_ID |
|
receivers.account |
是 |
接收方账号(商户号或 openid) |
1900000110 |
|
receivers.name |
商户类型必填 |
接收方名称(需用微信支付公钥加密) |
某某有限公司 |
|
receivers.relation_type |
是 |
关系类型:PARTNER/PARTNER_PLATFORM/PLATFORM/DISTRIBUTOR/SUPPLIER/CUSTOM/OTHERS |
PARTNER |
代码示例见第七部分 7.4。
第六部分 第五步:设置分账比例
分账比例由『子商户』在自己商户平台设置,限制『服务商最多能从每笔订单中分走多少』。
【什么是分账比例?】子商户告诉微信支付:『我允许服务商最多从我每笔订单里分走多少百分比』。这是子商户对服务商的让渡,由子商户自己设置。
【为什么需要这一步?】保护子商户资金安全。即使服务商调用接口想分 50%,子商户只授权了 30%,微信支付会拒绝超额分账。
|
ℹ️ 提示:关键认知:30% 是『服务商最多能分走』的上限,不是『子商户只能拿 30%』。子商户默认自留 70%-100%。 |
【举例说明】消费者支付 100 元,子商户设置最大比例 30%:
● 服务商想分 10 元 → 成功,子商户拿 90 元
● 服务商想分 30 元 → 成功(刚好到上限),子商户拿 70 元
● 服务商想分 50 元 → 失败!报错『分账金额超出最大分账比例』
6.1 四种业务模式的入口路径(必看,避免找错地方)
微信支付有4种分账业务模式,对应4个不同的设置入口。请先确认您的业务模式,再找对应入口:
【如何判断我的业务模式?】
● 普通直连商户分账:您自己开店自己收款,没有服务商,没有子商户关系。
● 普通服务商分账(最常用):您是服务商,旗下有多个子商户(特约商户),从每笔订单抽佣。这是本手册重点讲的模式。
● 电商收付通分账:您是电商平台,二级商户在您平台开店,资金先入您账户再分给二级商户。
● 连锁品牌分账:品牌总部+门店模式,品牌主从门店订单中抽成。
|
业务模式 |
设置路径 |
入口 |
适用场景 |
|
普通直连商户分账 |
登陆商户平台 → 产品中心 → 分账 → 分账管理比例 |
https://pay.weixin.qq.com/ |
适用自己开店自己收款 |
|
普通服务商分账(最常用) |
子商户登录商户平台 → 产品中心 → 授权的产品 → 分账授权 |
https://pay.weixin.qq.com/ |
本手册主要讲这个 |
|
电商收付通分账 |
登陆服务商商户平台 → 产品中心 → 我的工具箱 → 电商收付通 → 供应链分账设置 |
https://pay.weixin.qq.com/ |
电商平台二级商户 |
|
连锁品牌分账 |
登陆服务商平台 → 产品中心 → 合作工具箱 → 连锁品牌工具箱 → 品牌专区 → 品牌交易 → 品牌供应链分账 → 供应链分账管理 |
https://pay.weixin.qq.com/partner/public/home |
品牌+门店连锁 |
|
ℹ️ 提示:本手册以最常用的『普通服务商分账』为例。其他模式路径略有不同,但操作逻辑一致。 |
6.2 普通服务商分账比例设置(详细步骤)
【操作人】子商户的超级管理员(不是服务商操作)
【时间】签署授权协议后立即可以设置
子商户访问入口:https://pay.weixin.qq.com/
步骤 1:子商户登录商户平台
198. 子商户打开 https://pay.weixin.qq.com/,扫码登录。
199. 使用『超级管理员』微信扫码(普通操作员看不到设置入口)。
200. 【如何确认是不是超管?】登录后右上角账号信息显示『超级管理员』。如果不是,需要联系超管扫码或开通权限。

▲ 操作路径:子商户打开网址 → 超级管理员扫码登录
步骤 2:进入分账授权页
201. 左侧菜单:『产品中心』。
202. 在产品中心下找到『授权的产品』(部分版本叫『我授权的产品』)。
203. 找到『分账授权』(或叫『分账』)项,点击『管理』或『产品设置』。
204. 完整路径:产品中心 → 授权的产品 → 分账授权 → 设置比例。
205. 【找不到『授权的产品』?】可能是子商户还没收到服务商的邀请(回 3.3 重新发起),或子商户开通分账产品失败(回 3.2.2 重新开通)。

▲ 操作路径:左侧产品中心 → 找到授权的产品 → 找到分账授权 → 点击管理或产品设置
步骤 3:设置最大分账比例
206. 在『允许服务商分账的最大比例』输入框中填写数字(0-30 之间,单位 %)。
207. 默认值:30%。
208. 示例:填 20 表示服务商最多从每笔订单分走 20%。
209. 【建议】直接填 30(默认值),给服务商留足灵活空间,实际分多少由代码控制。
210. 点击『保存』或『提交』。
211. 保存即时生效,无需审核。

▲ 操作路径:找到最大比例输入框 → 填数字0-30 → 建议填30 → 点击保存

▲ 子商户设置分账比例(新版入口位置)

▲ 分账比例设置页(旧版示意)
|
⚠️ 注意:此比例设置完成后,调用请求分账接口时,分账总金额不能超过:订单金额 × 最大分账比例。否则会报错『分账金额超出最大分账比例』(错误码 271643173)。 |
【举例】订单金额 100 元,子商户设置最大比例 30%,那么服务商调用接口时,分账总金额不能超过 100×30%=30 元。
6.3 如何提高分账比例(>30%)
如果业务需要分账比例超过 30%(如 50%、100%),按以下方式申请:
【什么场景需要 >30%?】
● 品牌统收分账:消费者付款给品牌总部,总部 100% 收款后分给门店
● 供应链分账:上游供应商从下游门店抽大头(如 60%)
● 电商平台抽佣:平台从订单抽 40% 服务费
|
⚠️ 注意:申请主体:由『子商户』主动申请(不是服务商代申请),因为限制是子商户对服务商的让渡。 |
6.3.1 第一步:在线申请 30% → 50%(无需邮件)
【适用场景】需要分账比例 30%-50% 之间。
【操作人】子商户超级管理员
步骤 1:子商户登录商户平台
212. https://pay.weixin.qq.com/ → 扫码登录。
213. 产品中心 → 授权的产品 → 分账授权 → 设置比例。
214. 【前提】已经签署过分账授权协议,且当前比例为 30%。

▲ 操作路径:扫码登录 → 产品中心/授权的产品/分账授权/设置比例
步骤 2:点击『申请调高比例』
215. 在『最大分账比例』输入框右侧,点击『申请调高』链接。
216. 【如果没有此链接】说明当前商户号不支持在线申请,请走 6.3.3 客服通道。
217. 填写申请理由(50-200 字,说明为什么需要更高比例)。
218. 上传补充材料:

▲ 操作路径:找到最大比例输入框右侧 → 点击申请调高 → 填写理由50-200字 → 上传补充材料
- 营业执照(彩色扫描件或清晰照片)
- 与分账接收方的合作协议(盖章版)
- 分账业务场景说明(谁分给谁、为什么分、金额计算规则)
- 行业特殊资质(如医疗/教育等)
步骤 3:提交等待审核
219. 点击『提交申请』。
220. 审核周期:约 7 个工作日。
221. 通过后会在原设置位置看到新的比例上限(50%)。
222. 调用接口时按新上限校验。
223. 【审核期间怎么办?】仍按 30% 上限调用接口,通过后再调高。

▲ 操作路径:点击提交申请 → 等待约7工作日 → 通过后看到新比例上限50%
6.3.2 第二步:邮件申请 50% → 100%(需邮件)
如果 50% 仍无法满足业务需求(如品牌统收分账给门店场景需要 100%),需要单独邮件申请:
【100% 分账含义】消费者付款 100 元,服务商/品牌主可以分走全部 100 元,再自己分配给各接收方。
|
项目 |
内容 |
说明 |
|
申请邮箱 |
WeChatPayFunds@tencent.com |
微信支付业务专用邮箱 |
|
邮件主题 |
【微信支付品牌高比例分账申请】+ 服务商公司全称 |
必须按此格式 |
|
申请方 |
由服务商提交 |
服务商代商户提交材料 |
|
比例范围 |
50% 和 100% 需分别申请 |
100% 审核更严格 |
|
额外材料(100%) |
资金监管协议 |
证明资金安全监管机制 |
|
审核周期 |
7-15 个工作日 |
比 50% 申请更久 |
|
ℹ️ 提示:申请参考文档:分账资料包-第四部分 https://docs.qq.com/doc/DR0lVQkRXdHNlbHJx |
|
⚠️ 注意:重要提示:现有及后续新增的收款方,只要占比超过 30%,均需单独通过邮件申请并上传合同协议。意味着多个接收方都要重新签订合同。 |
6.3.3 客服咨询通道(无法找到入口时)
如果在商户平台找不到『申请调高比例』入口(部分老商户号未开放在线申请):
步骤 1:拨打微信支付客服
224. 电话:95017。
225. 转接『商户服务』或按语音提示选择『分账业务』。
226. 说明:『我是特约商户 XXX,需要申请提高分账比例,请告知流程』。
227. 【工作时间】9:00-22:00(全年无休)

▲ 操作路径:拨打95017 → 转接商户服务 → 说明申请提高分账比例
步骤 2:提供商户信息
228. 商户号:16xxxxxxxx 或 19xxxxxxxx(10 位数字)。
229. 商户全称:营业执照上的公司全称。
230. 法人姓名:法人身份证姓名。
231. 客服会通过邮箱发送申请指引。
232. 【提示】客服不能直接帮你调高比例,只能告诉你申请流程。真正的审核还是走邮件。

▲ 操作路径:提供商户号 → 提供商户全称 → 提供法人姓名 → 客服发送申请指引邮件
6.4 连锁品牌分账比例设置(品牌供应链分账专属)
如果您的业务是『品牌+门店』模式,需要走品牌供应链分账,路径略有不同:
【什么是连锁品牌分账?】品牌总部(如某奶茶品牌)有多家门店,消费者在门店付款后,资金先进入品牌总账户,再由品牌总部按约定比例分给各门店。
服务商访问入口:https://pay.weixin.qq.com/partner/public/home
步骤 1:服务商开通连锁品牌工具箱
233. 服务商登录服务商平台 https://pay.weixin.qq.com/partner/public/home。
234. 左侧:『合作工具箱』 → 找到『连锁品牌工具箱』 → 点击『开通』。
235. 按提示完成品牌申请、邀请品牌总部授权、品牌门店管理等操作。
236. 【前提】服务商已开通分账产品(第三部分),且有至少一个品牌商户授权。

▲ 操作路径:服务商登录服务商平台 → 左侧合作工具箱 → 找到连锁品牌工具箱 → 点击开通

▲ 服务商平台:合作工具箱 → 连锁品牌工具箱 → 开通
步骤 2:品牌主设置分账比例
237. 品牌主登录商户平台 https://pay.weixin.qq.com/。
238. 进入『品牌专区』 → 『品牌交易』 → 『品牌供应链分账』 → 『供应链分账管理』。
239. 在此页面可调整品牌主与门店之间的分账比例。
240. 基础分账比例默认 30%,可在线申请调高到 50%(品牌主申请后品牌主和门店均适用)。

▲ 操作路径:品牌主登录商户平台 → 进入品牌专区 → 品牌交易/品牌供应链分账 → 供应链分账管理/调整比例

▲ 品牌供应链分账关系示意(品牌/门店/合作伙伴/导购)
步骤 3:50% → 100% 品牌统收分账(特殊场景)
241. 若品牌主有营销场景(如品牌营销售券,再分账给门店),可申请『品牌统收分账』。
242. 申请入口:品牌专区 → 品牌交易 → 品牌供应链分账 → 供应链分账管理 → 申请。
243. 开通后品牌主可直接 100% 分账给门店。
244. 若 100% 仍不够,邮件申请:WeChatPayFunds@tencent.com,主题『微信支付品牌高比例分账申请 + 服务商公司全称』。

▲ 操作路径:品牌专区/品牌交易/品牌供应链分账 → 供应链分账管理/申请 → 申请品牌统收分账100%

▲ 品牌统收分账申请 100% 入口
6.5 分账比例的核心规则(必须知道)
【非技术人员必读】以下 8 条规则决定您的分账业务能否正常运转:
|
规则 |
说明 |
重要程度 |
|
按金额分账 |
微信支付只接受按金额分账,不接受按比例分账。比例的作用是限制『最多能分多少』,不是分账方式。 |
重要 |
|
默认值 30% |
所有分账模式初始默认最大比例为 30%。 |
通用 |
|
单笔订单校验 |
分账总金额 ≤ 订单金额 × 最大分账比例。 |
接口调用时校验 |
|
冻结期 30/180 天 |
普通服务商分账订单冻结 30 天,电商/品牌分账订单冻结 180 天。超时未分则自动解冻给分账方。 |
时效 |
|
多次分账 |
同一笔订单最多分账 50 次,每次最多分给 50 个接收方。 |
频次 |
|
剩余资金 |
服务商只需传入分给他方的账号和金额,订单剩余未分账资金平台默认都属于分账方,处理分账时直接解冻。 |
结算 |
|
分账失败处理 |
接收方账户不可用导致的失败,资金自动转回分账方。 |
异常 |
|
接收方资金提现 |
分账接收方收到资金后,需要手动提现到银行账户(不会自动提现)。 |
到账 |
【规则1详解】按金额分账,不是按比例分账。意思是:调用接口时,必须传具体金额(如 10 元=1000 分),不能传比例(如 10%)。
【规则4详解】冻结期:消费者付款后,资金先被冻结。普通服务商分账订单冻结 30 天,电商/品牌分账订单冻结 180 天。在冻结期内必须完成分账,否则过期自动解冻给子商户,无法再分。
【规则6详解】剩余资金:如订单 100 元,服务商分走 10 元,剩余 90 元会自动解冻给子商户,不需要再调用接口。
|
❌ 重要:下单时未传 profit_sharing=true 的订单,不能分账。下单后不能补传分账标识,请默认开启。 |
第七部分 第六步:代码开发接入
前置页面操作全部完成后(服务商开通分账 + 子商户授权 + 添加接收方 + 设置比例),即可进入代码开发阶段。
【非技术人员必读】从这一部分开始,需要后端开发人员接手。但请非技术人员也读一下 7.1 和 7.2,了解需要给开发同事提供哪些参数和资料。
【交接清单】非技术人员在交接给开发同事前,请准备好以下资料:
● 1) 服务商商户号(10 位数字,登录服务商平台后右上角可见)
● 2) 服务商 AppID(在公众平台 → 设置 → 基本配置 可见)
● 3) 商户 API 证书序列号 + apiclient_key.pem 私钥文件(在服务商平台 → 账户中心 → API 安全 下载)
● 4) APIv3 密钥(自己设置的 32 位字符串,请妥善保存)
● 5) 子商户号(特约商户的 10 位商户号)
● 6) 子商户 AppID(如果用子商户自己的小程序/公众号支付)
● 7) 微信支付平台证书(可让开发同事通过接口自动获取,或手动下载)
|
✓ 建议:把这些资料交给后端开发同事,对方就能根据本部分 7.4-7.6 的代码完成对接。 |
7.1 开发前准备清单
开发前请确认以下资料已准备齐全:
|
序号 |
参数 |
在哪里获取 |
示例值 |
|
1 |
服务商商户号 mch_id |
10 位数字,登录服务商平台首页可见 |
1900000108 |
|
2 |
服务商 AppID |
在 mp.weixin.qq.com → 设置 → 开发设置 可见 |
wx8888888888888888 |
|
3 |
子商户号 sub_mchid |
10 位数字,在服务商平台 → 特约商户管理 可见 |
1900000109 |
|
4 |
子商户 AppID |
子商户的小程序/公众号 AppID(如使用) |
wx8888888888888889 |
|
5 |
APIv3 密钥 |
32 位字符串,在服务商平台 → 账户中心 → API 安全 → 设置 APIv3 密钥 |
abcdefghijklmnopqrstuvwxyz123456 |
|
6 |
商户证书序列号 |
40 位十六进制字符串,下载 API 证书后可见 |
01234ABCD56789... |
|
7 |
商户私钥文件 |
下载 API 证书后获得的 apiclient_key.pem 文件 |
C:/cert/apiclient_key.pem |
|
8 |
微信支付平台证书 |
可让 SDK 自动下载(推荐),或手动从接口获取 |
自动管理 |
|
9 |
回调 URL |
您的服务器公网地址 + /api/wxpay/profit-sharing/notify,必须 https |
https://your-domain.com/api/wxpay/profit-sharing/notify |
|
ℹ️ 提示:【如何下载 API 证书】登录服务商平台 → 账户中心 → API 安全 → 申请 API 证书 → 下载 apiclient_key.pfx 和 apiclient_key.pem 文件。请妥善保存,不要泄露。 |
|
⚠️ 注意:【如何设置 APIv3 密钥】登录服务商平台 → 账户中心 → API 安全 → 设置 APIv3 密钥 → 输入 32 位字符串(自己设置,含字母数字,区分大小写)。请保存好,无法找回只能重置。 |
【代码开发业务流程图】

▲ 分账全流程业务时序图(来源:微信支付官方文档 4012062375)
流程图官方说明:https://pay.weixin.qq.com/doc/v3/partner/4012062375
上图展示了完整的分账时序:下单→支付→添加接收方→请求分账→查询结果→完结分账→(如退款)分账回退。
7.1.1 如何申请商户API证书(10步截图)
商户API证书是调用微信支付所有接口的必备条件。以下为官方文档的10步申请流程截图:
申请证书官方文档:https://pay.weixin.qq.com/doc/v3/partner/4013058924
【操作路径】服务商平台 → 账户中心 → 账户设置 → API 安全 → 商户API证书 → 申请证书
步骤 1-2:登录商户平台,下载证书工具
245. 登录 pay.weixin.qq.com → 账户中心 → API 安全 → 点击『申请证书』
246. 在弹出窗口内点击『下载证书工具』按钮
247. 复制商户号和商户名称

▲ 步骤一:登录商户平台,点击账户中心-API安全-申请证书

▲ 步骤二:下载证书工具,复制商户号和商户名称
步骤 3-4:安装证书工具,填写商户信息
248. 安装证书工具并打开
249. 选择证书存储路径
250. 点击『申请证书』
251. 将复制的商户号和商户名称粘贴到证书工具中
252. 点击『下一步』

▲ 步骤三:安装证书工具,选择存储路径,点击申请证书

▲ 步骤四:将商户号和商户名称粘贴到证书工具
步骤 5-6:复制证书请求串,粘贴到商户平台
253. 在证书工具中,复制证书请求串
254. 回到商户平台
255. 将证书工具中复制的请求串粘贴到商户平台文本框中
256. 点击『下一步』

▲ 步骤五:在证书工具中复制证书请求串

▲ 步骤六:将请求串粘贴到商户平台文本框
步骤 7-8:安全验证,复制证书串
257. 安全验证:输入操作密码 + 短信验证码
258. 点击『确定』
259. 在商户平台『复制证书串』环节,点击『复制证书串』

▲ 步骤七:安全验证,输入操作密码和短信验证码

▲ 步骤八:在商户平台复制证书串
步骤 9-10:粘贴证书串到工具,完成申请
260. 将商户平台复制的证书串粘贴到证书工具中
261. 点击『下一步』
262. 申请商户API证书成功
263. 点击『查看证书文件夹』,查看已生成的证书文件

▲ 步骤九:将证书串粘贴到证书工具

▲ 步骤十:申请成功,查看证书文件夹
【证书文件说明】生成后的证书文件为压缩包,解压后有 4 个文件:

▲ 证书文件解压后的4个文件:p12格式、pem格式、私钥pem格式、说明文件
● apiclient_cert.p12:p12 格式证书(APIv2 用)
● apiclient_cert.pem:pem 格式证书
● apiclient_key.pem:证书私钥(APIv3 签名用,最重要!)
● README.md:说明文件
|
❌ 重要:请将生成的证书文件转交给技术人员,由技术人员将证书部署到服务器上。私钥文件 apiclient_key.pem 只能通过证书工具导出,若丢失无法找回,只能作废重新申请。 |
证书申请完整官方文档:https://pay.weixin.qq.com/doc/v3/partner/4013058924
7.2 业务流程
完整分账流程(来自微信支付官方业务流程图):
264. 下单时传 profit_sharing=true(标识为分账订单)。
265. 用户支付成功,资金进入『冻结池』(默认冻结期 30 天,电商分账 180 天)。
266. 调用『添加分账接收方』接口建立接收方关系(一次性,已添加可跳过)。
267. 调用『请求分账』接口发起分账(接口异步受理,返回 order_id 不代表成功)。
268. 调用『查询分账结果』接口轮询/查询分账最终结果。
269. (可选)调用『完结分账』接口把剩余资金解冻给分账方。
270. (如退款)先调用『请求分账回退』把已分资金回退,再处理退款。
7.3 接口清单
|
接口名称 |
方法 |
路径 |
用途 |
|
添加分账接收方 |
POST |
/v3/profitsharing/receivers/add |
建立分账关系 |
|
删除分账接收方 |
POST |
/v3/profitsharing/receivers/delete |
解除分账关系 |
|
请求分账 |
POST |
/v3/profitsharing/orders |
发起分账,异步受理 |
|
查询分账结果 |
GET |
/v3/profitsharing/orders/{out_order_no} |
查询分账最终结果 |
|
完结分账 |
POST |
/v3/profitsharing/orders/{out_order_no}/finish |
解冻剩余资金给分账方 |
|
查询订单剩余待分金额 |
GET |
/v3/profitsharing/transactions/{transaction_id}/amounts |
查可分余额 |
|
请求分账回退 |
POST |
/v3/profitsharing/returns |
已分资金回退 |
|
查询分账回退结果 |
GET |
/v3/profitsharing/returns/{out_return_no} |
查回退结果 |
|
分账动账通知 |
POST(回调) |
商户配置的 notify_url |
分账/回退结果异步通知 |
7.4 完整 Java 代码示例
以下代码基于微信支付 APIv3 + Apache HttpClient,可直接放进 Spring Boot 项目。参数需替换为您自己的商户号、证书路径等。
|
ℹ️ 提示:代码来源:微信支付官方示例 https://pay.weixin.qq.com/doc/v3/partner/4015870957,已整理为可执行片段。 |

▲ 分账产品模型图:分账发起方 → 分账方 → 接收方(来源:官方文档 4015870957)

▲ 代码对接全流程时序图(来源:微信支付官方文档 4012062375)
7.4.1 创建 HttpClient(带签名验证)
|
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder; import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner; import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials; import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator; import com.wechat.pay.contrib.apache.httpclient.util.PemUtil; import org.apache.http.impl.client.CloseableHttpClient;
import java.io.FileInputStream; import java.security.PrivateKey;
public class WxPayClient { // ===== 替换成自己的参数 ===== private static final String MCH_ID = "1900000108"; // 服务商商户号 private static final String MCH_SERIAL = "xxxxxxxxxxxx"; // 商户API证书序列号 private static final String API_V3_KEY = "xxxxxxxxxxxx"; // APIv3 密钥 private static final String KEY_PATH = "C:/cert/apiclient_key.pem"; // 商户私钥文件
private static CloseableHttpClient httpClient;
static { try { PrivateKey privateKey = PemUtil.loadPrivateKey( new FileInputStream(KEY_PATH)); httpClient = WechatPayHttpClientBuilder.create() .withMerchant(MCH_ID, MCH_SERIAL, privateKey) .withValidator(new WechatPay2Validator( // 自动获取并校验微信支付平台证书 CertManagerSingleton.getCertManager(API_V3_KEY).getVerifier())) .build(); } catch (Exception e) { throw new RuntimeException("初始化微信支付 HttpClient 失败", e); } }
public static CloseableHttpClient getClient() { return httpClient; } } |
7.4.2 添加分账接收方
添加接收方接口文档:https://pay.weixin.qq.com/doc/v3/partner/4012477758

▲ 接收方添加成功后可在商户平台查看(来源:官方文档 4013058924)
|
import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpResponse; import org.apache.http.util.EntityUtils;
public class AddReceiver { /** * 添加分账接收方 * 接口:POST /v3/profitsharing/receivers/add * 文档:https://pay.weixin.qq.com/doc/v3/partner/4012690944 */ public static String addReceiver(String subMchid, String receiverAccount) throws Exception { String url = "https://api.mch.weixin.qq.com/v3/profitsharing/receivers/add";
// 请求体 JSON String reqdata = "{" + "\"sub_mchid\":\"" + subMchid + "\"," + "\"appid\":\"wx8888888888888888\"," // 服务商 AppID + "\"receivers\":[{" + "\"type\":\"MERCHANT_ID\"," // 接收方类型:商户号 + "\"account\":\"" + receiverAccount + "\"," // 接收方商户号 + "\"name\":\"某某合作公司\"," // 接收方名称(需用微信支付公钥加密) + "\"relation_type\":\"PARTNER\" // 关系类型:合作伙伴 + "}]" + "}";
HttpPost httpPost = new HttpPost(url); httpPost.addHeader("Accept", "application/json"); httpPost.addHeader("Content-Type", "application/json"); // Wechatpay-Serial 头:填微信支付公钥ID或平台证书序列号 httpPost.addHeader("Wechatpay-Serial", "PUB_KEY_ID_xxx"); httpPost.setEntity(new StringEntity(reqdata, "utf-8"));
try (CloseableHttpResponse response = WxPayClient.getClient().execute(httpPost)) { int code = response.getStatusLine().getStatusCode(); String body = EntityUtils.toString(response.getEntity()); if (code == 200) { System.out.println("添加分账接收方成功:" + body); return body; } else { throw new RuntimeException("添加失败:" + code + " " + body); } } } } |
7.4.3 请求分账
请求分账接口文档:https://pay.weixin.qq.com/doc/v3/partner/4012691594

▲ 分账产品模型图:请求分账对应图中『分账发起方 → 接收方』的资金流向(来源:4015870957)
|
public class CreateProfitSharing { /** * 请求分账 * 接口:POST /v3/profitsharing/orders * 文档:https://pay.weixin.qq.com/doc/v3/partner/4012692975 */ public static String create(String subMchid, String transactionId, String outOrderNo, String receiverAccount, int amount) throws Exception { String url = "https://api.mch.weixin.qq.com/v3/profitsharing/orders";
// 关键:分账金额单位是「分」,100 = 1 元 // receivers.amount 总和 ≤ 订单金额 × 子商户设置的最大分账比例 String reqdata = "{" + "\"sub_mchid\":\"" + subMchid + "\"," + "\"appid\":\"wx8888888888888888\"," + "\"transaction_id\":\"" + transactionId + "\"," // 微信支付订单号 + "\"out_order_no\":\"" + outOrderNo + "\"," // 商户分账单号,商户系统内唯一 + "\"receivers\":[{" + "\"type\":\"MERCHANT_ID\"," + "\"account\":\"" + receiverAccount + "\"," // 接收方商户号 + "\"amount\":" + amount + "," // 分账金额,单位:分 + "\"description\":\"订单" + transactionId + "分账给" + receiverAccount + "\"" + "}]," + "\"unfreeze_unsplit\":false" // false=不解冻剩余;true=完结分账 + "}";
HttpPost httpPost = new HttpPost(url); httpPost.addHeader("Accept", "application/json"); httpPost.addHeader("Content-Type", "application/json"); httpPost.addHeader("Wechatpay-Serial", "PUB_KEY_ID_xxx"); httpPost.setEntity(new StringEntity(reqdata, "utf-8"));
try (CloseableHttpResponse response = WxPayClient.getClient().execute(httpPost)) { int code = response.getStatusLine().getStatusCode(); String body = EntityUtils.toString(response.getEntity()); // 202 = 受理成功(不是最终分账结果!需后续查询) if (code == 200 || code == 202) { System.out.println("分账受理成功:" + body); return body; } else { throw new RuntimeException("分账失败:" + code + " " + body); } } } } |
7.6.7 查询分账结果
查询分账结果接口文档:https://pay.weixin.qq.com/doc/v3/partner/4012477734

▲ 查询分账结果对应流程图中『查询』环节(来源:4012062375)
|
import org.apache.http.client.methods.HttpGet;
public class QueryProfitSharing { /** * 查询分账结果 * 接口:GET /v3/profitsharing/orders/{out_order_no}?sub_mchid=xxx * 文档:https://pay.weixin.qq.com/doc/v3/partner/4012467002 */ public static String query(String subMchid, String outOrderNo) throws Exception { String url = "https://api.mch.weixin.qq.com/v3/profitsharing/orders/" + outOrderNo + "?sub_mchid=" + subMchid;
HttpGet httpGet = new HttpGet(url); httpGet.addHeader("Accept", "application/json");
try (CloseableHttpResponse response = WxPayClient.getClient().execute(httpGet)) { int code = response.getStatusLine().getStatusCode(); String body = EntityUtils.toString(response.getEntity()); if (code == 200) { // 解析 receivers[i].result 字段: // SUCCESS = 分账成功 // CLOSED = 已关闭(看 receivers[i].fail_reason) // PENDING = 处理中 System.out.println("查询分账结果:" + body); return body; } else { throw new RuntimeException("查询失败:" + code + " " + body); } } } } |
7.6.8 完结分账(解冻剩余资金)
完结分账接口文档:https://pay.weixin.qq.com/doc/v3/partner/4012477745

▲ 完结分账:剩余资金自动解冻给分账方(来源:4015870957)
|
public class FinishProfitSharing { /** * 完结分账 * 接口:POST /v3/profitsharing/orders/{out_order_no}/finish * 文档:https://pay.weixin.qq.com/doc/v3/partner/4012467016 * 用途:把剩余未分资金一次性解冻给分账方(子商户) */ public static String finish(String subMchid, String transactionId, String outOrderNo) throws Exception { String url = "https://api.mch.weixin.qq.com/v3/profitsharing/orders/" + outOrderNo + "/finish";
String reqdata = "{" + "\"sub_mchid\":\"" + subMchid + "\"," + "\"transaction_id\":\"" + transactionId + "\"," // 微信支付订单号 + "\"out_order_no\":\"" + outOrderNo + "\"," // 完结用的分账单号,不能与请求分账时相同 + "\"sub_appid\":\"wx8888888888888889\"" // 子商户 AppID(如有) + "}";
HttpPost httpPost = new HttpPost(url); httpPost.addHeader("Accept", "application/json"); httpPost.addHeader("Content-Type", "application/json"); httpPost.addHeader("Wechatpay-Serial", "PUB_KEY_ID_xxx"); httpPost.setEntity(new StringEntity(reqdata, "utf-8"));
try (CloseableHttpResponse response = WxPayClient.getClient().execute(httpPost)) { int code = response.getStatusLine().getStatusCode(); String body = EntityUtils.toString(response.getEntity()); if (code == 200 || code == 202) { System.out.println("完结分账受理成功:" + body); return body; } else { throw new RuntimeException("完结失败:" + code + " " + body); } } } } |
7.4.6 下单时传分账标识(关键步骤)
下单时必须在 settle_info 里传 profit_sharing=true,否则后续无法分账。示例(JSAPI 统一下单):
|
// 统一下单接口:POST /v3/pay/transactions/jsapi // 关键字段:settle_info.profit_sharing = true String reqdata = "{" + "\"sub_mchid\":\"1900000109\"," // 子商户号 + "\"appid\":\"wx8888888888888888\"," // 服务商 AppID + "\"sub_appid\":\"wx8888888888888889\"," // 子商户 AppID(如有) + "\"out_trade_no\":\"ORDER20260914001\"," + "\"description\":\"测试商品\"," + "\"amount\":{\"total\":1000,\"currency\":\"CNY\"}," // 1000 分 = 10 元 + "\"payer\":{\"openid\":\"oUpF8xxxxxx\"}," // 用户 openid(子商户 AppID 下的) + "\"settle_info\":{\"profit_sharing\":true}" // ★ 关键:分账标识 + "}"; |
|
❌ 重要:profit_sharing=true 必须在下单时传,已支付订单不能补传。如果忘了,该订单无法分账。 |
7.5 常见错误码速查
来源:https://pay.weixin.qq.com/doc/v3/merchant/4020807103
|
错误码 |
含义 |
排查步骤 |
|
271643173 |
超过分账限制的最大比例 |
子商户在商户平台 → 产品中心 → 授权的产品 → 分账授权 中提高比例,或减少本次分账金额。 |
|
271645722 |
无分账权限 |
1) 检查服务商是否开通分账;2) 检查子商户是否已授权;3) 检查请求参数是否用了普通商户文档(应该用服务商文档)。 |
|
271643175 |
不是分账订单 |
下单时未传 settle_info.profit_sharing=true,或 transaction_id 写错。 |
|
271643176 |
剩余可分金额为 0 |
1) 已全额退款;2) 已被解冻;3) 已分完。调用『查询订单剩余待分金额』接口确认。 |
|
271644678 |
分账关系非法 |
未先调用『添加分账接收方』建立关系,或商户接收方未『同意分账』。 |
|
271644831 |
订单未结算,交易投诉冻结 |
登录商户平台 → 交易中心/消费者投诉 2.0,处理投诉后等资金解冻。 |
|
268588428 |
分账单已完结 |
已经调过完结分账(unfreeze_unsplit=true),不能再次分账。 |
|
268588427 |
分账单已逾期解冻 |
超过 180 天冻结期,剩余资金已自动解冻给分账方,无法再分。 |
|
271644182 |
回退方没有开通分账回退功能 |
接收方商户登录商户平台 → 交易中心 → 分账 → 分账接收设置 → 开启『同意分账回退』。 |
|
271644737 |
微信用户没有实名 |
接收方是个人零钱时,用户未实名认证。请用户在微信 → 我 → 服务 → 右上角三点 → 实名认证。 |
7.6 完整工程实践(Spring Boot 项目结构)
本节给出一个可直接放进 Spring Boot 项目的完整分账对接方案,包含:
● Maven 依赖(pom.xml 片段)
● application.yml 配置参数
● WxPayConfig 配置类(自动初始化 HttpClient)
● WxPayUtil 工具类(V3 请求 + 签名 + 验签)
● ProfitSharingService 完整业务 Service(含所有分账接口)
● ProfitSharingController 回调接收 Controller(验签 + 解密 + 业务处理)
● SensitiveDataUtil 敏感字段加密(name 字段必须用微信支付公钥加密)
● 定时任务 QueryScheduler(异步查询分账最终结果)

▲ 完整工程实践对应业务时序图(来源:微信支付官方文档 4012062375)
7.6.1 Maven 依赖(pom.xml)
|
<!-- ============ 微信支付 APIv3 官方 SDK ============ --> <dependency> <groupId>com.github.wechatpay-apiv3</groupId> <artifactId>wechatpay-java</artifactId> <version>0.2.14</version> </dependency>
<!-- 兼容老版本 Apache HttpClient 风格(如果用 wechatpay-java 就不需要下面这个) --> <dependency> <groupId>com.github.wechatpay-apiv3</groupId> <artifactId>wechatpay-apache-httpclient</artifactId> <version>0.4.18</version> </dependency>
<!-- JSON 处理 --> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.10.1</version> </dependency>
<!-- Spring Boot Web(接收回调) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
<!-- Lombok(可选) --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> |
7.6.2 application.yml 配置
|
# ============ 微信支付服务商参数 ============ wxpay: # 服务商商户号 mch-id: "1900000108" # 服务商 AppID appid: "wx8888888888888888" # 商户 API 证书序列号(40 位十六进制) mch-serial: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # APIv3 密钥(32 位字符串,自己设置的) api-v3-key: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # 商户私钥文件路径(apiclient_key.pem) key-path: "C:/cert/apiclient_key.pem" # 微信支付公钥 ID(2025 年后新商户号用公钥模式) wechatpay-serial: "PUB_KEY_ID_xxxxxxxx" # 回调地址(必须 https,公网可访问) notify-url: "https://your-domain.com/api/wxpay/profit-sharing/notify"
# 子商户默认值(可被订单覆盖) sub: default-sub-mchid: "1900000109" default-sub-appid: "wx8888888888888889" |
|
ℹ️ 提示:代码使用 wechatpay-java 官方 SDK(推荐方式),底层自动处理签名、证书、平台证书自动更新。比手写 HttpClient 更安全、更省心。 |
7.6.3 WxPayConfig 配置类(自动初始化 SDK)
|
package com.example.wxpay.config;
import com.wechat.pay.java.core.Config; import com.wechat.pay.java.core.RSAAutoUpdateConfig; import com.wechat.pay.java.service.profitsharing.ProfitSharingService; import com.wechat.pay.java.service.profitsharing.ProfitSharingService.Builder; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
@Slf4j @Configuration public class WxPayConfig {
@Value("${wxpay.mch-id}") private String mchId; @Value("${wxpay.appid}") private String appid; @Value("${wxpay.mch-serial}") private String mchSerial; @Value("${wxpay.api-v3-key}") private String apiV3Key; @Value("${wxpay.key-path}") private String keyPath; @Value("${wxpay.wechatpay-serial}") private String wechatpaySerial;
/** * 自动更新微信支付平台证书的 Config * SDK 内部会定时下载并缓存平台证书,无需手动管理 */ @Bean public Config wxPayConfig() { log.info("初始化微信支付 Config,商户号={}, 证书序列号={}", mchId, mchSerial); return new RSAAutoUpdateConfig.Builder() .merchantId(mchId) .privateKeyFromPath(keyPath) .merchantSerialNumber(mchSerial) .apiV3Key(apiV3Key) .build(); }
/** * 分账 Service(官方 SDK 封装) */ @Bean public ProfitSharingService profitSharingService(Config wxPayConfig) { return new ProfitSharingService.Builder().config(wxPayConfig).build(); }
public String getMchId() { return mchId; } public String getAppid() { return appid; } public String getWechatpaySerial() { return wechatpaySerial; } } |
7.6.4 下单接口(必须传 profit_sharing=true)

▲ 下单传分账标识对应流程图中的『下单』环节(来源:4012062375)
下单使用服务商模式 JSAPI 统一下单:POST /v3/pay/partner/transactions/jsapi
|
❌ 重要:下单时必须传 settle_info.profit_sharing=true,否则后续无法分账。已支付订单不能补传。 |
|
package com.example.wxpay.service;
import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.wechat.pay.java.core.Config; import com.wechat.pay.java.service.payments.jsapi.JsapiService; import com.wechat.pay.java.service.payments.jsapi.model.*; import com.wechat.pay.java.service.payments.model.Payer; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service;
@Slf4j @Service public class PartnerPayService {
@Autowired private Config wxPayConfig; @Value("${wxpay.mch-id}") private String mchId; @Value("${wxpay.appid}") private String appid;
/** * 服务商模式 JSAPI 下单(带分账标识) * 接口:POST /v3/pay/partner/transactions/jsapi * 文档:https://pay.weixin.qq.com/doc/v3/partner/4012741851 */ public PrepayWithRequestJsapiResponse createOrderWithProfitSharing( String subMchid, String subAppid, String openid, String outTradeNo, String description, int totalAmount) {
JsapiService jsapiService = new JsapiService.Builder().config(wxPayConfig).build();
PrepayWithRequestJsapiRequest request = new PrepayWithRequestJsapiRequest(); request.setSubMchid(subMchid); request.setSubAppid(subAppid); request.setAppid(appid); request.setMchid(mchId); request.setDescription(description); request.setOutTradeNo(outTradeNo);
Amount amount = new Amount(); amount.setTotal(totalAmount); // 单位:分,1000=10 元 amount.setCurrency("CNY"); request.setAmount(amount);
Payer payer = new Payer(); payer.setSubOpenid(openid); // 子商户 AppID 下的 openid request.setPayer(payer);
// ★ 关键:分账标识,必须传 true SettleInfo settleInfo = new SettleInfo(); settleInfo.setProfitSharing(true); request.setSettleInfo(settleInfo);
log.info("下单参数:{}", new Gson().toJson(request)); return jsapiService.prepayWithRequestJsapi(request); } } |
7.6.5 添加分账接收方(含敏感字段加密)
添加接收方接口文档:https://pay.weixin.qq.com/doc/v3/partner/4012477758

▲ 添加接收方对应产品模型中『建立接收方列表』(来源:4015870957)
name 字段是个人姓名或商户全称,必须用微信支付公钥加密后传输。
|
package com.example.wxpay.service;
import com.wechat.pay.java.core.Config; import com.wechat.pay.java.service.profitsharing.ProfitSharingService; import com.wechat.pay.java.service.profitsharing.model.*; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service;
@Slf4j @Service public class ProfitSharingService {
@Autowired private ProfitSharingService profitSharingService; @Autowired private Config wxPayConfig; @Value("${wxpay.appid}") private String appid;
/** * 添加分账接收方 * 接口:POST /v3/profitsharing/receivers/add * 文档:https://pay.weixin.qq.com/doc/v3/partner/4012690944 */ public AddReceiverResponse addReceiver(String subMchid, String receiverType, String receiverAccount, String receiverName, String relationType) {
AddReceiverRequest request = new AddReceiverRequest(); request.setSubMchid(subMchid); request.setAppid(appid);
ReceiverDetail receiver = new ReceiverDetail(); receiver.setType(receiverType); // MERCHANT_ID / PERSONAL_OPENID / PERSONAL_SUB_OPENID receiver.setAccount(receiverAccount);
// ★ name 字段处理: // - MERCHANT_ID 类型必填商户全称(小微/个体户填开户人姓名) // - 个人类型选填(如填,必须用微信支付公钥加密,且校验实名一致) if (receiverName != null && !receiverName.isEmpty()) { // SDK 会自动用微信支付公钥加密敏感字段 receiver.setName(receiverName); } receiver.setRelationType(relationType); // PARTNER / DISTRIBUTOR / SUPPLIER / OTHERS 等
request.setReceivers(java.util.Collections.singletonList(receiver));
log.info("添加分账接收方:subMchid={}, account={}", subMchid, receiverAccount); return profitSharingService.addReceiver(request); }
/** * 删除分账接收方 * 接口:POST /v3/profitsharing/receivers/delete */ public DeleteReceiverResponse deleteReceiver(String subMchid, String receiverType, String receiverAccount) { DeleteReceiverRequest request = new DeleteReceiverRequest(); request.setSubMchid(subMchid); request.setAppid(appid);
ReceiverDetail receiver = new ReceiverDetail(); receiver.setType(receiverType); receiver.setAccount(receiverAccount); request.setReceivers(java.util.Collections.singletonList(receiver));
log.info("删除分账接收方:account={}", receiverAccount); return profitSharingService.deleteReceiver(request); } } |
7.6.6 请求分账(核心接口)
请求分账接口文档:https://pay.weixin.qq.com/doc/v3/partner/4012691594

▲ 分账产品模型图:请求分账是整个流程的核心(来源:4015870957)
|
/** * 请求分账 * 接口:POST /v3/profitsharing/orders * 文档:https://pay.weixin.qq.com/doc/v3/partner/4012692975 * * 关键规则: * 1. 分账金额单位是「分」,100=1 元 * 2. receivers.amount 总和 ≤ 订单金额 × 子商户设置的最大分账比例 * 3. 接口是异步受理,返回 order_id 不代表分账成功,需后续查询 * 4. 同一笔订单最多分账 50 次,每次最多 50 个接收方 * 5. unfreeze_unsplit=true 表示本次是最后一次分账并解冻剩余资金 */ public CreateOrderResponse createProfitSharing( String subMchid, String transactionId, String outOrderNo, List<Receiver> receivers, boolean unfreezeUnsplit) {
CreateOrderRequest request = new CreateOrderRequest(); request.setSubMchid(subMchid); request.setAppid(appid); request.setTransactionId(transactionId); // 微信支付订单号 request.setOutOrderNo(outOrderNo); // 商户分账单号,商户系统内唯一,6-64 位 request.setReceivers(receivers); request.setUnfreezeUnsplit(unfreezeUnsplit); // true=本次分账同时完结,false=不解冻
log.info("请求分账:outOrderNo={}, receivers={}", outOrderNo, receivers.size()); return profitSharingService.createOrder(request); }
/** * 构造分账接收方列表(示例:分给商户) */ public List<Receiver> buildReceivers(String receiverAccount, int amountFen, String desc) { Receiver r = new Receiver(); r.setType("MERCHANT_ID"); r.setAccount(receiverAccount); // 接收方商户号 r.setAmount(amountFen); // 分账金额,单位:分 r.setDescription(desc); // 分账描述,最多 80 字 r.setName("某某合作公司"); // 商户类型必填全称 return java.util.Collections.singletonList(r); }
/** * 构造分账给个人零钱的接收方 */ public List<Receiver> buildPersonalReceivers(String openid, int amountFen, String desc, String userName) { Receiver r = new Receiver(); r.setType("PERSONAL_OPENID"); // 或 PERSONAL_SUB_OPENID r.setAccount(openid); // 用户 openid r.setAmount(amountFen); r.setDescription(desc); // 个人类型 name 选填,填了会校验实名一致性 if (userName != null) r.setName(userName); return java.util.Collections.singletonList(r); } |
7.6.7 查询分账结果
|
/** * 查询分账结果 * 接口:GET /v3/profitsharing/orders/{out_order_no}?sub_mchid=xxx * 文档:https://pay.weixin.qq.com/doc/v3/partner/4012467002 * * receivers[i].result 取值: * SUCCESS = 分账成功 * CLOSED = 已关闭(看 receivers[i].fail_reason) * PENDING = 处理中 */ public QueryOrderResponse queryProfitSharing(String subMchid, String outOrderNo) { QueryOrderRequest request = new QueryOrderRequest(); request.setSubMchid(subMchid); request.setOutOrderNo(outOrderNo);
QueryOrderResponse response = profitSharingService.queryOrder(request); log.info("查询分账结果:outOrderNo={}, state={}", outOrderNo, response.getState());
// 遍历每个接收方的分账结果 if (response.getReceivers() != null) { for (ReceiverResult r : response.getReceivers()) { log.info("接收方 {} 分账结果:{},失败原因:{}", r.getAccount(), r.getResult(), r.getFailReason()); } } return response; }
/** * 查询订单剩余待分金额 * 接口:GET /v3/profitsharing/transactions/{transaction_id}/amounts?sub_mchid=xxx */ public QueryOrderAmountsResponse queryUnsplitAmount(String subMchid, String transactionId) { QueryOrderAmountsRequest request = new QueryOrderAmountsRequest(); request.setSubMchid(subMchid); request.setTransactionId(transactionId); return profitSharingService.queryOrderAmounts(request); } |
7.6.8 完结分账(解冻剩余资金)
|
/** * 完结分账 * 接口:POST /v3/profitsharing/orders/{out_order_no}/finish * 文档:https://pay.weixin.qq.com/doc/v3/partner/4012467016 * * 用途:把剩余未分资金一次性解冻给分账方(子商户) * 注意:out_order_no 必须与请求分账时的 out_order_no 不同! */ public FinishOrderResponse finishProfitSharing(String subMchid, String transactionId, String outOrderNo, String subAppid) { FinishOrderRequest request = new FinishOrderRequest(); request.setSubMchid(subMchid); request.setTransactionId(transactionId); request.setOutOrderNo(outOrderNo); // 完结用的单号,必须不同于请求分账的单号 if (subAppid != null) request.setSubAppid(subAppid);
log.info("完结分账:transactionId={}, outOrderNo={}", transactionId, outOrderNo); return profitSharingService.finishOrder(request); } |
7.6.9 请求分账回退(已分资金回退)
分账回退接口文档:https://pay.weixin.qq.com/doc/v3/partner/4012477747

▲ 分账回退:已分资金回退给分账方(来源:4015870957)
退款流程:先调用本接口把已分资金回退给分账方 → 再调用普通退款接口退款。
|
/** * 请求分账回退 * 接口:POST /v3/profitsharing/returns * 文档:https://pay.weixin.qq.com/doc/v3/partner/4012467097 * * 前置条件:接收方商户登录商户平台 → 交易中心 → 分账 → 分账接收设置 → 开启『同意分账回退』 * 否则报错 271644182 */ public ReturnResponse createReturn(String subMchid, String orderId, String outReturnNo, String outOrderNo, String receiverAccount, String receiverType, int returnAmount, String description) { CreateReturnRequest request = new CreateReturnRequest(); request.setSubMchid(subMchid); request.setOrderId(orderId); // 微信分账单号(请求分账返回的 order_id) request.setOutReturnNo(outReturnNo); // 商户回退单号,商户系统内唯一 request.setOutOrderNo(outOrderNo); // 原分账单号 request.setReturnAccountType(receiverType); // MERCHANT_ID request.setReturnAccount(receiverAccount); request.setReturnAmount(returnAmount); request.setDescription(description);
log.info("请求分账回退:outReturnNo={}, amount={}", outReturnNo, returnAmount); return profitSharingService.createReturn(request); }
/** * 查询分账回退结果 * 接口:GET /v3/profitsharing/returns/{out_return_no} * ?sub_mchid=xxx&out_order_no=xxx */ public QueryReturnResponse queryReturn(String subMchid, String outReturnNo, String outOrderNo) { QueryReturnRequest request = new QueryReturnRequest(); request.setSubMchid(subMchid); request.setOutReturnNo(outReturnNo); request.setOutOrderNo(outOrderNo); return profitSharingService.queryReturn(request); } |
7.6.10 回调 Controller(核心:验签 + 解密 + 业务处理)
分账动账通知官方文档:https://pay.weixin.qq.com/doc/v3/partner/4012467002

▲ 回调通知在流程图中的位置:分账成功后异步通知商户(来源:4012062375)
微信支付在分账/回退成功后会主动 POST 通知商户,需要:
● 1) 验签(确认请求来自微信支付,防伪造)
● 2) 解密 resource.ciphertext(AES-256-GCM 解密,密钥是 APIv3 密钥)
● 3) 业务处理(更新订单状态)
● 4) 返回 200 + {code: SUCCESS},否则微信会重试
|
package com.example.wxpay.controller;
import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.wechat.pay.java.core.notification.NotificationParser; import com.wechat.pay.java.service.profitsharing.model.*; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*;
@Slf4j @RestController @RequestMapping("/api/wxpay/profit-sharing") public class ProfitSharingController {
@Autowired private NotificationParser notificationParser; @Autowired private OrderService orderService;
/** * 分账动账通知回调 * 路径需与下单时 notify_url 一致(https://your-domain.com/api/wxpay/profit-sharing/notify) * 文档:https://pay.weixin.qq.com/doc/v3/partner/4012075400 * * SDK 自动完成: * - 验签(用微信支付平台证书) * - 解密(AES-256-GCM,密钥=APIv3 密钥) * - 反序列化为 ProfitSharingNotifySource 对象 */ @PostMapping("/notify") public String profitSharingNotify(@RequestBody String body, @RequestHeader("Wechatpay-Timestamp") String timestamp, @RequestHeader("Wechatpay-Nonce") String nonce, @RequestHeader("Wechatpay-Signature") String signature, @RequestHeader("Wechatpay-Serial") String serial) { log.info("收到分账回调:serial={}", serial);
try { // 构造 RequestParam com.wechat.pay.java.core.notification.RequestParam requestParam = new com.wechat.pay.java.core.notification.RequestParam.Builder() .serialNumber(serial) .nonce(nonce) .timestamp(timestamp) .signature(signature) .body(body) .build();
// SDK 自动验签 + 解密,得到通知内容 ProfitSharingNotifySource notify = notificationParser.parse(requestParam, ProfitSharingNotifySource.class);
log.info("分账回调解析成功:outOrderNo={}, state={}", notify.getOutOrderNo(), notify.getState());
// ===== 业务处理 ===== // notify.getState():FINISHED / PROCESSING // notify.getReceivers():每个接收方的最终结果 for (ReceiverResult r : notify.getReceivers()) { if ("SUCCESS".equals(r.getResult())) { // 分账成功:更新订单状态、给接收方加余额、触发下游业务 orderService.markReceiverSuccess( notify.getOutOrderNo(), r.getAccount(), r.getAmount()); } else if ("CLOSED".equals(r.getResult())) { // 分账失败:记录失败原因、通知运营处理 log.error("分账失败:account={}, reason={}", r.getAccount(), r.getFailReason()); orderService.markReceiverFailed( notify.getOutOrderNo(), r.getAccount(), r.getFailReason()); } }
// 必须返回 SUCCESS,否则微信会重试 8 次 return "{\"code\": \"SUCCESS\", \"message\": \"成功\"}";
} catch (Exception e) { log.error("分账回调处理失败", e); // 返回失败,微信会重试 return "{\"code\": \"FAIL\", \"message\": \"" + e.getMessage() + "\"}"; } } } |
|
⚠️ 注意:回调必须返回 200 + {"code":"SUCCESS"}。否则微信会按 15s/15s/30s/3m/10m/20m/30m/30m/30m/60m 节奏重试 8 次。 |
7.6.11 NotificationParser Bean 配置
在 WxPayConfig 里追加:
|
@Bean public NotificationParser notificationParser(Config wxPayConfig) { // SDK 自动用 APIv3 密钥解密 + 用平台证书验签 return new NotificationParser(wxPayConfig); } |
7.6.12 定时任务:异步查询分账结果(兜底)
回调可能丢失,所以定时任务定期主动查询未完成的分账单:
|
package com.example.wxpay.scheduler;
import com.example.wxpay.service.ProfitSharingService; import com.example.wxpay.entity.ProfitSharingOrder; import com.example.wxpay.repository.ProfitSharingOrderRepository; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component;
import java.time.LocalDateTime; import java.util.List;
@Slf4j @Component public class ProfitSharingQueryScheduler {
@Autowired private ProfitSharingService profitSharingService; @Autowired private ProfitSharingOrderRepository orderRepository;
/** * 每 5 分钟查询一次状态为 PENDING 的分账单 * 兜底回调丢失的情况 */ @Scheduled(fixedRate = 5 * 60 * 1000) public void queryPendingProfitSharing() { LocalDateTime deadline = LocalDateTime.now().minusMinutes(10); // 只查 10 分钟前发起的 List<ProfitSharingOrder> pendingOrders = orderRepository.findByStateAndUpdateTimeBefore("PENDING", deadline);
log.info("定时查询分账结果,待查单数:{}", pendingOrders.size());
for (ProfitSharingOrder order : pendingOrders) { try { QueryOrderResponse response = profitSharingService.queryProfitSharing( order.getSubMchid(), order.getOutOrderNo());
// 更新订单状态 order.setState(response.getState()); if (response.getReceivers() != null) { for (ReceiverResult r : response.getReceivers()) { order.setReceiverResult(r.getAccount(), r.getResult(), r.getFailReason()); } } orderRepository.save(order);
log.info("定时查询完成:outOrderNo={}, state={}", order.getOutOrderNo(), response.getState());
} catch (Exception e) { log.error("查询分账结果失败:outOrderNo={}", order.getOutOrderNo(), e); } } } } |
7.6.13 完整业务调用示例

▲ 完整业务调用对应的全流程时序图(来源:4012062375)
一个完整的分账流程调用示例(用户支付成功后自动分账):
|
package com.example.wxpay.service;
import com.example.wxpay.entity.Order; import com.example.wxpay.repository.OrderRepository; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;
@Slf4j @Service public class ProfitSharingFacadeService {
@Autowired private ProfitSharingService profitSharingService; @Autowired private OrderRepository orderRepository;
/** * 完整分账流程(订单支付成功后调用) */ public void doProfitSharing(String outTradeNo) { // 1. 查订单信息 Order order = orderRepository.findByOutTradeNo(outTradeNo); if (order == null) throw new RuntimeException("订单不存在");
// 2. 查询订单剩余可分金额(重要!避免超额分账报错) QueryOrderAmountsResponse amounts = profitSharingService.queryUnsplitAmount( order.getSubMchid(), order.getTransactionId()); int unsplitAmount = amounts.getUnsplitAmount();
if (unsplitAmount <= 0) { log.warn("订单无可分金额:{}", outTradeNo); return; }
// 3. 计算本次分账金额 // 例:订单总额 100 元,服务商抽 10% = 10 元 = 1000 分 int profitAmount = order.getTotalAmount() / 10; // 服务商分 10% // 检查不超过剩余可分金额 if (profitAmount > unsplitAmount) { profitAmount = unsplitAmount; }
// 4. 构造分账接收方(分给服务商自己的商户号) List<Receiver> receivers = profitSharingService.buildReceivers( "1900000110", // 接收方商户号(服务商自己) profitAmount, // 分账金额(分) "订单" + outTradeNo + "分给服务商" // 描述 );
// 5. 请求分账 String outOrderNo = "PS" + System.currentTimeMillis(); CreateOrderResponse response = profitSharingService.createProfitSharing( order.getSubMchid(), order.getTransactionId(), outOrderNo, receivers, false // false=不解冻剩余,让子商户拿到大头;true=本次即完结 );
log.info("分账受理成功:orderId={}, outOrderNo={}", response.getOrderId(), outOrderNo);
// 6. 保存分账单到数据库(等回调或定时任务更新结果) orderRepository.saveProfitSharingOrder( outOrderNo, order.getTransactionId(), order.getSubMchid(), profitAmount, "PENDING");
// 注:剩余资金(订单金额-分账金额)默认自动解冻给子商户 // 如需主动解冻可调用 finishProfitSharing,但只有『最后一笔分账』才需要传 unfreeze_unsplit=true }
/** * 退款流程:先回退分账,再退款 */ public void refundWithProfitSharing(String outTradeNo, int refundAmount) { Order order = orderRepository.findByOutTradeNo(outTradeNo);
// 1. 先调用分账回退接口,把已分给服务商的资金回退给子商户 String outReturnNo = "RT" + System.currentTimeMillis(); profitSharingService.createReturn( order.getSubMchid(), order.getProfitSharingOrderId(), // 微信分账单号 outReturnNo, order.getOutOrderNo(), // 原分账单号 "1900000110", // 回退给谁(原分账接收方) "MERCHANT_ID", refundAmount, "退款回退分账资金" );
// 2. 等回退成功(可监听回调或定时查询)后,再调用普通退款接口 // ... 此处省略退款接口调用 } } |
7.6.14 敏感字段手动加密(如不用 SDK)
如果直接用 HttpClient 不用官方 SDK,name 字段必须手动用微信支付公钥 RSA-OAEP 加密:
|
import javax.crypto.Cipher; import javax.crypto.spec.OAEPParameterSpec; import javax.crypto.spec.PSource; import java.security.KeyFactory; import java.security.PublicKey; import java.security.spec.X509EncodedKeySpec; import java.util.Base64;
public class SensitiveDataUtil {
/** * 用微信支付公钥加密敏感字段 * 算法:RSA/ECB/OAEPWithSHA-1AndMGF1Padding */ public static String encrypt(String plaintext, String publicKeyBase64) throws Exception { byte[] keyBytes = Base64.getDecoder().decode(publicKeyBase64); X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes); KeyFactory kf = KeyFactory.getInstance("RSA"); PublicKey pubKey = kf.generatePublic(spec);
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding"); OAEPParameterSpec oaepParams = new OAEPParameterSpec( "SHA-1", "MGF1", java.security.spec.MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT ); cipher.init(Cipher.ENCRYPT_MODE, pubKey, oaepParams); byte[] encrypted = cipher.doFinal(plaintext.getBytes("UTF-8")); return Base64.getEncoder().encodeToString(encrypted); } }
// 调用示例: String encryptedName = SensitiveDataUtil.encrypt("某某公司", wxPayPublicKeyBase64); // 然后传给接口的 receivers[i].name 字段 |
7.6.15 项目目录结构建议

▲ 项目结构对应分账产品模型(来源:4015870957)
|
src/main/java/com/example/wxpay/ ├── config/ │ └── WxPayConfig.java # SDK 配置 + Bean 注入 ├── controller/ │ ├── PartnerPayController.java # 下单 + 支付回调 │ └── ProfitSharingController.java # 分账回调(验签+解密+业务) ├── service/ │ ├── PartnerPayService.java # 下单(含 profit_sharing=true) │ ├── ProfitSharingService.java # 分账接口封装 │ │ ├── addReceiver() │ │ ├── deleteReceiver() │ │ ├── createProfitSharing() │ │ ├── queryProfitSharing() │ │ ├── finishProfitSharing() │ │ ├── createReturn() # 分账回退 │ │ └── queryReturn() │ ├── ProfitSharingFacadeService.java # 业务编排(完整流程) │ └── OrderService.java # 订单状态管理 ├── scheduler/ │ └── ProfitSharingQueryScheduler.java # 定时查询兜底 ├── entity/ │ ├── Order.java │ └── ProfitSharingOrder.java ├── repository/ │ ├── OrderRepository.java │ └── ProfitSharingOrderRepository.java └── util/ └── SensitiveDataUtil.java # 敏感字段加密
src/main/resources/ ├── application.yml # 微信支付参数 └── cert/ └── apiclient_key.pem # 商户私钥文件(保密) |
7.6.16 测试用例(小额跑通)

▲ 测试用例覆盖的完整流程(来源:4012062375)
上线前用 1 元跑通一笔分账:
|
// 1. 下单(带分账标识) PrepayWithRequestJsapiResponse resp = partnerPayService.createOrderWithProfitSharing( "1900000109", // 子商户号 "wx8888888888888889", // 子商户 AppID "oUpF8xxxxxx", // 用户 openid "TEST" + System.currentTimeMillis(), // 商户订单号 "测试商品", 100 // 100 分 = 1 元 ); String transactionId = ... // 等支付成功回调获取
// 2. 查询可分金额 QueryOrderAmountsResponse amounts = profitSharingService.queryUnsplitAmount("1900000109", transactionId); // 应返回 unsplitAmount ≈ 100(扣手续费后约 99)
// 3. 添加接收方(一次性,已添加可跳过) profitSharingService.addReceiver( "1900000109", "MERCHANT_ID", "1900000110", // 接收方商户号(服务商自己) "某某公司", "PARTNER" );
// 4. 请求分账(分 10 分 = 0.1 元 给服务商) List<Receiver> receivers = profitSharingService.buildReceivers( "1900000110", 10, "测试分账" ); CreateOrderResponse resp = profitSharingService.createProfitSharing( "1900000109", transactionId, "PS" + System.currentTimeMillis(), receivers, false ); // 返回 orderId,state=ACCEPTED(已受理)
// 5. 查询分账结果(约 1 分钟后变 SUCCESS) Thread.sleep(60 * 1000); QueryOrderResponse query = profitSharingService.queryProfitSharing( "1900000109", outOrderNo ); // query.getReceivers()[0].getResult() = "SUCCESS"
// 6. 完结分账(剩余 89 分解冻给子商户) profitSharingService.finishProfitSharing( "1900000109", transactionId, "FIN" + System.currentTimeMillis(), "wx8888888888888889" ); |
|
ℹ️ 提示:测试建议金额 1 元(100 分),避免大额分账出错。先跑通单接口,再跑通完整流程。最后接入回调处理。 |
第八部分 验收清单与官方资源
8.1 上线前检查清单(非技术人员对照打勾)
请逐项打勾,全部完成才可上线:

▲ 完整流程回顾图(来源:微信支付官方文档 4012062375)
|
已做 |
检查项 |
|
□ |
已注册企业服务号且通过微信认证 |
|
□ |
已申请成为微信支付服务商,获得服务商商户号 |
|
□ |
服务商平台 → 产品中心 → 特约商户授权产品 → 服务商分账 已开通 |
|
□ |
已发起分账授权邀请给每个子商户 |
|
□ |
每个子商户已在商户平台 → 产品中心 → 我授权的产品 中确认授权 |
|
□ |
所有子商户已完成进件(含打款验证) |
|
□ |
子商户已关联小程序/公众号 AppID(如使用) |
|
□ |
已通过接口或商户平台添加了分账接收方 |
|
□ |
子商户已在商户平台 → 产品中心 → 授权的产品 → 分账授权 设置最大分账比例 |
|
□ |
服务商平台 → 账户中心 → API 安全 已下载 API 证书、设置 APIv3 密钥 |
|
□ |
已记录服务商商户号、AppID、证书序列号、子商户号等开发参数 |
|
□ |
代码已实现:下单传 profit_sharing=true |
|
□ |
代码已实现:请求分账、查询分账结果、完结分账 |
|
□ |
已用小额(如 1 元)跑通一笔分账测试 |
|
□ |
分账动账通知回调地址(notify_url)已配置并能正确接收 |
8.2 关键客服与咨询渠道

▲ 全流程回顾:从服务商申请到分账完成(来源:4012062375)
|
渠道 |
联系方式 / 网址 |
用途 |
|
微信支付客服 |
95017 |
提高分账比例申请、其他业务咨询 |
|
服务商 BD 邮箱 |
weixinpayBD@tencent.com |
大客户合作 |
|
官方文档总站 |
https://pay.weixin.qq.com/ |
所有产品文档入口 |
|
服务商平台 |
https://pay.weixin.qq.com/index.php/partner/public/home |
服务商登录与操作 |
|
商户平台 |
https://pay.weixin.qq.com/ |
子商户登录与操作 |
|
公众平台 |
https://mp.weixin.qq.com/ |
服务号、小程序后台 |
注:全部官方文档链接
本文档所有截图、步骤、参数均来自以下官方文档页面:
● 开发接入准备:https://pay.weixin.qq.com/doc/v3/partner/4012072589
● 对接步骤(V2):https://pay.weixin.qq.com/doc/v2/partner/4011984375
● 开发指引(连锁品牌):https://pay.weixin.qq.com/doc/v3/partner/4012072637
● 添加分账接收方接口:https://pay.weixin.qq.com/doc/v3/partner/4012690944
● 请求分账接口:https://pay.weixin.qq.com/doc/v3/partner/4012692975
● 查询分账结果接口:https://pay.weixin.qq.com/doc/v3/partner/4012467002
● 完结分账接口:https://pay.weixin.qq.com/doc/v3/partner/4012467016
● 查询订单剩余待分金额:https://pay.weixin.qq.com/doc/v3/partner/4012457927
● 分账动账通知:https://pay.weixin.qq.com/doc/v3/partner/4012075400
● 分账失败处理指引:https://pay.weixin.qq.com/doc/v3/partner/4015504918
● 分账常见问题:https://pay.weixin.qq.com/doc/v3/partner/4014547107
● 分账错误码:https://pay.weixin.qq.com/doc/v3/merchant/4020807103
● 业务示例代码:https://pay.weixin.qq.com/doc/v3/partner/4015870957
● 商家注册小程序指引:https://pay.weixin.qq.com/static/help_guide/business_registration.shtml
● 微信支付服务商接入指引 PDF:https://gtimg.wechatpay.cn/resource/xres/mmpaydoc/static/attachment/d7ed63166bac0051d3b2c13ea0fc36dc/服务商接入指引-大交通中心(2020新版).pdf
● 服务商申请入口:https://pay.weixin.qq.com/index.php/partner/public/home
● 公众平台:https://mp.weixin.qq.com/
● 微信支付商户平台:https://pay.weixin.qq.com/

浙公网安备 33010602011771号