Jeepay 分账接口实战指南:绑定分账用户与发起订单分账(基于 jeepay-payment 源码解析)
2026/9/17 12:02:16 网站建设 项目流程

Jeepay 分账接口实战指南:绑定分账用户与发起订单分账(基于 jeepay-payment 源码解析)

【免费下载链接】jeepayJeepay是一套适合互联网企业使用的开源支付系统,支持多渠道服务商和普通商户模式。已对接微信支付,支付宝,云闪付官方接口,支持聚合码支付。项目地址: https://gitcode.com/GitHub_Trending/je/jeepay

本文以 Jeepay 支付系统分账接口文档(jeepay-payment/src/main/resources/markdown/doc/api5.md)为核心,系统讲解商户分账业务的两个核心 API——绑定分账用户/api/division/receiver/bind)与发起订单分账/api/division/exec)的完整参数、请求/返回示例与调用前提,并结合jeepay-payment模块的控制器、请求体与渠道适配源码,深入剖析分账从请求校验、接收者匹配、金额计算到渠道侧调用的完整链路。读完本文,你将能够独立对接 Jeepay 分账接口,理解"按账号分账""按组自动分账""商户手动分账"三种模式的区别,并掌握分账失败时的补单与排查思路。

一、分账业务概述

分账(Profit Sharing / Royalty)是支付系统中面向多角色资金分配的核心能力。商户将交易成功的资金,按照一定的周期或比例,分账给其他方——可以是合作伙伴、员工、用户或者其他分润方。

在 Jeepay 中,分账能力由支付网关模块(jeepay-payment)统一对外提供,其接口目录位于 jeepay-payment/src/main/resources/markdown/doc/api5.md,包含两个公开接口:

接口请求 URL作用
绑定分账用户POST /api/division/receiver/bind将分账接收者(账号)绑定到某个分账账号组,绑定成功后才能参与订单分账
发起订单分账POST /api/division/exec对一笔已支付成功且处于"商户手动分账"模式的订单执行分账

两个接口的适用对象均为:普通商户特约商户,即既支持普通商户直连模式,也支持服务商模式下的特约商户(ISV 子商户)调用。

说明:微信、支付宝官方对分账能力均有独立的产品定义与开通要求(微信"分账"、支付宝"分账")。Jeepay 侧只是将这些渠道能力统一封装为上述两个接口,实际能否分账还取决于商户在渠道侧是否已开通对应分账权限(下文源码中NOAUTH 无分账权限的返回即与此相关)。

二、接口通用约定

两个接口具备相同的通用规范,调用前需先了解:

  • 请求方式POST
  • 请求类型application/jsonapplication/x-www-form-urlencoded
  • 公共必传参数(由 AbstractMchAppRQ.java 定义并强制校验):
参数说明
mchNo商户号(30 位以内字符串)
appId商户应用 ID(24 位字符串)
reqTime请求接口时间,13 位毫秒时间戳
version接口版本号,固定1.0
signType签名类型,目前仅支持MD5
sign签名值(32 位字符串),详见签名算法
  • 返回结构(统一返回体,由 ApiRes.java 定义):
字段类型说明
codeint返回状态,0表示处理成功,其他表示处理有误(详见错误码)
msgString具体错误原因,如"签名失败""参数格式校验错误"
signStringdata内数据签名(data为空时不返回)
dataString返回业务数据,JSON 格式

三、接口一:绑定分账用户(/api/division/receiver/bind)

分账接收者必须先绑定后分账。该接口用于把某个分账接收账号(个人或商户)绑定到指定分账账号组,绑定结果由上游渠道确认,Jeepay 侧保存绑定记录。

请求 URL:https://pay.jeepay.vip/api/division/receiver/bind(按实际部署域名替换)

3.1 请求参数

字段名变量名必填类型示例值描述
商户号mchNoString(30)M1621873433953商户号
应用IDappIdString(24)60cc09bce4b0f1c0b83761c9应用ID
接口代码ifCodeString(10)wxpaywxpay-微信官方接口 ; alipay-支付宝官方接口
接收者账号别名receiverAliasString(64)张三接收者账号别名
组IDreceiverGroupIdlong10001需先登录商户系统查找待加入的组ID
分账接收账号类型accTypeint1分账接收账号类型: 0-个人(对私) 1-商户(对公)
分账接收账号accNoString(10)1231312@qq.com分账接收账号,微信个人是openid,支付宝可以是userId或登录名
分账接收账号名称accNameString(30)张三微信选填(当填入则验证),支付宝账号必填
分账关系类型relationTypeString(30)PARTNER分账关系类型,见下方枚举说明
分账关系类型名称relationTypeNameString(30)我的员工当 relationType=CUSTOM 时必填
渠道特殊信息channelExtInfoString(256)-渠道特殊信息
默认分账比例divisionProfitString(10)0.3若分账30%则填入 0.3
请求时间reqTimelong1622016572190请求接口时间,13位时间戳
接口版本versionString(3)1.0接口版本号,固定:1.0
签名signString(32)C380BEC2BFD727A4B6845133519F3AD6签名值,详见签名算法
签名类型signTypeString(32)MD5签名类型,目前只支持MD5方式

分账关系类型(relationType)枚举(对齐微信分账关系定义):

SERVICE_PROVIDER:服务商 STORE:门店 STAFF:员工 STORE_OWNER:店主 PARTNER:合作伙伴 HEADQUARTER:总部 BRAND:品牌方 DISTRIBUTOR:分销商 USER:用户 SUPPLIER:供应商 CUSTOM:自定义

relationType=CUSTOM(自定义)时,relationTypeName必填。其余情况下,MchDivisionReceiverBindController.java 中的getRelationTypeName方法会将枚举自动映射为中文名称(如PARTNER→ "合作伙伴"),仅在映射不到时才取请求中的relationTypeName

3.2 请求示例数据

{ 'version': '1.0', 'reqTime': '1622016572190', 'signType': 'MD5', 'sign': 'MD5MD5MD5MD5MD5MD5MD5MD5MD5MD5MD5MD5', 'mchNo': 'M1623997000', 'appId': '60cc3ba74ee0e6685f57e000', 'ifCode': 'wxpay', 'receiverAlias': '我的第一个账号', 'receiverGroupId': '100001', 'accType': '0', 'accNo': 'sfsfsd@qq.com', 'accName': '张三', 'relationType': 'OTHERS', 'relationTypeName': '我的员工', 'divisionProfit': '0.3' }

3.3 返回参数

字段名变量名必填类型示例值描述
返回状态codeint00-处理成功,其他-处理有误,详见错误码
返回信息msgString(128)签名失败具体错误原因
签名信息signString(32)CCD9083A6DAD9A2DA9F668C3D4517A84对data内数据签名
返回数据dataString(512){}返回绑定数据,json格式

data 数据格式:

字段名变量名必填类型示例值描述
绑定账号IDreceiverIdlong10001绑定账号ID,订单分账将使用该ID
接收者账号别名receiverAliasString(64)张三接收者账号别名
组IDreceiverGroupIdlong10001组ID
分账接收账号类型accTypeint1分账接收账号类型: 0-个人(对私) 1-商户(对公)
分账接收账号accNoString(10)1231312@qq.com分账接收账号
分账接收账号名称accNameString(30)张三分账接收账号名称
分账关系类型relationTypeString(30)PARTNER分账关系类型
渠道特殊信息channelExtInfoString(256)-渠道特殊信息
默认分账比例divisionProfitString(10)0.3默认分账比例
绑定成功时间bindSuccessTimeLong1622016572190绑定成功时间(毫秒时间戳)
绑定状态bindStateint1绑定状态 1-绑定成功,0-绑定异常
渠道错误码errCodeStringACQ.PAYMENT_AUTH_CODE_INVALID上游渠道返回的错误码
渠道错误描述errMsgStringBusiness Failed 失败上游渠道返回的错误描述

返回示例数据:

{ "code": 0, "data": { "accName": "张三", "accNo": "sfsfsd@qq.com", "accType": 0, "appId": "60cc3ba74ee0e6685f57eb1e", "bindState": 0, "divisionProfit": 0.3, "errCode": "NOAUTH", "errMsg": "无分账权限", "ifCode": "wxpay", "mchNo": "M1623997351", "receiverAlias": "我的第一个账号", "receiverGroupId": 100001, "relationType": "OTHERS", "relationTypeName": "我的员工" }, "msg": "SUCCESS", "sign": "552CB91FA1E1DB378A534B377E4E9403" }

注意:上例中code=0仅表示 Jeepay 侧请求处理成功,但data.bindState=0errCode=NOAUTHerrMsg=无分账权限说明渠道侧绑定失败——即商户尚未在微信侧开通分账权限。这是绑定接口最典型的"业务失败"形态,调用方务必同时校验codebindState

3.4 源码解析:绑定流程

