分账场景

更新时间:2024.11.15

1. 接口规则

为了在保证支付安全的前提下,带给商户简单、一致且易用的开发体验,我们推出了全新的微信支付APIv3接口。该版本API的具体规则请参考APIv3接口规则

2. 开发准备

2.1. 搭建和配置开发环境

开发者应当依据自身的编程语言来构建并配置相应的开发环境。

2.2. 业务开发配置-分账

需分账的订单,平台在下单时需预先打上分账标识“profit_sharing”,详细可查看各场景下单API(普通支付下单/合单支付下单API)。

3. 快速接入

3.1. 业务流程图-分账

重要步骤说明:

步骤1 平台通过添加分账接收方API添加需要分账的分账对象(接收方)。

步骤2 平台预先在合单支付/普通支付下单API接口中上传分账标识“profit_sharing”,待订单完成支付后即可调用请求分账API接口发起分账请求。

步骤3 分账完成后,微信会通过分账动账通知API接口,主动通知商户。商户如有需要,可以通过查询分账结果API接口,主动查询分账结果。

步骤4 分账后若产生退款,则需先调用请求分账回退API 接口,请求将已经分给分账方的资金回退,再处理退款。

步骤5 分账回退完成后,微信同样会通过分账动账通知API接口,主动通知商户。商户也可以通过查询分账回退结果API接口,主动查询分账结果。

步骤6: 分账结束后,商户需调用完结分账API接口结束分账订单。

3.2. API接入-分账

本文档展示了如何使用微信支付服务端 SDK 快速接入平台收付通产品,完成与微信支付对接的部分。

注意

  • 文档中的代码示例是用来阐述 API 基本使用方法,代码中的示例参数需替换成商户自己账号及请求参数才能跑通。

  • 以下接入步骤仅提供参考,请商户结合自身业务需求进行评估、修改。

3.2.1.【服务端】添加分账接收方

步骤说明: 平台可通过此接口添加分账接收方,建立分账接收方列表。后续通过发起分账请求,将平台下的二级商户结算后的资金,分给分账接收方列表中具体的分账接收方。

示例代码

JAVA

1public void AddProfitsharingReceivers() throws Exception{
2  //请求URL
3  HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/ecommerce/profitsharing/receivers/add");
4  // 请求body参数
5  String reqdata = "{"
6          + "\"appid\":\"wx8888888888888888\","
7          + "\"type\":\"MERCHANT_ID\","
8          + "\"account\":\"190001001\","
9          + "\"name\":\"张三网络公司\","
10          + "\"relation_type\":\"SUPPLIER\""
11          + "}";
12  StringEntity entity = new StringEntity(reqdata,"utf-8");
13  entity.setContentType("application/json");
14  httpPost.setEntity(entity);
15  httpPost.setHeader("Accept", "application/json");
16  //完成签名并执行请求
17  CloseableHttpResponse response = httpClient.execute(httpPost);
18  try {
19      int statusCode = response.getStatusLine().getStatusCode();
20      if (statusCode == 200) { //处理成功
21          System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
22      } else if (statusCode == 204) { //处理成功,无返回Body
23          System.out.println("success");
24      } else {
25          System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
26          throw new IOException("request failed");
27      }
28  } finally {
29      response.close();
30  }
31}

PHP

1use GuzzleHttp\Exception\RequestException;
2use WechatPay\GuzzleMiddleware\WechatPayMiddleware;
3use WechatPay\GuzzleMiddleware\Util\PemUtil;
4use GuzzleHttp\HandlerStack;
5try {
6    $resp = $client->request(
7        'POST',
8        'https://api.mch.weixin.qq.com/v3/ecommerce/profitsharing/receivers/add', //请求URL
9        [
10            // JSON请求体
11            'json' => [
12                "appid" => "wx8888888888888888",
13                "type" => "MERCHANT_ID",
14                "account" => "190001001",
15                "name" => "张三网络公司",
16                "relation_type" => "SUPPLIER",
17            ],
18            'headers' => [ 'Accept' => 'application/json' ]
19        ]
20    );
21    $statusCode = $resp->getStatusCode();
22    if ($statusCode == 200) { //处理成功
23        echo "success,return body = " . $resp->getBody()->getContents()."\n";
24    } else if ($statusCode == 204) { //处理成功,无返回Body
25        echo "success";
26    }
27} catch (RequestException $e) {
28    // 进行错误处理
29    echo $e->getMessage()."\n";
30    if ($e->hasResponse()) {
31        echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
32    }
33    return;
34}

