一、钱到了,怎么分?这是平台绕不开的坎
做源码交易、转卡码平台的开发者都有一个共同的痛点:收款容易,分钱难。业务稍微跑起来,资金就会牵扯三方甚至四方——买家付款给平台,货款里有一部分要分给上游作者、下级代理或者渠道商。最原始的做法是人工记账、定期手动转账,但单量一上来,对不上账、转错人、拖账扯皮的问题全来了。
微信支付的分账能力(Profit Sharing)就是为这个场景设计的:一笔订单支付成功后,平台按规则把资金实时分给多个接收方,货款与分润在支付通道层面就自动清分,账目透明、可查可对。今天这篇文章不讲怎么接入收款(那是前几篇的主题),专门讲清楚三件事:分账怎么配、退款怎么回退、风控怎么扛。
二、先选模式:普通商户分账还是服务商分账
微信分账有两种玩法,选择直接决定你的整体架构:
- 普通商户分账:一个商户号收款,分账给个人或其他商户接收方。适合单商户 + 少量代理的轻量场景,单笔订单可分出的比例有限制(以官方最新规则为准),胜在开通简单。
- 服务商分账:平台作为服务商,下面挂多个特约商户(子商户)。买家付款走子商户,服务商在订单维度发起分账,把资金分给服务商自己、其他子商户或商户个人。这是多商户 SaaS 平台的标配,转卡码系统 V3 的多商户模式就是按这个思路设计的。
判断标准很简单:未来会不会出现第二个收款主体。会,就直接上服务商模式,别等商户号铺开了再迁移,迁移的代价远高于提前规划。
三、分账 API 实战:Python 请求一次真实分账
先准备分账专用的商户配置。普通商户需要开通分账功能并设置分账比例上限;服务商则需要先把特约商户添加进分账关系。下面是添加分账接收方的接口:
# 添加分账接收方 POST /v3/profitsharing/receivers/add
payload = {
"appid": APPID, # 服务商 appid
"type": "MERCHANT_ID", # 接收方类型:商户号
"account": "1900000002", # 代理/子商户的商户号
"relation_type": "SERVICE_PROVIDER",
"name": "某某代理" # 首次添加需传名称,用于校验
}
添加成功后,订单支付完成即可发起分账。完整请求要带上 V3 签名(RSA-SHA256):
import json, time, uuid, base64, requests
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
def wx_sign(method, url, body):
ts = str(int(time.time()))
nonce = uuid.uuid4().hex
message = f"{method}\n{url}\n{ts}\n{nonce}\n{body}\n"
with open("merchant_private_key.pem", "rb") as f:
key = serialization.load_pem_private_key(f.read(), password=None)
sig = base64.b64encode(
key.sign(message.encode(), padding.PKCS1v15())).decode()
return ts, nonce, sig
# 请求分账 POST /v3/profitsharing/orders
url = "/v3/profitsharing/orders"
body = json.dumps({
"appid": APPID,
"transaction_id": "4200001234202408190000000000",
"out_order_no": f"SPLIT20260819001",
"receivers": [{
"type": "MERCHANT_ID",
"account": "1900000002",
"amount": 100, # 分给代理 100 分(1 元)
"description": "代理分润"
}],
"unfreeze_unsplit": True # 剩余资金解冻给收款商户
}, ensure_ascii=False)
ts, nonce, sig = wx_sign("POST", url, body)
resp = requests.post("https://api.mch.weixin.qq.com" + url,
data=body, headers={
"Authorization": (f'WECHATPAY2-SHA256-RSA2048 mchid="{MCHID}",'
f'nonce_str="{nonce}",signature="{sig}",'
f'timestamp="{ts}",serial_no="{SERIAL_NO}"'),
"Content-Type": "application/json",
"Accept": "application/json",
})
# 返回 200 且 state=FINISHED 即分账成功
注意三个细节:分账金额单位是分;unfreeze_unsplit 决定未分资金是否自动解冻给收款方;同一订单的多次追加分账复用同一个 out_order_no 即可实现幂等。分账后随时可用 GET /v3/profitsharing/orders/{out_order_no} 查询分账状态,这也是对账脚本的数据来源。
四、退款前的必修课:先分账回退,再退款
分账最容易被忽略的坑在这里:订单退款时,如果资金已经被分出去了,直接调退款接口会报错(订单已分账,无法直接退款)。正确的处理顺序是:
- 调用分账回退接口,把已分给接收方的钱退回;
- 回退完成后,再发起订单退款;
- 退款成功后,再把卡密库存回补、订单状态机流转到已关闭。
# 分账回退 POST /v3/profitsharing/return-orders
url = "/v3/profitsharing/return-orders"
body = json.dumps({
"out_return_no": f"RETURN20260819001",
"return_mchid": "1900000002", # 原分账接收方商户号
"amount": 100, # 回退金额不能超过已分金额
"description": "订单退款,回退分账"
})
# 回退成功后再调用退款接口(out_refund_no 保证幂等)
url = "/v3/refund/domestic/refunds"
body = json.dumps({
"out_trade_no": "ORDER20260819001",
"out_refund_no": f"REFUND20260819001",
"amount": {"refund": 1000, "total": 1000, "currency": "CNY"}
})
退款和回退都有幂等键(out_refund_no / out_return_no),重试时务必复用同一个单号,否则会生成多笔退款。整套时序建议用状态机串起来,之前订单状态机文章里的 REFUNDING 状态,在这里就对应"回退中 → 退款中 → 已关闭"三步。
五、商户风控与投诉处理:虚拟商品的重灾区
虚拟商品交易是微信风控的重点观察对象,源码、卡密这类"无物流"订单尤其容易触发拦截。常见信号包括:短时间大量同金额订单、收款码被恶意投诉、退款率和投诉率飙升、交易地域与商品属性不匹配。被风控的典型后果是延迟结算、交易拦截甚至限制收款,处理成本远高于预防成本。
实操建议:
- 投诉要"秒回":微信支付提供商户投诉 API(
GET /v3/merchant-service/complaints-v2拉取投诉列表),建议接入系统自动提醒,在官方要求的时效内(通常为 3 个自然日)完成处理,超时未处理会直接拉高风控等级。 - 异常订单先人工复核再发货:风控引擎判定可疑的订单,卡密先不自动发,转人工确认,宁可慢一点也不要被批量退款。
- 控制投诉率:商品描述写清楚"虚拟商品,售出不退",发货前做好卡密校验,大部分投诉其实来自"发错货"和"描述不符"。
- 分散收款主体:多商户、多入口轮换收款,避免单一商户号交易量过猛,智能入口池那篇文章讲过具体做法。
一句话总结:风控的命门是投诉率和异常交易模式。把投诉处理自动化、把发货校验前置,比出事后再申诉靠谱一百倍。
六、对账兜底:分账账单每日核对
再稳的系统也要对账兜底。微信提供分账账单接口(GET /v3/profitsharing/bills),可下载指定日期的分账明细;配合资金账单与每日订单流水,三方对账就能覆盖"订单数、收款额、分账额、退款额"四个维度。对不上账要第一时间报警,而不是月底才发现。
七、结语
分账是支付体系的"下半场":接入收款只是开始,把钱分对、把退款回退、把风控扛住,平台才算真正稳了。如果你正在做源码交易或转卡码业务,不想从零趟这些坑,源码商城的转卡码系统 V3 已经内置了多商户分账、代理分润与微信/支付宝双通道对接,开箱即用;开发分账对接时搭配 Codex Desktop 这类 AI 编程助手,写签名、调接口的速度能快上一大截。欢迎到源码商城看看: