支付即服务开发指引
1. 接口规则
为了在保证支付安全的前提下,带给商户简单、一致且易用的开发体验,我们推出了全新的微信支付APIv3接口。该版本API的具体规则请参考“APIv3接口规则”
备注:当前接口用于微信国内钱包
2. 开发准备
2.1. 搭建和配置开发环境
为了帮助开发者调用开放接口,我们提供了JAVA、PHP、GO三种语言版本的开发库,封装了签名生成、签名验证、敏感信息加/解密、媒体文件上传等基础功能(更多语言版本的开发库将在近期陆续提供)
测试步骤:
1、根据自身开发语言,选择对应的开发库并构建项目,具体配置请参考下面链接的详细说明:
• wechatpay-java(推荐)wechatpay-apache-httpclient,适用于Java开发者。
• wechatpay-php(推荐)、wechatpay-guzzle-middleware,适用于PHP开发者
注:当前开发指引接口PHP示例代码采用wechatpay-guzzle-middleware版本
• wechatpay-go,适用于Go开发者
更多资源可前往微信支付开发者社区搜索查看
2、创建加载商户私钥、加载平台证书、初始化httpClient的通用方法
@Before
public void setup() throws IOException {
// 加载商户私钥(privateKey:私钥字符串)
PrivateKey merchantPrivateKey = PemUtil
.loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes("utf-8")));
// 加载平台证书(mchId:商户号,mchSerialNo:商户证书序列号,apiV3Key:V3密钥)
AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
new WechatPay2Credentials(mchId, new PrivateKeySigner(mchSerialNo, merchantPrivateKey)),apiV3Key.getBytes("utf-8"));
// 初始化httpClient
httpClient = WechatPayHttpClientBuilder.create()
.withMerchant(mchId, mchSerialNo, merchantPrivateKey)
.withValidator(new WechatPay2Validator(verifier)).build();
}
@After
public void after() throws IOException {
httpClient.close();
}
use GuzzleHttp\Exception\RequestException;
use WechatPay\GuzzleMiddleware\WechatPayMiddleware;
use WechatPay\GuzzleMiddleware\Util\PemUtil;
use GuzzleHttp\HandlerStack;
// 商户相关配置,
$merchantId = '1000100'; // 商户号
$merchantSerialNumber = 'XXXXXXXXXX'; // 商户API证书序列号
$merchantPrivateKey = PemUtil::loadPrivateKey('./path/to/mch/private/key.pem'); // 商户私钥文件路径
// 微信支付平台配置
$wechatpayCertificate = PemUtil::loadCertificate('./path/to/wechatpay/cert.pem'); // 微信支付平台证书文件路径
// 构造一个WechatPayMiddleware
$wechatpayMiddleware = WechatPayMiddleware::builder()
->withMerchant($merchantId, $merchantSerialNumber, $merchantPrivateKey) // 传入商户相关配置
->withWechatPay([ $wechatpayCertificate ]) // 可传入多个微信支付平台证书,参数类型为array
->build();
// 将WechatPayMiddleware添加到Guzzle的HandlerStack中
$stack = GuzzleHttp\HandlerStack::create();
$stack->push($wechatpayMiddleware, 'wechatpay');
// 创建Guzzle HTTP Client时,将HandlerStack传入,接下来,正常使用Guzzle发起API请求,WechatPayMiddleware会自动地处理签名和验签
$client = new GuzzleHttp\Client(['handler' => $stack]);
/*
Package core 微信支付api v3 go http-client 基础库,你可以使用它来创建一个client,并向微信支付发送http请求
只需要你在初始化客户端的时候,传递credential以及validator
credential用来生成http header中的authorization信息
validator则用来校验回包是否被篡改
如果http请求返回的err为nil,一般response.Body 都不为空,你可以尝试对其进行序列化
请注意及时关闭response.Body
注意:使用微信支付apiv3 go库需要引入相关的包,该示例代码必须引入的包名有以下信息
"context"
"crypto/x509"
"fmt"
"io/ioutil"
"log"
"github.com/wechatpay-apiv3/wechatpay-go/core"
"github.com/wechatpay-apiv3/wechatpay-go/core/option"
"github.com/wechatpay-apiv3/wechatpay-go/utils"
*/
func SetUp() (opt []option.ClientOption, err error) {
//商户号
mchID := ""
//商户证书序列号
mchCertSerialNumber := ""
//商户私钥文件路径
privateKeyPath := ""
//平台证书文件路径
wechatCertificatePath := ""
// 加载商户私钥
privateKey, err := utils.LoadPrivateKeyWithPath(privateKeyPath)
if err != nil {
log.Printf("load private err:%s", err.Error())
return nil, err
}
// 加载微信支付平台证书
wechatPayCertificate, err := utils.LoadCertificateWithPath(wechatCertificatePath)
if err != nil {
log.Printf("load certificate err:%s",err)
return nil, err
}
//设置header头中authorization信息
opts := []option.ClientOption{
option.WithMerchant(mchID, mchCertSerialNumber, privateKey), // 设置商户相关配置
option.WithWechatPay([]*x509.Certificate{wechatPayCertificate}), // 设置微信支付平台证书,用于校验回包信息用
}
return opts, nil
}
3、基于接口的示例代码,替换请求参数后可发起测试
说明:
• 上面的开发库为微信支付官方开发库,其它没有审核或者控制下的第三方工具和库,微信支付不保证它们的安全性和可靠性
通过包管理工具引入SDK后,可根据下面每个接口的示例代码替换相关参数后进行快速测试
• 开发者如果想详细了解签名生成、签名验证、敏感信息加/解密、媒体文件上传等常用方法的具体代码实现,可阅读下面的详细说明:
1.签名生成
2.签名验证
3.敏感信息加解密
4.merchantPrivateKey(私钥)
5.wechatpayCertificates(平台证书)
6.APIV3Key(V3 key)
• 如想更详细的了解我们的接口规则,可查看我们的接口规则指引文档
2.2. 业务开发配置
1、登录【微信支付服务商平台】后,通过路径【产品中心—>我的产品—>支付即服务—>产品设置】,即可开通支付即服务,开通后完成产品设置。
2、【产品设置】页面如下图所示,具体内容包括上传商家logo、选择服务人员名称及选择名片功能模块。
3. 快速接入
3.1. 业务流程图
重点步骤说明:
步骤6 使用企业微信的商户,通过《服务人员注册API》接口传入服务人员信息进行注册,微信支付返回服务人员ID给到商户,商户需将服务人员注册信息和对应的服务人员ID进行妥善保存。
步骤11 商户在下单时生成商户订单号,接着调用《服务人员分配API》传入“商户订单号+服务人员ID”,随后按照原有流程和支付接口完成支付即可。
3.2. API接入(含示例代码)
文档展示了如何使用微信支付服务端 SDK 快速接入支付即服务产品,完成与微信支付对接的部分。
注意:
- 文档中的代码示例是用来阐述 API 基本使用方法,代码中的示例参数需替换成商户自己账号及请求参数才能跑通。
- 以下接入步骤仅提供参考,请商户结合自身业务需求进行评估、修改。
3.2.1. 【服务端】服务人员注册
步骤说明:服务人员注册接口用于商户开发者为商户注册服务人员使用。
注意:
- 调用接口前商家需完成支付即服务产品的开通和设置。若服务商为特约商户调用接口,需在特约商户开通并完成产品设置后,与特约商户建立产品授权关系。
示例代码
public void RegSmartGuide() throws Exception{
//请求URL
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/smartguide/guides");
// 请求body参数
String reqdata = "{"
+ "\"sub_mchid\":\"1234567890\","
+ "\"store_id\":1234,"
+ "\"corpid\":\"1234567890\","
+ "\"name\":\"pVd1HJ6v/69bDnuC4EL5Kz4jBHLiCa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg==\","
+ "\"mobile\":\"pVd1HJ6v/69bDnuC4EL5Kz4jBHLiCa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg==\","
+ "\"qr_code\":\"https://open.work.weixin.qq.com/wwopen/userQRCode?vcode=xxx\","
+ "\"avatar\":\"http://wx.qlogo.cn/mmopen/ajNVdqHZLLA3WJ6DSZUfiakYe37PKnQhBIeOQBO4czqrnZDS79FH5Wm5m4X69TBicnHFlhiafvDwklOpZeXYQQ2icg/0\","
+ "\"group_qrcode\":\"http://p.qpic.cn/wwhead/nMl9ssowtibVGyrmvBiaibzDtp/0\","
+ "\"userid\":\"robert\""
+ "}";
StringEntity entity = new StringEntity(reqdata,"utf-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
httpPost.setHeader("Accept", "application/json");
//完成签名并执行请求
CloseableHttpResponse response = httpClient.execute(httpPost);
try {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) { //处理成功
System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
} else if (statusCode == 204) { //处理成功,无返回Body
System.out.println("success");
} else {
System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
throw new IOException("request failed");
}
} finally {
response.close();
}
}
try {
$resp = $client->request(
'POST',
'https://api.mch.weixin.qq.com/v3/smartguide/guides', //请求URL
[
// JSON请求体
'json' => [
"store_id" => 1234,
"sub_mchid" => "1234567890",
"corpid" => "1234567890",
"name" => "pVd1HJ6v/69bDnuC4EL5Kz4jBHLiCa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg==",
"mobile" => "pVd1HJ6v/69bDnuC4EL5Kz4jBHLiCa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg==",
"qr_code" => "https://open.work.weixin.qq.com/wwopen/userQRCode?vcode=xxx",
"avatar" => "http://wx.qlogo.cn/mmopen/ajNVdqHZLLA3WJ6DSZUfiakYe37PKnQhBIeOQBO4czqrnZDS79FH5Wm5m4X69TBicnHFlhiafvDwklOpZeXYQQ2icg/0",
"group_qrcode" => "http://p.qpic.cn/wwhead/nMl9ssowtibVGyrmvBiaibzDtp/0",
"userid" => "robert",
],
'headers' => [ 'Accept' => 'application/json' ]
]
);
$statusCode = $resp->getStatusCode();
if ($statusCode == 200) { //处理成功
echo "success,return body = " . $resp->getBody()->getContents()."\n";
} else if ($statusCode == 204) { //处理成功,无返回Body
echo "success";
}
} catch (RequestException $e) {
// 进行错误处理
echo $e->getMessage()."\n";
if ($e->hasResponse()) {
echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
}
return;
}
//此处请求头需增加序列号
func RegSmartGuide() {
// 初始化客户端
ctx := context.TODO()
opts, err := SetUp()
if err != nil {
return
}
client, err := core.NewClient(ctx, opts...,)
if err != nil{
log.Printf("init client err:%s",err)
return
}
//设置请求地址
URL := "https://api.mch.weixin.qq.com/v3/smartguide/guides"
//设置请求信息,此处也可以使用结构体来进行请求
mapInfo := map[string]interface{}{
"store_id": 1234,
"corpid": "1234567890",
"name": "pVd1HJ6v/69bDnuC4EL5Kz4jBHLiCa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg==",
"mobile": "pVd1HJ6v/69bDnuC4EL5Kz4jBHLiCa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg==",
"qr_code": "https://open.work.weixin.qq.com/wwopen/userQRCode?vcode=xxx",
"sub_mchid": "1234567890",
"avatar": "http://wx.qlogo.cn/mmopen/ajNVdqHZLLA3WJ6DSZUfiakYe37PKnQhBIeOQBO4czqrnZDS79FH5Wm5m4X69TBicnHFlhiafvDwklOpZeXYQQ2icg/0",
"group_qrcode": "http://p.qpic.cn/wwhead/nMl9ssowtibVGyrmvBiaibzDtp/0",
"userid": "robert",
}
// 发起请求
response, err := client.Post(ctx, URL, mapInfo)
if err != nil{
log.Printf("client post err:%s",err)
return
}
// 校验回包内容是否有逻辑错误
err = core.CheckResponse(response)
if err != nil{
log.Printf("check response err:%s",err)
return
}
// 读取回包信息
body, err := ioutil.ReadAll(response.Body)
if err != nil{
log.Printf("read response body err:%s",err)
return
}
fmt.Println(string(body))
}
重要入参说明:
• store_id:门店在微信支付商户平台的唯一标识(查找路径:登录商户平台—>营销中心—>门店管理,若无门店则需先创建门店)
• name:员工在商户企业微信通讯录上的姓名,需使用微信支付平台公钥加密该字段需进行加密处理,加密方法详见敏感信息加密说明。特殊规则:加密前字段长度限制为64个字节
更多参数、响应详情及错误码请参见服务人员注册API接口文档
3.2.2.【服务端】服务人员分配
步骤说明:服务人员分配接口用于商户开发者在顾客下单后为顾客分配服务人员使用。
注意:
调用服务人员分配接口需在完成支付之前,若分配服务人员晚于支付完成,则将无法在支付凭证上出现服务人员名片入口。
示例代码:
public void AssignGuide() throws Exception{
//请求URL
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/smartguide/guides/LLA3WJ6DSZUfiaZDS79FH5Wm5m4X69TBic/assign");
// 请求body参数
String reqdata = "{"
+ "\"out_trade_no\":\"20150806125346\""
+ "\"sub_mchid\":\"1234567890\""
+ "}";
StringEntity entity = new StringEntity(reqdata,"utf-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
httpPost.setHeader("Accept", "application/json");
//完成签名并执行请求
CloseableHttpResponse response = httpClient.execute(httpPost);
try {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) { //处理成功
System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
} else if (statusCode == 204) { //处理成功,无返回Body
System.out.println("success");
} else {
System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
throw new IOException("request failed");
}
} finally {
response.close();
}
}
try {
$resp = $client->request(
'POST',
'https://api.mch.weixin.qq.com/v3/smartguide/guides/LLA3WJ6DSZUfiaZDS79FH5Wm5m4X69TBic/assign', //请求URL
[
// JSON请求体
'json' => [
"out_trade_no" => "20150806125346",
"sub_mchid" => "1234567890",
],
'headers' => [ 'Accept' => 'application/json' ]
]
);
$statusCode = $resp->getStatusCode();
if ($statusCode == 200) { //处理成功
echo "success,return body = " . $resp->getBody()->getContents()."\n";
} else if ($statusCode == 204) { //处理成功,无返回Body
echo "success";
}
} catch (RequestException $e) {
// 进行错误处理
echo $e->getMessage()."\n";
if ($e->hasResponse()) {
echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
}
return;
}
func AssignGuide() {
// 初始化客户端
ctx := context.TODO()
opts, err := SetUp()
if err != nil {
return
}
client, err := core.NewClient(ctx, opts...,)
if err != nil{
log.Printf("init client err:%s",err)
return
}
//设置请求地址
//设置请求地址
URL := "https://api.mch.weixin.qq.com/v3/smartguide/guides/LLA3WJ6DSZUfiaZDS79FH5Wm5m4X69TBic/assign"
//设置请求信息,此处也可以使用结构体来进行请求
mapInfo := map[string]interface{}{
"out_trade_no": "20150806125346",
"sub_mchid": "1234567890",
}
// 发起请求
response, err := client.Post(ctx, URL, mapInfo)
if err != nil{
log.Printf("client post err:%s",err)
return
}
// 校验回包内容是否有逻辑错误
err = core.CheckResponse(response)
if err != nil{
log.Printf("check response err:%s",err)
return
}
// 读取回包信息
body, err := ioutil.ReadAll(response.Body)
if err != nil{
log.Printf("read response body err:%s",err)
return
}
fmt.Println(string(body))
}
重要入参说明:
• out_trade_no:商户系统内部订单号,要求32个字符内,仅支持使用字母、数字、中划线-、下划线_、竖线|、星号*这些英文半角字符的组合,请勿使用汉字或全角等特殊字符,且在同一个商户号下唯一。
更多参数、响应详情及错误码请参见服务人员分配API接口文档
3.2.3.【服务端】服务人员查询
步骤说明:服务人员查询接口用于商户开发者查询已注册的服务人员ID等信息。
注意:
个人微信商家
传入门店ID,查询该门店下的所有已注册服务人员的信息(每次查询不可超过10条)
传入服务人员的工号(服务人员注册时填写)或手机号,查询单个服务人员的信息。
企业微信商家
传入门店ID,查询该门店下的所有已注册服务人员的信息(每次查询不可超过10条)
传入服务人员的企业微信员工ID或手机号,查询单个服务人员的信息。
服务人员注册API和查询API请求URL相同,区别主要是在body和query,请注意区分。
示例代码:
public void QueryGuide() throws Exception{
//请求URL
HttpGet httpGet = new HttpGet("https://api.mch.weixin.qq.com/v3/smartguide/guides?store_id=1234&sub_mchid=1234567890");
httpGet.setHeader("Accept", "application/json");
//完成签名并执行请求
CloseableHttpResponse response = httpClient.execute(httpGet);
try {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) { //处理成功
System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
} else if (statusCode == 204) { //处理成功,无返回Body
System.out.println("success");
} else {
System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
throw new IOException("request failed");
}
} finally {
response.close();
}
}
try {
$resp = $client->request(
'GET',
'https://api.mch.weixin.qq.com/v3/smartguide/guides?store_id=1234&=sub_mch=1234567890', //请求URL
[
'headers' => [ 'Accept' => 'application/json']
]
);
$statusCode = $resp->getStatusCode();
if ($statusCode == 200) { //处理成功
echo "success,return body = " . $resp->getBody()->getContents()."\n";
} else if ($statusCode == 204) { //处理成功,无返回Body
echo "success";
}
} catch (RequestException $e) {
// 进行错误处理
echo $e->getMessage()."\n";
if ($e->hasResponse()) {
echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
}
return;
}
func QueryGuide() {
// 初始化客户端
ctx := context.TODO()
opts, err := SetUp()
if err != nil {
return
}
client, err := core.NewClient(ctx, opts...,)
if err != nil{
log.Printf("init client err:%s",err)
return
}
//设置请求地址
URL := "
https://api.mch.weixin.qq.com/v3/smartguide/guides?store_id=1234&sub_mchid=1234567890"
// 发起请求
response, err := client.Get(ctx, URL)
if err != nil{
log.Printf("client get err:%s",err)
return
}
// 校验回包内容是否有逻辑错误
err = core.CheckResponse(response)
if err != nil{
log.Printf("check response err:%s",err)
return
}
// 读取回包信息
body, err := ioutil.ReadAll(response.Body)
if err != nil{
log.Printf("read response body err:%s",err)
return
}
fmt.Println(string(body))
}
重要入参说明:
• userid:员工在商户企业微信通讯录使用的唯一标识,企业微信商家可传入该字段查询单个服务人员信息;不传则查询整个门店下的服务人员信息。
更多参数、响应详情及错误码请参见服务人员查询API接口文档
3.2.4.【服务端】服务人员信息更新
步骤说明:服务人员信息更新接口用于商户开发者为商户更新门店服务人员的姓名、头像等信息。
注意:
个人微信商家、企业微信商家均支持服务人员信息更新
示例代码:
public void UpdateGuide() throws Exception{
//请求URL
HttpPatch httpPatch = new HttpPatch("https://api.mch.weixin.qq.com/v3/smartguide/guides/LLA3WJ6DSZUfiaZDS79FH5Wm5m4X69TBic");
// 请求body参数
String reqdata = "{"
+
"\"sub_mchid\":\"1234567890\","
+
"\"name\":\"pVd1HJ6v/69bDnuC4EL5Kz4jBHLiCa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg==\","
+ "\"mobile\":\"pVd1HJ6v/69bDnuC4EL5Kz4jBHLiCa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg==\","
+ "\"qr_code\":\"https://open.work.weixin.qq.com/wwopen/userQRCode?vcode=xxx\","
+ "\"avatar\":\"http://wx.qlogo.cn/mmopen/ajNVdqHZLLA3WJ6DSZUfiakYe37PKnQhBIeOQBO4czqrnZDS79FH5Wm5m4X69TBicnHFlhiafvDwklOpZeXYQQ2icg/0\","
+ "\"group_qrcode\":\"http://p.qpic.cn/wwhead/nMl9ssowtibVGyrmvBiaibzDtp/0\""
+ "}";
StringEntity entity = new StringEntity(reqdata,"utf-8");
entity.setContentType("application/json");
httpPatch.setEntity(entity);
httpPatch.setHeader("Accept", "application/json");
//完成签名并执行请求
CloseableHttpResponse response = httpClient.execute(httpPatch);
try {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) { //处理成功
System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
} else if (statusCode == 204) { //处理成功,无返回Body
System.out.println("success");
} else {
System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
throw new IOException("request failed");
}
} finally {
response.close();
}
}
try {
$resp = $client->request(
'PATCH',
'https://api.mch.weixin.qq.com/v3/smartguide/guides/LLA3WJ6DSZUfiaZDS79FH5Wm5m4X69TBic', //请求URL
[
// JSON请求体
'json' => [
"name" => "pVd1HJ6v/69bDnuC4EL5Kz4jBHLiCa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg==",
"mobile" => "pVd1HJ6v/69bDnuC4EL5Kz4jBHLiCa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg==",
"qr_code" => "https://open.work.weixin.qq.com/wwopen/userQRCode?vcode=xxx",
"avatar" => "http://wx.qlogo.cn/mmopen/ajNVdqHZLLA3WJ6DSZUfiakYe37PKnQhBIeOQBO4czqrnZDS79FH5Wm5m4X69TBicnHFlhiafvDwklOpZeXYQQ2icg/0",
"group_qrcode" => "http://p.qpic.cn/wwhead/nMl9ssowtibVGyrmvBiaibzDtp/0",
"sub_mchid" => "1234567890",
],
'headers' => [ 'Accept' => 'application/json' ]
]
);
$statusCode = $resp->getStatusCode();
if ($statusCode == 200) { //处理成功
echo "success,return body = " . $resp->getBody()->getContents()."\n";
} else if ($statusCode == 204) { //处理成功,无返回Body
echo "success";
}
} catch (RequestException $e) {
// 进行错误处理
echo $e->getMessage()."\n";
if ($e->hasResponse()) {
echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
}
return;
}
//此处请求头需增加序列号
func UpdateGuide() {
// 初始化客户端
ctx := context.TODO()
opts, err := SetUp()
if err != nil {
return
}
client, err := core.NewClient(ctx, opts...,)
if err != nil{
log.Printf("init client err:%s",err)
return
}
//设置请求地址
URL := "https://api.mch.weixin.qq.com/v3/smartguide/guides/LLA3WJ6DSZUfiaZDS79FH5Wm5m4X69TBic"
//设置请求信息,此处也可以使用结构体来进行请求
mapInfo := map[string]interface{}{
"sub_mchid": "1234567890",
"name": "pVd1HJ6v/69bDnuC4EL5Kz4jBHLiCa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg==",
"mobile": "pVd1HJ6v/69bDnuC4EL5Kz4jBHLiCa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg==",
"qr_code": "https://open.work.weixin.qq.com/wwopen/userQRCode?vcode=xxx",
"avatar": "http://wx.qlogo.cn/mmopen/ajNVdqHZLLA3WJ6DSZUfiakYe37PKnQhBIeOQBO4czqrnZDS79FH5Wm5m4X69TBicnHFlhiafvDwklOpZeXYQQ2icg/0",
"group_qrcode": "http://p.qpic.cn/wwhead/nMl9ssowtibVGyrmvBiaibzDtp/0",
}
// 发起请求
response, err := client.Patch(ctx, URL, mapInfo)
if err != nil{
log.Printf("client patch err:%s",err)
return
}
// 校验回包内容是否有逻辑错误
err = core.CheckResponse(response)
if err != nil{
log.Printf("check response err:%s",err)
return
}
// 读取回包信息
body, err := ioutil.ReadAll(response.Body)
if err != nil{
log.Printf("read response body err:%s",err)
return
}
fmt.Println(string(body))
}
重要入参说明:
• guide_id:务人员在支付即服务系统中的唯一标识。
更多参数、响应详情及错误码请参见服务人员信息更新API接口文档
4. 常见问题
Q:使用服务人员注册API进行注册时,sub_mchid(子商户ID)应该传什么?
A:如果是普通特约商户自己调接口,不传即可;如果是服务商帮普通特约商户调接口,传普通特约商户的商户号
Q:企业微信的corpid如何获取?
A:获取corpid可进入企业微信的管理后台,查找路径:【我的企业->企业信息→查看“企业ID”】(需要有管理员权限)
Q:注册服务人员时必须传入门店ID吗?在哪里找这个门店ID
A:是的,注册时必须传入门店ID。该门店ID是微信支付门店系统的编码,查找路径:【登录商户平台->营销中心→门店管理】,门店管理页面下的门店编号即为需要填写的门店ID(该门店信息与企业微信的门店系统无关)。
若未创建门店,则需创建门店并通过腾讯地图审核后,方可使用门店ID进行注册。
Q:调用服务人员分配接口是在支付前还是支付后?
A:支付前。建议当商家生成当前交易的“商户订单号”时,通过“服务人员分配API”将“服务人员ID+商户订单号”传给微信支付,并按照原有流程引导用户完成支付即可。若分配服务人员晚于支付完成,则将无法在支付凭证上出现服务人员名片入口
Q:服务人员分配应该采取什么样的分配机制?
A:使用服务人员分配API进行分配时,服务人员的分配机制由商家内部闭环,可以灵活掌控。在支付前调用分配接口时,商家可自行决定分配哪名服务人员,商家可选择随机分配、按时间段分配,或为某笔订单指定特定服务人员的分配方式(例如在线下门店支付时,可分配当前为该顾客提供服务的服务人员)。使用免开发版本时,商户号下的所有订单将随机分配给不同服务人员,商家可通过小程序调整服务人员分配的时间段,但是不能针对不同订单分配特定的服务人员