更多参数、响应详情及错误码请参见添加分账接收方API接口文档。

3.2.2.【服务端】请求分账

步骤说明: 平台,如有订单需要进行分账,可通过此接口完成。

示例代码

JAVA

1public void Profitsharing() throws Exception{
2  //请求URL
3  HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/ecommerce/profitsharing/orders");
4  // 请求body参数
5  String reqdata = "{"
6          + "\"sub_mchid\":\"1900000109\","
7          + "\"transaction_id\":\"4208450740201411110007820472\","
8          + "\"out_order_no\":\"P20150806125346\","
9          + "\"receivers\": ["
10          + "{"
11          + "\"type\":\"MERCHANT_ID\","
12          + "\"receiver_account\":\"1900000110\","
13          + "\"receiver_mchid\":\"1900000110\","
14          + "\"amount\":100,"
15          + "\"description\":\"分给商户1900000110\""
16          + "}"
17          + "],"
18          + "\"finish\":true"
19          + "}";
20  StringEntity entity = new StringEntity(reqdata,"utf-8");
21  entity.setContentType("application/json");
22  httpPost.setEntity(entity);
23  httpPost.setHeader("Accept", "application/json");
24  //完成签名并执行请求
25  CloseableHttpResponse response = httpClient.execute(httpPost);
26  try {
27      int statusCode = response.getStatusLine().getStatusCode();
28      if (statusCode == 200) { //处理成功
29          System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
30      } else if (statusCode == 204) { //处理成功,无返回Body
31          System.out.println("success");
32      } else {
33          System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
34          throw new IOException("request failed");
35      }
36  } finally {
37      response.close();
38  }
39}

PHP

1try {
2    $resp = $client->request(
3        'POST',
4        'https://api.mch.weixin.qq.com/v3/ecommerce/profitsharing/orders', //请求URL
5        [
6            // JSON请求体
7            'json' => [
8                "sub_mchid" => "1900000109",
9                "transaction_id" => "4208450740201411110007820472",
10                "out_order_no" => "P20150806125346",
11                "receivers" => [
12                    [
13                        "type" => "MERCHANT_ID",
14                        "receiver_account" => "1900000110",
15                        "receiver_mchid" => "1900000110",
16                        "amount" => 100,
17                        "description" => "分给商户1900000110",
18                    ],
19                ],
20                "finish" => true,
21            ],
22            'headers' => [ 'Accept' => 'application/json' ]
23        ]
24    );
25    $statusCode = $resp->getStatusCode();
26    if ($statusCode == 200) { //处理成功
27        echo "success,return body = " . $resp->getBody()->getContents()."\n";
28    } else if ($statusCode == 204) { //处理成功,无返回Body
29        echo "success";
30    }
31} catch (RequestException $e) {
32    // 进行错误处理
33    echo $e->getMessage()."\n";
34    if ($e->hasResponse()) {
35        echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
36    }
37    return;
38}

更多参数、响应详情及错误码请参见请求分账API接口文档。

3.2.3.【服务端】分账动账通知

步骤说明: 此功能仅针对分账接收方,当分账动账金额发生变动时,微信会把相关变动结果发送给需要实时关注的分账接收方。

注意

  • 支付结果通知是以POST 方法访问商户设置的通知URL,通知的数据以JSON 格式通过请求主体(BODY)传输。通知的数据包括了加密的支付结果详情。

  • 加密不能保证通知请求来自微信。微信会对发送给商户的通知进行签名,并将签名值放在通知的HTTP头Wechatpay-Signature。商户应当验证签名,以确认请求来自微信,而不是其他的第三方。签名验证的算法请参考 《微信支付API v3签名验证》

  • 支付通知HTTP应答码为200或204才会当作正常接收,当回调处理异常时,应答的HTTP状态码应为500,或者4xx。

  • 商户成功接收到回调通知后应返回成功的HTTP应答码为200或204。

  • 同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。 推荐的做法是,当商户系统收到通知进行处理时,先检查对应业务数据的状态,并判断该通知是否已经处理。如果未处理,则再进行处理;如果已处理,则直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。

更多参数、响应详情及错误码请参见分账动账通知API接口文档