绑定接口由 MchDivisionReceiverBindController.java 实现,核心流程如下:

  1. 验签与参数解析:调用getRQByWithMchSign(DivisionReceiverBindRQ.class)完成签名校验与参数绑定,请求体定义见 DivisionReceiverBindRQ.java。其中accType通过@Range(min=0, max=1)限制,ifCodereceiverGroupIdaccNorelationTypedivisionProfit均强制非空。
  2. 商户应用校验:通过configContextQueryService.queryMchInfoAndAppInfo(mchNo, appId)校验商户与应用存在性;通过payInterfaceConfigService.mchAppHasAvailableIfCode(appId, ifCode)校验该应用已配置并启用对应支付接口,否则抛出"商户应用的支付配置不存在或已关闭"。
  3. 分账组校验:调用mchDivisionReceiverGroupService.findByIdAndMchNo(receiverGroupId, mchNo)校验组归属,必须属于该商户,否则提示"请进入商户平台进行创建操作"。
  4. 分账比例校验divisionProfit解析为BigDecimal后必须满足0 < 比例 ≤ 1,即取值范围为[0.0001, 1.0000]
  5. 调起渠道绑定:通过SpringBeansUtil.getBean(ifCode + "DivisionService", IDivisionService.class)按接口代码动态获取渠道实现(如wxpayDivisionServicealipayDivisionService),调用divisionService.bind(receiver, mchAppConfigContext)
  6. 结果落库与返回:渠道返回CONFIRM_SUCCESS时绑定状态置为成功(bindState=1)并落库;否则记录渠道错误码与错误信息返回调用方。

渠道适配层通过统一的 IDivisionService.java 接口抽象,其bind方法在不同渠道中映射到不同上游接口:

  • 微信(WxpayDivisionService.java):V2 使用ProfitSharingReceiverRequest(添加分账接收方),V3 使用ProfitSharingReceiverV3Request;账号类型0-个人映射为PERSONAL_OPENID1-商户映射为MERCHANT_ID
  • 支付宝(AlipayDivisionService.java):调用AlipayTradeRoyaltyRelationBindRequest(分账关系绑定),通过正则(RegKit.isAlipayUserId)判断accNouserId还是loginName以决定RoyaltyEntity.type

四、接口二:发起订单分账(/api/division/exec)

当订单下单时传入的分账模式divisionMode = 2(商户手动分账,即解冻商户金额),支付成功后支持商户手动发起订单分账。

重要前提:需要在订单支付完成后(建议 1 分钟后)再调用分账接口,避免渠道侧订单状态尚未最终确认导致分账失败。

请求 URL:https://pay.jeepay.vip/api/division/exec

4.1 请求参数

字段名变量名必填类型示例值描述
商户号mchNoString(30)M1621873433953商户号
应用IDappIdString(24)60cc09bce4b0f1c0b83761c9应用ID
支付订单号payOrderIdString(30)P20160427210604000490支付中心生成的支付订单号,与mchOrderNo二者传一即可
商户单号mchOrderNoString(30)20160427210604000490商户生成的支付单号,与payOrderId二者传一即可
是否使用系统配置的自动分账组useSysAutoDivisionReceiversint1是否使用系统配置的自动分账组: 0-否 1-是
分账接收者账号列表receiversString(512)[]接收者账号列表(JSONArray 转换为字符串类型),仅当 useSysAutoDivisionReceivers=0 时该字段值有效
请求时间reqTimelong1622016572190请求接口时间,13位时间戳
接口版本versionString(3)1.0接口版本号,固定:1.0
签名signString(32)C380BEC2BFD727A4B6845133519F3AD6签名值,详见签名算法
签名类型signTypeString(32)MD5签名类型,目前只支持MD5方式

receivers 字段说明(JSONArray 序列化后的字符串):

  • 方式1(按账号维度):[{"receiverId": 800001, "divisionProfit": 0.1}]——divisionProfit不填则使用系统默认配置值。
  • 方式2(按组维度):[{"receiverGroupId": 100001, "divisionProfit": 0.1}]—— 该组所有"当前订单渠道账号且可用状态"的接收者全部参与分账;divisionProfit表示每个账号的分账比例,不填则使用系统默认配置值(建议不填写)。

4.2 请求示例数据

{ 'version': '1.0', 'reqTime': '1622016572190', 'signType': 'MD5', 'sign': '1', 'mchNo': 'M1623997351', 'appId': '60cc3ba74ee0e6685f57eb1e', 'payOrderId': 'P202108271011463510002', 'useSysAutoDivisionReceivers': '0', 'receivers': '[{"receiverGroupId":"","receiverId":"800029","divisionProfit":"0.0001"},{"receiverGroupId":"","receiverId":"800028","divisionProfit":"0.0002"}]' }