3.2.4. 【服务端】查询分账结果

步骤说明: 平台可通过此接口实时关注订单的分账请求和分账完结情况。

示例代码

JAVA

1public void QueryProfitsharing() throws Exception{
2  //请求URL
3  HttpGet httpGet = new HttpGet("https://api.mch.weixin.qq.com/v3/ecommerce/profitsharing/orders?sub_mchid=1900000109&transaction_id=4208450740201411110007820472&out_order_no=P20150806125346");
4  httpGet.setHeader("Accept", "application/json");
5  //完成签名并执行请求
6  CloseableHttpResponse response = httpClient.execute(httpGet);
7  try {
8      int statusCode = response.getStatusLine().getStatusCode();
9      if (statusCode == 200) { //处理成功
10          System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
11      } else if (statusCode == 204) { //处理成功,无返回Body
12          System.out.println("success");
13      } else {
14          System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
15          throw new IOException("request failed");
16      }
17  } finally {
18      response.close();
19  }
20}

PHP

1try {
2    $resp = $client->request(
3        'GET',
4        'https://api.mch.weixin.qq.com/v3/ecommerce/profitsharing/orders?sub_mchid=1900000109&transaction_id=4208450740201411110007820472&out_order_no=P20150806125346', //请求URL
5        [
6            'headers' => [ 'Accept' => 'application/json']
7        ]
8    );
9    $statusCode = $resp->getStatusCode();
10    if ($statusCode == 200) { //处理成功
11        echo "success,return body = " . $resp->getBody()->getContents()."\n";
12    } else if ($statusCode == 204) { //处理成功,无返回Body
13        echo "success";
14    }
15} catch (RequestException $e) {
16    // 进行错误处理
17    echo $e->getMessage()."\n";
18    if ($e->hasResponse()) {
19        echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
20    }
21    return;
22}

更多参数、响应详情及错误码请参见 查询分账结果API接口文档

3.2.5. 【服务端】请求分账回退

步骤说明: 订单已经分账,在退款时,可以先调此接口,将已分账的资金从分账接收方的账户回退给分账方,再发起退款。

示例代码

JAVA

1public void Demo() throws Exception{
2  //请求URL
3  HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/ecommerce/profitsharing/returnorders");
4  // 请求body参数
5  String reqdata = "{"
6          + "\"sub_mchid\":\"1900000109\","
7          + "\"order_id\":\"3008450740201411110007820472\","
8          + "\"out_order_no\":\"P20150806125346\","
9          + "\"out_return_no\":\"R20190516001\","
10          + "\"return_mchid\":\"86693852\","
11          + "\"amount\":10,"
12          + "\"description\":\"分账回退\""
13          + "}";
14  StringEntity entity = new StringEntity(reqdata,"utf-8");
15  entity.setContentType("application/json");
16  httpPost.setEntity(entity);
17  httpPost.setHeader("Accept", "application/json");
18  //完成签名并执行请求
19  CloseableHttpResponse response = httpClient.execute(httpPost);
20  try {
21      int statusCode = response.getStatusLine().getStatusCode();
22      if (statusCode == 200) { //处理成功
23          System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
24      } else if (statusCode == 204) { //处理成功,无返回Body
25          System.out.println("success");
26      } else {
27          System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
28          throw new IOException("request failed");
29      }
30  } finally {
31      response.close();
32  }
33}

PHP

1try {
2    $resp = $client->request(
3        'POST',
4        'https://api.mch.weixin.qq.com/v3/ecommerce/profitsharing/returnorders', //请求URL
5        [
6            // JSON请求体
7            'json' => [
8                "sub_mchid" => "1900000109",
9                "order_id" => "3008450740201411110007820472",
10                "out_order_no" => "P20150806125346",
11                "out_return_no" => "R20190516001",
12                "return_mchid" => "86693852",
13                "amount" => 10,
14                "description" => "分账回退",
15            ],
16            'headers' => [ 'Accept' => 'application/json' ]
17        ]
18    );
19    $statusCode = $resp->getStatusCode();
20    if ($statusCode == 200) { //处理成功
21        echo "success,return body = " . $resp->getBody()->getContents()."\n";
22    } else if ($statusCode == 204) { //处理成功,无返回Body
23        echo "success";
24    }
25} catch (RequestException $e) {
26    // 进行错误处理
27    echo $e->getMessage()."\n";
28    if ($e->hasResponse()) {
29        echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
30    }
31    return;
32}

更多参数、响应详情及错误码请参见请求分账回退API 接口文档。

3.2.6. 【服务端】查询分账回退结果

步骤说明: 商户需要核实回退结果,可调用此接口查询回退结果;如果分账回退接口返回状态为处理中,可调用此接口查询回退结果。

示例代码

JAVA

1public void QueryFallbackProfitsharing() throws Exception{
2  //请求URL
3  HttpGet httpGet = new HttpGet("https://api.mch.weixin.qq.com/v3/ecommerce/profitsharing/returnorders?sub_mchid=1900000109&out_order_no=P20150806125346&out_return_no=R20190516001");
4  httpGet.setHeader("Accept", "application/json");
5  //完成签名并执行请求
6  CloseableHttpResponse response = httpClient.execute(httpGet);
7  try {
8      int statusCode = response.getStatusLine().getStatusCode();
9      if (statusCode == 200) { //处理成功
10          System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
11      } else if (statusCode == 204) { //处理成功,无返回Body
12          System.out.println("success");
13      } else {
14          System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
15          throw new IOException("request failed");
16      }
17  } finally {
18      response.close();
19  }
20}

PHP

1try {
2    $resp = $client->request(
3        'GET',
4        'https://api.mch.weixin.qq.com/v3/ecommerce/profitsharing/returnorders?sub_mchid=1900000109&out_order_no=P20150806125346&out_return_no=R20190516001', //请求URL
5        [
6            'headers' => [ 'Accept' => 'application/json']
7        ]
8    );
9    $statusCode = $resp->getStatusCode();
10    if ($statusCode == 200) { //处理成功
11        echo "success,return body = " . $resp->getBody()->getContents()."\n";
12    } else if ($statusCode == 204) { //处理成功,无返回Body
13        echo "success";
14    }
15} catch (RequestException $e) {
16    // 进行错误处理
17    echo $e->getMessage()."\n";
18    if ($e->hasResponse()) {
19        echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
20    }
21    return;
22}

更多参数、响应详情及错误码请参见查询分账回退结果API 接口文档。

3.2.7. 【服务端】完结分账

步骤说明: 不需要进行分账的订单,可直接调用本接口将订单的金额全部解冻给二级商户。

示例代码

JAVA

1public void FinishProfitsharing() throws Exception{
2  //请求URL
3  HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/ecommerce/profitsharing/finish-order");
4  // 请求body参数
5  String reqdata = "{"
6          + "\"sub_mchid\":\"1900000109\","
7          + "\"transaction_id\":\"4208450740201411110007820472\","
8          + "\"out_order_no\":\"P20150806125346\","
9          + "\"description\":\"分账完结\""
10          + "}";
11  StringEntity entity = new StringEntity(reqdata,"utf-8");
12  entity.setContentType("application/json");
13  httpPost.setEntity(entity);
14  httpPost.setHeader("Accept", "application/json");
15  //完成签名并执行请求
16  CloseableHttpResponse response = httpClient.execute(httpPost);
17  try {
18      int statusCode = response.getStatusLine().getStatusCode();
19      if (statusCode == 200) { //处理成功
20          System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
21      } else if (statusCode == 204) { //处理成功,无返回Body
22          System.out.println("success");
23      } else {
24          System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
25          throw new IOException("request failed");
26      }
27  } finally {
28      response.close();
29  }
30}

PHP

1try {
2    $resp = $client->request(
3        'POST',
4        'https://api.mch.weixin.qq.com/v3/ecommerce/profitsharing/finish-order', //请求URL
5        [
6            // JSON请求体
7            'json' => [
8                "sub_mchid" => "1900000109",
9                "transaction_id" => "4208450740201411110007820472",
10                "out_order_no" => "P20150806125346",
11                "description" => "分账完结",
12            ],
13            'headers' => [ 'Accept' => 'application/json' ]
14        ]
15    );
16    $statusCode = $resp->getStatusCode();
17    if ($statusCode == 200) { //处理成功
18        echo "success,return body = " . $resp->getBody()->getContents()."\n";
19    } else if ($statusCode == 204) { //处理成功,无返回Body
20        echo "success";
21    }
22} catch (RequestException $e) {
23    // 进行错误处理
24    echo $e->getMessage()."\n";
25    if ($e->hasResponse()) {
26        echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
27    }
28    return;
29}