4.3 返回参数

字段名变量名必填类型示例值描述
返回状态codeint00-处理成功,其他-处理有误,详见错误码
返回信息msgString(128)签名失败具体错误原因
签名信息signString(32)CCD9083A6DAD9A2DA9F668C3D4517A84对data内数据签名
返回数据dataString(512){}返回分账数据,json格式

data 数据格式:

字段名变量名必填类型示例值描述
分账状态stateint2分账状态 1-分账成功,2-分账失败
上游分账批次号channelBatchOrderIdString(30)T20160427210604000490上游分账批次号
渠道错误码errCodeString1002渠道返回错误码
渠道错误描述errMsgStringERROR渠道返回错误描述

返回示例数据:

{ "code": 0, "data": { "errCode": "unknown-sub-code", "errMsg": "Business Failed【未知的错误码ACQ.ROYALTY_ACCOUNT_NOT_EXIST】", "state": 2 }, "msg": "SUCCESS", "sign": "56836E18015DD7E4FAFE45380C0AD098" }

该示例展示了一次典型的分账失败:code=0表示请求与校验通过,但渠道侧返回ACQ.ROYALTY_ACCOUNT_NOT_EXIST(支付宝:分账接收方账号不存在),即所传receivers中的账号尚未在支付宝侧完成分账关系绑定,因此data.state=2排查方向:先调用绑定接口确认每个 receiver 绑定成功,再发起分账。

4.4 源码解析:分账执行流程

分账执行接口由 PayOrderDivisionExecController.java 实现,核心流程如下:

  1. 验签与参数解析:请求体见 PayOrderDivisionExecRQ.java,其中useSysAutoDivisionReceivers强制非空。
  2. 订单定位与状态校验payOrderIdmchOrderNo至少传一项(同时为空直接报错);通过payOrderService.queryMchOrder查询订单后,必须同时满足三个条件才允许分账:
    • payOrder.state = STATE_SUCCESS(支付成功);
    • payOrder.divisionState = DIVISION_STATE_UNHAPPEN(未发生过自动分账/待分账);
    • payOrder.divisionMode = DIVISION_MODE_MANUAL(商户手动分账模式)。 否则抛出"当前订单状态不支持分账"。
  3. 接收者列表解析与校验:当useSysAutoDivisionReceivers=0receivers非空时,将 JSON 字符串反序列化为PayOrderDivisionMQ.CustomerDivisionReceiver列表;checkReceiverList逐项校验:
    • receiverIdreceiverGroupId必填一项;
    • divisionProfit必须介于 0%~100% 之间;
    • 按账号维度时,校验 receiverId 集合均属于该商户、该应用、该渠道且状态可用(state=YES);
    • 按组维度时,校验 receiverGroupId 集合均属于该商户。
  4. 执行分账:调用 PayOrderDivisionProcessService.processPayOrderDivision 完成分账处理(详见下节)。
  5. 结果映射:根据渠道返回状态映射data.state——CONFIRM_SUCCESS1(分账成功)、CONFIRM_FAIL2(分账失败)、其余(WAITING等)→ 受理中,并回填上游分账批次号channelBatchOrderId与渠道错误信息。

4.5 分账处理核心逻辑

PayOrderDivisionProcessService.java 是分账执行的服务层核心,其关键设计:

  • 状态机流转:订单divisionState依次经历WAIT_TASK/UNHAPPEN(待分账)→ING(分账处理中)→FINISH(分账任务结束)。通过带divisionState等值条件的乐观更新防止重复发起。
  • 接收者查询(queryReceiver)
    • useSysAutoDivisionReceivers=1时,查询商户下autoDivisionFlag=YES的自动分账组,取第一个自动分账组内的全部可用接收者;
    • useSysAutoDivisionReceivers=0时,按mchNo + appId + ifCode + state=可用查询全部接收者,再与请求中的receivers列表按receiverIdreceiverGroupId匹配过滤;若请求中某接收者携带divisionProfit,将覆盖其系统默认分账比例。
  • 金额计算:以商户实际入账金额(calMchIncomeAmount,即扣除渠道手续费的净额)作为分账基数;先按"全部分账比例总和"算出剩余待分账金额(向下取整,避免金额溢出),再逐条按分账金额 = 分账基数 × 分账比例计算,并保证"最后一个账号分账金额不超过剩余金额"。
  • 记录落库:每条分账明细生成PayOrderDivisionRecord(状态STATE_WAIT待分账),同一批次共享batchOrderIdSeqKit.genDivisionBatchId()生成),并记录订单号、渠道订单号、接收者信息、计算分账金额等快照。
  • 渠道调用:通过SpringBeansUtil.getBean(payOrder.getIfCode() + "DivisionService", IDivisionService.class)动态获取渠道实现并调用singleDivision。以支付宝为例(AlipayDivisionService.java),调用AlipayTradeOrderSettleRequest(交易结算)并设置royaltyMode="sync"(同步分账)、royaltyFinish="true"(分账完结,支付宝无完结接口因此直接完结);接收者列表为空时直接返回成功。
  • 结果回写:渠道明确成功则明细更新为STATE_SUCCESS;明确失败则更新为STATE_FAIL并记录渠道错误;WAITING(已受理)则更新为STATE_ACCEPT,等待补单任务轮询。