更多参数、响应详情及错误码请参见完结分账API接口文档。

3.2.8. 【服务端】查询订单剩余待分金额

步骤说明: 分账接口支持对一笔订单进行多次分账,在这过程中,你可以使用该接口查询订单剩余的可进行分账的金额。

示例代码

JAVA

1public void QueryProfitsharingAmounts() throws Exception{
2  //请求URL
3  HttpGet httpGet = new HttpGet("https://api.mch.weixin.qq.com/v3/ecommerce/profitsharing/orders/4208450740201411110007820472/amounts");
4  httpGet.setHeader("Accept", "application/json");
5  //完成签名并执行请求
6  CloseableHttpResponse response = httpClient.execute(httpGet);
7  try {
8      int statusCode = response.getStatusLine().getStatusCode();
9      if (statusCode == 200) { //处理成功
10          System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
11      } else if (statusCode == 204) { //处理成功,无返回Body
12          System.out.println("success");
13      } else {
14          System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
15          throw new IOException("request failed");
16      }
17  } finally {
18      response.close();
19  }
20}

PHP

1try {
2    $resp = $client->request(
3        'GET',
4        'https://api.mch.weixin.qq.com/v3/ecommerce/profitsharing/orders/4208450740201411110007820472/amounts', //请求URL
5        [
6            'headers' => [ 'Accept' => 'application/json']
7        ]
8    );
9    $statusCode = $resp->getStatusCode();
10    if ($statusCode == 200) { //处理成功
11        echo "success,return body = " . $resp->getBody()->getContents()."\n";
12    } else if ($statusCode == 204) { //处理成功,无返回Body
13        echo "success";
14    }
15} catch (RequestException $e) {
16    // 进行错误处理
17    echo $e->getMessage()."\n";
18    if ($e->hasResponse()) {
19        echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
20    }
21    return;
22}

更多参数、响应详情及错误码请参见查询订单剩余待分金额API接口文档。

3.2.9. 【服务端】删除分账接收方

步骤说明: 平台发起删除分账接收方请求。删除后,不支持将平台下二级商户结算后的资金,分到该分账接收方。

示例代码

JAVA

1public void DeleteProfitsharingReceivers() throws Exception{
2  //请求URL
3  HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/ecommerce/profitsharing/receivers/delete");
4  // 请求body参数
5  String reqdata = "{"
6          + "\"appid\":\"wx8888888888888888\","
7          + "\"type\":\"MERCHANT_ID\","
8          + "\"account\":\"190001001\""
9          + "}";
10  StringEntity entity = new StringEntity(reqdata,"utf-8");
11  entity.setContentType("application/json");
12  httpPost.setEntity(entity);
13  httpPost.setHeader("Accept", "application/json");
14  //完成签名并执行请求
15  CloseableHttpResponse response = httpClient.execute(httpPost);
16  try {
17      int statusCode = response.getStatusLine().getStatusCode();
18      if (statusCode == 200) { //处理成功
19          System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
20      } else if (statusCode == 204) { //处理成功,无返回Body
21          System.out.println("success");
22      } else {
23          System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
24          throw new IOException("request failed");
25      }
26  } finally {
27      response.close();
28  }
29}

PHP

1try {
2    $resp = $client->request(
3        'POST',
4        'https://api.mch.weixin.qq.com/v3/ecommerce/profitsharing/receivers/delete', //请求URL
5        [
6            // JSON请求体
7            'json' => [
8                "appid" => "wx8888888888888888",
9                "type" => "MERCHANT_ID",
10                "account" => "190001001",
11            ],
12            'headers' => [ 'Accept' => 'application/json' ]
13        ]
14    );
15    $statusCode = $resp->getStatusCode();
16    if ($statusCode == 200) { //处理成功
17        echo "success,return body = " . $resp->getBody()->getContents()."\n";
18    } else if ($statusCode == 204) { //处理成功,无返回Body
19        echo "success";
20    }
21} catch (RequestException $e) {
22    // 进行错误处理
23    echo $e->getMessage()."\n";
24    if ($e->hasResponse()) {
25        echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
26    }
27    return;
28}

更多参数、响应详情及错误码请参见 删除分账接收方API接口文档。