4.6 分账补单机制

对于渠道返回"已受理"(STATE_ACCEPT)的分账明细,PayOrderDivisionRecordReissueTask.java 提供兜底补偿:定时任务每分钟执行一次(cron = 0 0/1 * * * ?),查询"受理中且创建时间早于当前时间 5 分钟"的分账记录,按batchOrderId分组后调用渠道queryDivision查询最终结果,并将明确的成功/失败状态回写明细记录。这也是分账接口"建议支付完成后 1 分钟再调用"的原因之一——给渠道留出状态收敛时间。

五、两种分账模式的使用场景建议

场景推荐模式说明
固定合作伙伴、固定比例定期分润自动分账组(下单时divisionMode=1配合系统自动分账)支付完成后系统按自动分账组自动触发,无需手动调用/api/division/exec
每次分账对象与比例灵活变化商户手动分账(下单时divisionMode=2支付成功后调用/api/division/exec,通过receivers按账号或按组指定本次分账明细
同一批接收者长期复用分账账号组(组 ID 模式)先在商户平台创建账号组,绑定接口按receiverGroupId加入,分账时按组纬度引用

六、对接要点与常见问题排查

  1. 绑定是分账的前置条件:微信、支付宝均要求分账接收者先在渠道侧完成关系绑定,否则分账时返回ACQ.ROYALTY_ACCOUNT_NOT_EXIST(支付宝)或NOAUTH无分账权限(微信)。绑定结果以data.bindState为准,而非外层code
  2. 订单状态必须匹配:发起分账前确认订单divisionMode=2(手动分账)、支付成功且尚未分账;否则返回"当前订单状态不支持分账"。
  3. 分账比例校验:单个接收者比例范围为0.0001 ~ 1.0000(绑定接口)或0% ~ 100%(分账执行接口);建议控制全部分账比例总和不超过 100%,系统会在计算时对最后一个账号按剩余金额向下取整兜底。
  4. 渠道权限:分账属于微信/支付宝的高权限能力,需在渠道侧单独申请开通(微信分账、支付宝分账),Jeepay 侧无法替代渠道审核。
  5. 幂等与补单receivers列表重复提交时,系统通过订单分账状态乐观锁防重;渠道"已受理"的分账会由 PayOrderDivisionRecordReissueTask.java 每分钟自动补单查询,无需业务方重复发起。
  6. 返回码判定:所有接口先看code=0判断请求链路是否正常,再看data内业务状态(bindState/state)判断渠道侧结果,两者不可混淆。

七、相关参考

  • 接口文档原文:jeepay-payment/src/main/resources/markdown/doc/api5.md
  • 绑定接口实现:MchDivisionReceiverBindController.java
  • 分账执行实现:PayOrderDivisionExecController.java
  • 分账处理服务:PayOrderDivisionProcessService.java
  • 渠道分账接口抽象:IDivisionService.java
  • 渠道实现示例:AlipayDivisionService.java、WxpayDivisionService.java
  • 分账补单任务:PayOrderDivisionRecordReissueTask.java
  • 相关数据实体:MchDivisionReceiver.java、MchDivisionReceiverGroup.java、PayOrderDivisionRecord.java

【免费下载链接】jeepayJeepay是一套适合互联网企业使用的开源支付系统,支持多渠道服务商和普通商户模式。已对接微信支付,支付宝,云闪付官方接口,支持聚合码支付。项目地址: https://gitcode.com/GitHub_Trending/je/jeepay

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询