开发指引
更新时间:2024.12.27# 1. 接口规则
为了在保证支付安全的前提下,带给商户简单、一致且易用的开发体验,我们推出了全新的微信支付APIv3接口。该版本API的具体规则请参考APIv3接口规则。
# 2. 开发准备
# 2.1. 搭建和配置开发环境
开发者应当依据自身的编程语言来构建并配置相应的开发环境。
# 2.2. 业务开发配置
# 2.2.1. 开通营销事件推送能力
开通营销事件推送能力说明:
- 用于设置接收商家券相关事件通知的URL,可接收商家券相关的事件通知、包括发放通知等。需要设置接收通知的URL,并在商户平台开通营销事件推送的能力,即可接收到相关通知。
- 营销事件推送:点击开通产品权限。 由商家券批次创建方登录Pay平台,操作开通。
# 3. 快速接入
# 3.1. 业务流程图
# 业务流程时序图
重点步骤说明:
步骤1 商户发起创建商家券请求,可通过《创建商家券》接口创建商家券,微信支付生成商家券批次后并返回商家券批次号给到商户。
请求参数商户logo(merchant_url)的内容要求使用图片上传(营销专用)接口上传后获取
步骤4.2 商户获取到商家券批次号,需要调用《小程序发券插件》来发放商户券,并获取微信支付返回商家券发放结果。
步骤7.2 商户发券成功后,商户可通过《查询商家券批次详情》、《根据过滤条件查询用户的券》、《查询用户券详情》等商家券管理接口进行券管理,商户需核销用户券时,可通过调用《核销用户的券》来核销用户微信卡包中具体某一张商家券。
# 3.2. API接入(含示例代码)
文档展示了如何使用微信支付服务端 SDK 快速接入商家券产品,完成与微信支付对接的部分。
注意
- 文档中的代码示例是用来阐述 API 基本使用方法,代码中的示例参数需替换成商户自己账号及请求参数才能跑通。
- 以下接入步骤仅提供参考,请商户结合自身业务需求进行评估、修改。
# 3.2.1. 【服务端】创建商家券
步骤说明: 通过此接口可为有需求的商户创建商家券。当前支持创建的商家券类型包含满减券、换购券和折扣券三种。
卡券背景颜色图:
商家券样式图:
券详情信息展示:
1public void CreateBusiStocks() throws Exception{2 //请求URL3 HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/marketing/busifavor/stocks");4 // 请求body参数5 String reqdata = "{"6 + "\"stock_name\":\"8月1日活动券\","7 + "\"belong_merchant\":\"1900008361\","8 + "\"comment\":\"活动使用\","9 + "\"goods_name\":\"填写代金券可适用的商品或服务\","10 + "\"stock_type\":\"NORMAL\","11 + "\"coupon_use_rule\": {"12 + "\"coupon_available_time\": {"13 + "\"available_begin_time\":\"2021-04-20T13:29:35+08:00\","14 + "\"available_end_time\":\"2021-04-25T13:29:35+08:00\","15 + "\"available_day_after_receive\":3,"16 + "\"wait_days_after_receive\":7"17 + "},"18 + "\"fixed_normal_coupon\": {"19 + "\"discount_amount\":5,"20 + "\"transaction_minimum\":100"21 + "},"22 + "\"use_method\":\"OFF_LINE\""23 + "},"24 + "\"stock_send_rule\": {"25 + "\"max_coupons\":100,"26 + "\"max_coupons_per_user\":5,"27 + "\"max_coupons_by_day\":100,"28 + "\"natural_person_limit\":false,"29 + "\"prevent_api_abuse\":false,"30 + "\"transferable\":false,"31 + "\"shareable\":false"32 + "},"33 + "\"out_request_no\":\"100002322019090134234sfdf\","34 + "\"coupon_code_mode\":\"WECHATPAY_MODE\""35 + "}";36 StringEntity entity = new StringEntity(reqdata,"utf-8");37 entity.setContentType("application/json");38 httpPost.setEntity(entity);39 httpPost.setHeader("Accept", "application/json");4041 //完成签名并执行请求42 CloseableHttpResponse response = httpClient.execute(httpPost);4344 try {45 int statusCode = response.getStatusLine().getStatusCode();46 if (statusCode == 200) { //处理成功47 System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));48 } else if (statusCode == 204) { //处理成功,无返回Body49 System.out.println("success");50 } else {51 System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));52 throw new IOException("request failed");53 }54 } finally {55 response.close();56 }57}
1try {2 $resp = $client->request(3 'POST',4 'https://api.mch.weixin.qq.com/v3/marketing/busifavor/stocks', //请求URL5 [6 // JSON请求体7 'json' => [8 "stock_name" => "8月1日活动券", 9 "belong_merchant" => "10000098", 10 "comment" => "活动使用", 11 "goods_name" => "填写代金券可适用的商品或服务", 12 "stock_type" => "NORMAL", 13 "coupon_use_rule" => [14 "coupon_available_time" => [15 "available_begin_time" => "2015-05-20T13:29:35+08:00", 16 "available_end_time" => "2015-05-20T13:29:35+08:00", 17 "available_day_after_receive" => 3, 18 "wait_days_after_receive" => 7, 19 "available_week" => [20 "week_day" => [21 "0" => 1, 22 "1" => 2, 23 ],24 "available_day_time" => [25 [26 "begin_time" => 3600, 27 "end_time" => 86399, 28 ],29 ],30 ],31 "irregulary_avaliable_time" => [32 [33 "begin_time" => "2015-05-20T13:29:35+08:00", 34 "end_time" => "2015-05-20T13:29:35+08:00", 35 ],36 ],37 ],38 "fixed_normal_coupon" => [39 "discount_amount" => 5, 40 "transaction_minimum" => 100, 41 ],42 "use_method" => "OFF_LINE", 43 "mini_programs_appid" => "wx23232232323", 44 "mini_programs_path" => "/path/index/index", 45 ],46 "stock_send_rule" => [47 "max_coupons" => 100, 48 "max_coupons_per_user" => 5, 49 "max_coupons_by_day" => 100, 50 "natural_person_limit" => false, 51 "prevent_api_abuse" => false, 52 "transferable" => false, 53 "shareable" => false, 54 ],55 "out_request_no" => "100002322019090134234sfdf", 56 "custom_entrance" => [57 "mini_programs_info" => [58 "mini_programs_appid" => "wx234545656765876", 59 "mini_programs_path" => "/path/index/index", 60 "entrance_words" => "欢迎选购", 61 "guiding_words" => "获取更多优惠", 62 ],63 "appid" => "wx324345hgfhfghfg", 64 "hall_id" => "233455656", 65 "store_id" => "233554655", 66 ],67 "display_pattern_info" => [68 "description" => "xxx门店可用", 69 "merchant_logo_url" => "https://xxx", 70 "merchant_name" => "微信支付", 71 "background_color" => "Color020", 72 "coupon_image_url" => "https://qpic.cn/xxx", 73 ],74 "coupon_code_mode" => "WECHATPAY_MODE",75 ],76 'headers' => [ 'Accept' => 'application/json' ]77 ]78 );79 $statusCode = $resp->getStatusCode();80 if ($statusCode == 200) { //处理成功81 echo "success,return body = " . $resp->getBody()->getContents()."\n";82 } else if ($statusCode == 204) { //处理成功,无返回Body83 echo "success";84 }85} catch (RequestException $e) {86 // 进行错误处理87 echo $e->getMessage()."\n";88 if ($e->hasResponse()) {89 echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";90 }91 return;92}
重要入参说明:
- belong_merchant: 批次归属商户号,批次归属于哪个商户。普通商户请填写普通商户号
- out_request_no: 商户请求单号,商户创建批次凭据号(格式:商户ID+日期+流水号),商户侧需保持唯一性。
- max_coupons: 批次最大发放个数,批次最大可发放个数限制。特殊规则:取值范围 1 ≤ value ≤ 1000000000。
- notify_appid: 事件通知AppID,用于回调通知时,计算返回操作用户的OpenID(诸如领券用户),支持小程序or公众号的AppID;如该字段不填写,则回调通知中涉及到用户身份信息的OpenID与unionid都将为空。
更多参数、响应详情及错误码请参见创建商家券接口文档。
# 3.2.2. 【服务端】查询商家券批次详情
步骤说明: 商户可通过该接口查询已创建的商家券批次详情信息。
卡券背景颜色图:
1public void GetBusiStocksInfo() throws Exception{2 //请求URL3 HttpGet httpGet = new HttpGet("https://api.mch.weixin.qq.com/v3/marketing/busifavor/stocks/1212");4 httpGet.setHeader("Accept", "application/json");56 //完成签名并执行请求7 CloseableHttpResponse response = httpClient.execute(httpGet);89 try {10 int statusCode = response.getStatusLine().getStatusCode();11 if (statusCode == 200) { //处理成功12 System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));13 } else if (statusCode == 204) { //处理成功,无返回Body14 System.out.println("success");15 } else {16 System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));17 throw new IOException("request failed");18 }19 } finally {20 response.close();21 }22}
1try {2 $resp = $client->request(3 'GET',4 'https://api.mch.weixin.qq.com/v3/marketing/busifavor/stocks/1212', //请求URL5 [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) { //处理成功,无返回Body13 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}
重要入参说明:
- stock_id: 批次号,微信为每个商家券批次分配的唯一ID。
更多参数、响应详情及错误码请参见查询商家券批次详情接口文档。
# 3.2.3. 【服务端】核销用户的券
步骤说明: 在用户满足优惠门槛后,商户可通过该接口核销用户微信卡包中具体某一张商家券。
1public void SetBusiStockUse() throws Exception{2 //请求URL3 HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/marketing/busifavor/coupons/use");4 // 请求body参数5 String reqdata = "{"6 + "\"coupon_code\":\"sxxe34343434\","7 + "\"stock_id\":\"100088\","8 + "\"appid\":\"wx1234567889999\","9 + "\"use_time\":\"2015-05-20T13:29:35+08:00\","10 + "\"use_request_no\":\"1002600620019090123143254435\","11 + "\"openid\":\"xsd3434454567676\""12 + "}";13 StringEntity entity = new StringEntity(reqdata,"utf-8");14 entity.setContentType("application/json");15 httpPost.setEntity(entity);16 httpPost.setHeader("Accept", "application/json");1718 //完成签名并执行请求19 CloseableHttpResponse response = httpClient.execute(httpPost);2021 try {22 int statusCode = response.getStatusLine().getStatusCode();23 if (statusCode == 200) { //处理成功24 System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));25 } else if (statusCode == 204) { //处理成功,无返回Body26 System.out.println("success");27 } else {28 System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));29 throw new IOException("request failed");30 }31 } finally {32 response.close();33 }34}
1try {2 $resp = $client->request(3 'POST',4 'https://api.mch.weixin.qq.com/v3/marketing/busifavor/coupons/use', //请求URL5 [6 // JSON请求体7 'json' => [8 "coupon_code" => "sxxe34343434", 9 "stock_id" => "100088", 10 "appid" => "wx1234567889999", 11 "use_time" => "2015-05-20T13:29:35+08:00", 12 "use_request_no" => "1002600620019090123143254435", 13 "openid" => "xsd3434454567676",14 ],15 'headers' => [ 'Accept' => 'application/json' ]16 ]17 );18 $statusCode = $resp->getStatusCode();19 if ($statusCode == 200) { //处理成功20 echo "success,return body = " . $resp->getBody()->getContents()."\n";21 } else if ($statusCode == 204) { //处理成功,无返回Body22 echo "success";23 }24} catch (RequestException $e) {25 // 进行错误处理26 echo $e->getMessage()."\n";27 if ($e->hasResponse()) {28 echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";29 }30 return;31}
重要入参说明:
- coupon_code: 券code,券的唯一标识。
- AppID: 公众账号ID,支持传入与当前调用接口商户号有绑定关系的AppID。支持小程序AppID与公众号AppID。核销接口返回的OpenID会在该传入AppID下进行计算获得。
- use_request_no: 核销请求单据号,每次核销请求的唯一标识,商户需保证唯一。
更多参数、响应详情及错误码请参见核销用户的券接口文档。
# 3.2.4. 【服务端】根据过滤条件查询用户券
步骤说明: 商户自定义筛选条件(如创建商户号、归属商户号、发放商户号等),查询指定微信用户卡包中满足对应条件的所有商家券信息。
1public void FilterUserStocks() throws Exception{2 //请求URL3 HttpGet httpGet = new HttpGet("https://api.mch.weixin.qq.com/v3/marketing/busifavor/users/o4GgauInH_RCEdvrrNGrntXDu6D4/coupons?appid=wx233544546545989&stock_id=9865000&coupon_state=USED&creator_merchant=1000000001&offset=0&limit=20");4 httpGet.setHeader("Accept", "application/json");56 //完成签名并执行请求7 CloseableHttpResponse response = httpClient.execute(httpGet);89 try {10 int statusCode = response.getStatusLine().getStatusCode();11 if (statusCode == 200) { //处理成功12 System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));13 } else if (statusCode == 204) { //处理成功,无返回Body14 System.out.println("success");15 } else {16 System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));17 throw new IOException("request failed");18 }19 } finally {20 response.close();21 }22}
1try {2 $resp = $client->request(3 'GET',4 'https://api.mch.weixin.qq.com/v3/marketing/busifavor/users/o4GgauInH_RCEdvrrNGrntXDu6D4/coupons?appid=wx233544546545989&stock_id=9865000&coupon_state=USED&creator_merchant=1000000001&offset=0&limit=20', //请求URL5 [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) { //处理成功,无返回Body13 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}
重要入参说明:
- OpenID: 用户标识,OpenID信息,用户在AppID下的唯一标识。
- AppID: 公众账号ID,支持传入与当前调用接口商户号有绑定关系的AppID。支持小程序AppID与公众号AppID。
更多参数、响应详情及错误码请参见根据过滤条件查询用户的券接口文档。
# 3.2.5. 【服务端】查询用户券详情
步骤说明: 商户可通过该接口查询微信用户卡包中某一张商家券的详情信息。
1public void FilterUserStocks() throws Exception{2 //请求URL3 HttpGet httpGet = new HttpGet("https://api.mch.weixin.qq.com/v3/marketing/busifavor/users/o4GgauInH_RCEdvrrNGrntXDu6D4/coupons/123446565767/appids/wx233544546545989");4 httpGet.setHeader("Accept", "application/json");56 //完成签名并执行请求7 CloseableHttpResponse response = httpClient.execute(httpGet);89 try {10 int statusCode = response.getStatusLine().getStatusCode();11 if (statusCode == 200) { //处理成功12 System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));13 } else if (statusCode == 204) { //处理成功,无返回Body14 System.out.println("success");15 } else {16 System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));17 throw new IOException("request failed");18 }19 } finally {20 response.close();21 }22}
1try {2 $resp = $client->request(3 'GET',4 'https://api.mch.weixin.qq.com/v3/marketing/busifavor/users/o4GgauInH_RCEdvrrNGrntXDu6D4/coupons/123446565767/appids/wx233544546545989', //请求URL5 [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) { //处理成功,无返回Body13 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}
重要入参说明:
- coupon_code: 券code,券的唯一标识。
- OpenID: 用户标识,OpenID信息,用户在AppID下的唯一标识。
- AppID: 公众账号ID,支持传入与当前调用接口商户号有绑定关系的AppID。支持小程序AppID与公众号AppID。
更多参数、响应详情及错误码请参见查询用户券详情接口文档。
# 3.2.6. 【服务端】上传预存code
步骤说明: 商家券的Code码可由微信后台随机分配,同时支持商户自定义。如商家已有自己的优惠券系统,可直接使用自定义模式。即商家预先向微信支付上传券Code,当券在发放时,微信支付自动从已导入的Code中随机取值(不能指定),派发给用户。
1public void UploadBusiStockCodes() throws Exception{2 //请求URL3 HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/marketing/busifavor/stocks/98065001/couponcodes");4 // 请求body参数5 String reqdata = "{"6 + "\"coupon_code_list\": ["7 + "\"0\":\"ABC9588200\","8 + "\"1\":\"ABC9588201\""9 + "],"10 + "\"upload_request_no\":\"100002322019090134234sfdf\""11 + "}";12 StringEntity entity = new StringEntity(reqdata,"utf-8");13 entity.setContentType("application/json");14 httpPost.setEntity(entity);15 httpPost.setHeader("Accept", "application/json");1617 //完成签名并执行请求18 CloseableHttpResponse response = httpClient.execute(httpPost);1920 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) { //处理成功,无返回Body25 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}
1try {2 $resp = $client->request(3 'POST',4 'https://api.mch.weixin.qq.com/v3/marketing/busifavor/stocks/98065001/couponcodes', //请求URL5 [6 // JSON请求体7 'json' => [8 "coupon_code_list" => [9 "0" => "ABC9588200", 10 "1" => "ABC9588201", 11 ],12 "upload_request_no" => "100002322019090134234sfdf",13 ],14 'headers' => [ 'Accept' => 'application/json' ]15 ]16 );17 $statusCode = $resp->getStatusCode();18 if ($statusCode == 200) { //处理成功19 echo "success,return body = " . $resp->getBody()->getContents()."\n";20 } else if ($statusCode == 204) { //处理成功,无返回Body21 echo "success";22 }23} catch (RequestException $e) {24 // 进行错误处理25 echo $e->getMessage()."\n";26 if ($e->hasResponse()) {27 echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";28 }29 return;30}
重要入参说明:
- stock_id: 批次号,微信为每个商家券批次分配的唯一ID。
- upload_request_no: 请求业务单据号,商户上传code的凭据号,商户侧需保持唯一性。
更多参数、响应详情及错误码请参见上传预存code接口文档。
# 3.2.7. 【服务端】设置商家券事件通知地址
步骤说明: 用于设置接收商家券相关事件通知的URL,可接收商家券相关的事件通知、包括发放通知等。需要设置接收通知的URL,并在商户平台开通营销事件推送的能力,即可接收到相关通知。
注意
- 仅可以收到由商户自己创建的批次相关的通知
- 需要设置APIv3密钥,否则无法收到回调。
- 如果需要领券回调中的参数OpenID。需要创券时候传入notify_appid参数。
1public void SetBusiStockCallback() throws Exception{2 //请求URL3 HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/marketing/busifavor/callbacks");4 // 请求body参数5 String reqdata = "{"6 + "\"mchid\":\"10000098\","7 + "\"notify_url\":\"https://pay.weixin.qq.com\""8 + "}";9 StringEntity entity = new StringEntity(reqdata,"utf-8");10 entity.setContentType("application/json");11 httpPost.setEntity(entity);12 httpPost.setHeader("Accept", "application/json");1314 //完成签名并执行请求15 CloseableHttpResponse response = httpClient.execute(httpPost);1617 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) { //处理成功,无返回Body22 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}
1try {2 $resp = $client->request(3 'POST',4 'https://api.mch.weixin.qq.com/v3/marketing/busifavor/callbacks', //请求URL5 [6 // JSON请求体7 'json' => [8 "mchid" => "10000098", 9 "notify_url" => "https://pay.weixin.qq.com",10 ],11 'headers' => [ 'Accept' => 'application/json' ]12 ]13 );14 $statusCode = $resp->getStatusCode();15 if ($statusCode == 200) { //处理成功16 echo "success,return body = " . $resp->getBody()->getContents()."\n";17 } else if ($statusCode == 204) { //处理成功,无返回Body18 echo "success";19 }20} catch (RequestException $e) {21 // 进行错误处理22 echo $e->getMessage()."\n";23 if ($e->hasResponse()) {24 echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";25 }26 return;27}
重要入参说明:
- notify_url: 通知URL地址,商户提供的用于接收商家券事件通知的URL地址,必须支持HTTPS。
更多参数、响应详情及错误码请参见设置商家券事件通知地址接口文档。
# 3.2.8. 【服务端】查询商家券事件通知地址
步骤说明: 通过调用此接口可查询设置的通知URL。
注意
- 仅可以查询由请求商户号设置的商家券通知URL。
1public void QueryBusiStockCallback() throws Exception {2 3 //请求URL4 HttpGet httpGet = new HttpGet("https://api.mch.weixin.qq.com/v3/marketing/busifavor/callbacks?mchid=10000098");5 httpGet.setHeader("Accept", "application/json");67 //完成签名并执行请求8 CloseableHttpResponse response = httpClient.execute(httpGet);910 try {11 int statusCode = response.getStatusLine().getStatusCode();12 if (statusCode == 200) { //处理成功13 System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));14 } else if (statusCode == 204) { //处理成功,无返回Body15 System.out.println("success");16 } else {17 System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));18 throw new IOException("request failed");19 }20 } finally {21 response.close();22 }23}
1try {2 $resp = $client->request(3 'GET',4 'https://api.mch.weixin.qq.com/v3/marketing/busifavor/callbacks?mchid=10000098', //请求URL5 [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) { //处理成功,无返回Body13 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}
重要入参说明:
- mchid: 商户号,微信支付商户的商户号,由微信支付生成并下发,不填默认查询调用方商户的通知URL。
更多参数、响应详情及错误码请参见查询商家券事件通知地址接口文档。
# 3.2.9. 【服务端】关联订单信息
步骤说明: 将有效态(未核销)的商家券与订单信息关联,用于后续参与摇奖&返佣激励等操作的统计。
注意
- 仅对有关联订单需求的券进行该操作。
1public void AssociateBusiStockOrder() throws Exception{2 //请求URL3 HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/marketing/busifavor/coupons/associate");4 // 请求body参数5 String reqdata = "{"6 + "\"coupon_code\":\"sxxe34343434\","7 + "\"out_trade_no\":\"MCH_102233445\","8 + "\"stock_id\":\"100088\","9 + "\"out_request_no\":\"1002600620019090123143254435\""10 + "}";11 StringEntity entity = new StringEntity(reqdata,"utf-8");12 entity.setContentType("application/json");13 httpPost.setEntity(entity);14 httpPost.setHeader("Accept", "application/json");1516 //完成签名并执行请求17 CloseableHttpResponse response = httpClient.execute(httpPost);1819 try {20 int statusCode = response.getStatusLine().getStatusCode();21 if (statusCode == 200) { //处理成功22 System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));23 } else if (statusCode == 204) { //处理成功,无返回Body24 System.out.println("success");25 } else {26 System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));27 throw new IOException("request failed");28 }29 } finally {30 response.close();31 }32}
1try {2 $resp = $client->request(3 'POST',4 'https://api.mch.weixin.qq.com/v3/marketing/busifavor/coupons/associate', //请求URL5 [6 // JSON请求体7 'json' => [8 "coupon_code" => "sxxe34343434", 9 "out_trade_no" => "MCH_102233445", 10 "stock_id" => "100088", 11 "out_request_no" => "1002600620019090123143254435",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) { //处理成功,无返回Body20 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}
重要入参说明:
- stock_id: 批次号,微信为每个商家券批次分配的唯一ID。
- coupon_code: 券code,券的唯一标识。
- out_trade_no: 关联的商户订单号,微信支付下单时的商户订单号,预与该商家券关联的微信支付。
- out_request_no: 商户请求单号,商户创建批次凭据号(格式:商户ID+日期+流水号),商户侧需保持唯一性,可包含英文字母,数字,|,_,*,-等内容,不允许出现其他不合法符号。
更多参数、响应详情及错误码请参见关联订单信息接口文档。
# 3.2.10. 【服务端】取消关联订单信息
步骤说明: 取消商家券与订单信息的关联关系。
注意
- 建议取消前调用查询接口,查到当前关联的商户单号并确认后,再进行取消操作。
1public void CancelAssociateBusiStockOrder() throws Exception {2//请求URL3 HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/marketing/busifavor/coupons/disassociate");4 // 请求body参数5 String reqdata = "{"6 + "\"coupon_code\":\"213dsadfsa\","7 + "\"out_trade_no\":\"treads8a9f980\","8 + "\"stock_id\":\"100088\","9 + "\"out_request_no\":\"fdsafdsafdsa231321\""10 + "}";11 StringEntity entity = new StringEntity(reqdata,"utf-8");12 entity.setContentType("application/json");13 httpPost.setEntity(entity);14 httpPost.setHeader("Accept", "application/json");1516 //完成签名并执行请求17 CloseableHttpResponse response = httpClient.execute(httpPost);1819 try {20 int statusCode = response.getStatusLine().getStatusCode();21 if (statusCode == 200) { //处理成功22 System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));23 } else if (statusCode == 204) { //处理成功,无返回Body24 System.out.println("success");25 } else {26 System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));27 throw new IOException("request failed");28 }29 } finally {30 response.close();31 }32}
1try {2 $resp = $client->request(3 'POST',4 'https://api.mch.weixin.qq.com/v3/marketing/busifavor/coupons/disassociate', //请求URL5 [6 // JSON请求体7 'json' => [8 "coupon_code" => "213dsadfsa", 9 "out_trade_no" => "treads8a9f980", 10 "stock_id" => "100088", 11 "out_request_no" => "fdsafdsafdsa231321",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) { //处理成功,无返回Body20 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}
重要入参说明:
- stock_id: 批次号,微信为每个商家券批次分配的唯一ID
- coupon_code: 券code,券的唯一标识。
- out_trade_no: 关联的商户订单号,微信支付下单时的商户订单号,预与该商家券关联的微信支付
- **out_request_no:**商户请求单号,商户创建批次凭据号(格式:商户ID+日期+流水号),商户侧需保持唯一性,可包含英文字母,数字,|,_,*,-等内容,不允许出现其他不合法符号。
更多参数、响应详情及错误码请参见取消关联订单信息接口文档
# 3.2.11. 【服务端】修改批次预算
步骤说明: 商户可以通过该接口修改批次单天发放上限数量或者批次最大发放数量
1public void UpdataBusiStockBudget() throws Exception{2 //请求URL3 HttpPatch httpPatch = new HttpPatch("https://api.mch.weixin.qq.com/v3/marketing/busifavor/stocks/98065001/budget");4 // 请求body参数5 String reqdata = "{"6 + "\"target_max_coupons\":3000,"7 + "\"current_max_coupons\":500,"8 + "\"modify_budget_request_no\":\"1002600620019090123143254436\""9 + "}";10 StringEntity entity = new StringEntity(reqdata,"utf-8");11 entity.setContentType("application/json");12 httpPatch.setEntity(entity);13 httpPatch.setHeader("Accept", "application/json");1415 //完成签名并执行请求16 CloseableHttpResponse response = httpClient.execute(httpPatch);1718 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) { //处理成功,无返回Body23 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}
1try {2 $resp = $client->request(3 'PATCH',4 'https://api.mch.weixin.qq.com/v3/marketing/busifavor/stocks/98065001/budget', //请求URL5 [6 // JSON请求体7 'json' => [8 "target_max_coupons" => 3000, 9 "current_max_coupons" => 500, 10 "modify_budget_request_no" => "1002600620019090123143254436",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) { //处理成功,无返回Body19 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}
重要入参说明:
- stock_id: 批次号,微信为每个商家券批次分配的唯一ID。
- modify_budget_request_no: 修改预算请求单据号(格式:商户ID+日期+流水号),商户侧需保持唯一性。
更多参数、响应详情及错误码请参见修改批次预算接口文档。
# 3.2.12. 【服务端】修改商家券基本信息
步骤说明: 商户可以通过该接口修改商家券基本信息。
1public void UpdataBusiStockInfo() throws Exception{2 //请求URL3 HttpPatch httpPatch = new HttpPatch("https://api.mch.weixin.qq.com/v3/marketing/busifavor/stocks/101156451224");4 // 请求body参数5 String reqdata = "{"6 + "\"custom_entrance\": {"7 + "\"mini_programs_info\": {"8 + "\"mini_programs_appid\":\"wx234545656765876\","9 + "\"mini_programs_path\":\"/path/index/index\","10 + "\"entrance_words\":\"欢迎选购\","11 + "\"guiding_words\":\"获取更多优惠\""12 + "},"13 + "\"appid\":\"wx324345hgfhfghfg\","14 + "\"hall_id\":\"233455656\","15 + "\"code_display_mode\":\"BARCODE\""16 + "},"17 + "\"stock_name\":\"8月1日活动券\","18 + "\"comment\":\"活动使用\","19 + "\"goods_name\":\"xxx商品使用\","20 + "\"out_request_no\":\"6122352020010133287985742\","21 + "\"display_pattern_info\": {"22 + "\"description\":\"xxx门店可用\","23 + "\"merchant_logo_url\":\"https://xxx\","24 + "\"merchant_name\":\"微信支付\","25 + "\"background_color\":\"xxxxx\","26 + "\"coupon_image_url\":\"图片cdn地址\""27 + "},"28 + "\"coupon_use_rule\": {"29 + "\"use_method\":\"OFF_LINE\","30 + "\"mini_programs_appid\":\"wx23232232323\","31 + "\"mini_programs_path\":\"/path/index/index\""32 + "},"33 + "\"stock_send_rule\": {"34 + "\"prevent_api_abuse\":false"35 + "},"36 + "\"notify_config\": {"37 + "\"notify_appid\":\"wx23232232323\""38 + "}"39 + "}";40 StringEntity entity = new StringEntity(reqdata,"utf-8");41 entity.setContentType("application/json");42 httpPatch.setEntity(entity);43 httpPatch.setHeader("Accept", "application/json");4445 //完成签名并执行请求46 CloseableHttpResponse response = httpClient.execute(httpPatch);4748 try {49 int statusCode = response.getStatusLine().getStatusCode();50 if (statusCode == 200) { //处理成功51 System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));52 } else if (statusCode == 204) { //处理成功,无返回Body53 System.out.println("success");54 } else {55 System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));56 throw new IOException("request failed");57 }58 } finally {59 response.close();60 }61}
1try {2 $resp = $client->request(3 'PATCH',4 'https://api.mch.weixin.qq.com/v3/marketing/busifavor/stocks/101156451224', //请求URL5 [6 // JSON请求体7 'json' => [8 "custom_entrance" => [9 "mini_programs_info" => [10 "mini_programs_appid" => "wx234545656765876", 11 "mini_programs_path" => "/path/index/index", 12 "entrance_words" => "欢迎选购", 13 "guiding_words" => "获取更多优惠", 14 ],15 "appid" => "wx324345hgfhfghfg", 16 "hall_id" => "233455656", 17 "code_display_mode" => "BARCODE", 18 ],19 "stock_name" => "8月1日活动券", 20 "comment" => "活动使用", 21 "goods_name" => "xxx商品使用", 22 "out_request_no" => "6122352020010133287985742", 23 "display_pattern_info" => [24 "description" => "xxx门店可用", 25 "merchant_logo_url" => "https://xxx", 26 "merchant_name" => "微信支付", 27 "background_color" => "xxxxx", 28 "coupon_image_url" => "图片cdn地址", 29 ],30 "coupon_use_rule" => [31 "use_method" => "OFF_LINE", 32 "mini_programs_appid" => "wx23232232323", 33 "mini_programs_path" => "/path/index/index", 34 ],35 "stock_send_rule" => [ 36 "prevent_api_abuse" => false, 37 ],38 "notify_config" => [39 "notify_appid" => "wx23232232323", 40 ]41 ],42 'headers' => [ 'Accept' => 'application/json' ]43 ]44 );45 $statusCode = $resp->getStatusCode();46 if ($statusCode == 200) { //处理成功47 echo "success,return body = " . $resp->getBody()->getContents()."\n";48 } else if ($statusCode == 204) { //处理成功,无返回Body49 echo "success";50 }51} catch (RequestException $e) {52 // 进行错误处理53 echo $e->getMessage()."\n";54 if ($e->hasResponse()) {55 echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";56 }57 return;58}
重要入参说明:
- stock_id: 批次号,微信为每个商家券批次分配的唯一ID。
- out_request_no: 商户请求单号,商户修改批次凭据号(格式:商户ID+日期+流水号),商户侧需保持唯一性。
更多参数、响应详情及错误码请参见修改商家券基本信息接口文档。
# 3.2.13. 【服务端】申请退券
步骤说明: 商户可以通过该接口为已核销的券申请退券。
1public void ReturnBusiStock() throws Exception{2 //请求URL3 HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/marketing/busifavor/coupons/return");4 // 请求body参数5 String reqdata = "{"6 + "\"coupon_code\":\"sxxe34343434\","7 + "\"stock_id\":\"1234567891\","8 + "\"return_request_no\":\"1002600620019090123143254436\""9 + "}";10 StringEntity entity = new StringEntity(reqdata,"utf-8");11 entity.setContentType("application/json");12 httpPost.setEntity(entity);13 httpPost.setHeader("Accept", "application/json");1415 //完成签名并执行请求16 CloseableHttpResponse response = httpClient.execute(httpPost);1718 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) { //处理成功,无返回Body23 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}
1try {2 $resp = $client->request(3 'POST',4 'https://api.mch.weixin.qq.com/v3/marketing/busifavor/coupons/return', //请求URL5 [6 // JSON请求体7 'json' => [8 "coupon_code" => "sxxe34343434", 9 "stock_id" => "1234567891", 10 "return_request_no" => "1002600620019090123143254436",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) { //处理成功,无返回Body19 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}
重要入参说明:
- stock_id: 批次号,微信为每个商家券批次分配的唯一ID
- coupon_code: 券code,券的唯一标识。
- return_request_no: 退券请求单据号,每次退券请求的唯一标识,商户需保证唯一。
更多参数、响应详情及错误码请参见申请退券接口文档。
# 3.2.14. 【服务端】使券失效
步骤说明: 商户可通过该接口将单张领取后未核销的券进行失效处理。
1public void DeactivateBusiStock() throws Exception{2 //请求URL3 HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/marketing/busifavor/coupons/deactivate");4 // 请求body参数5 String reqdata = "{"6 + "\"coupon_code\":\"sxxe34343434\","7 + "\"stock_id\":\"1234567891\","8 + "\"deactivate_request_no\":\"1002600620019090123143254436\","9 + "\"deactivate_reason\":\"此券使用时间设置错误\""10 + "}";11 StringEntity entity = new StringEntity(reqdata,"utf-8");12 entity.setContentType("application/json");13 httpPost.setEntity(entity);14 httpPost.setHeader("Accept", "application/json");1516 //完成签名并执行请求17 CloseableHttpResponse response = httpClient.execute(httpPost);1819 try {20 int statusCode = response.getStatusLine().getStatusCode();21 if (statusCode == 200) { //处理成功22 System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));23 } else if (statusCode == 204) { //处理成功,无返回Body24 System.out.println("success");25 } else {26 System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));27 throw new IOException("request failed");28 }29 } finally {30 response.close();31 }32}
1try {2 $resp = $client->request(3 'POST',4 'https://api.mch.weixin.qq.com/v3/marketing/busifavor/coupons/deactivate', //请求URL5 [6 // JSON请求体7 'json' => [8 "coupon_code" => "sxxe34343434", 9 "stock_id" => "1234567891", 10 "deactivate_request_no" => "1002600620019090123143254436", 11 "deactivate_reason" => "此券使用时间设置错误",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) { //处理成功,无返回Body20 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}
重要入参说明:
- stock_id: 批次号,微信为每个商家券批次分配的唯一ID。
- coupon_code: 券code,券的唯一标识。
- deactivate_request_no: 失效请求单据号,每次失效请求的唯一标识,商户需保证唯一。
更多参数、响应详情及错误码请参见使券失效接口文档。
# 3.2.15.【服务端】领券事件回调通知
步骤说明: 领券完成后,微信会把相关领券结果和用户信息发送给商户,商户需要接收处理,并按照文档规范返回应答。出于安全的考虑,我们对支付结果数据进行了加密,商户需要先对通知数据进行解密,才能得到支付结果数据。
注意
- 领券事件通知是以POST 方法访问商户设置的通知URL,通知的数据以JSON 格式通过请求主体(BODY)传输。通知的数据包括了加密的支付结果详情。
- 加密不能保证通知请求来自微信。微信会对发送给商户的通知进行签名,并将签名值放在通知的HTTP头Wechatpay-Signature。商户应当验证签名,以确认请求来自微信,而不是其他的第三方。签名验证的算法请参考 《微信支付API v3签名验证》。
- 支付通知HTTP应答码为200或204才会当作正常接收,当回调处理异常时,应答的HTTP状态码应为500,或者4xx。
- 商户成功接收到回调通知后应返回成功的HTTP应答码为200或204。
- 同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。 推荐的做法是,当商户系统收到通知进行处理时,先检查对应业务数据的状态,并判断该通知是否已经处理。如果未处理,则再进行处理;如果已处理,则直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱
- 对后台通知交互时,如果微信收到应答不是成功或超时,微信认为通知失败,微信会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但微信不保证通知最终能成功。(通知频率为60s/次 - 总计11次 )
更多参数、响应详情及错误码请参见 领券事件回调通知接口文档。
# 4. 常见问题
# Q:调用创建商家券接口返回“非法敏感图片”
A:请求参数商户logo(merchant_url)的内容要求使用图片上传(营销专用)接口上传后获取,请检查确认。
# Q:创建商家券接口,goods_name字段展示在哪里?
A:展示在商家券详情里面的优惠说明中。
# Q:调用修改商家券基本信息API返回:无法将输入源“/body/stock_id”映射到目标字段“批次号”中,此字段并非多重字段但被输入源“/uri_template/stock_id”映射过了
A:请注意参数stock_id传到请求URL里面,body里面就不用传该参数。
# Q:商家券领券回调,正常设置地址,为什么接收不到回调信息?
A:请按以下几点检查
- 请检查是否有正确设置APIv3。设置步骤如下: 【微信商户平台 (opens new window)—>账户设置—>API安全—>设置APIv3】
- 请检查回调URL是否能正常公网访问
- 如果是HTTP地址,建议更换支持HTTPS
- 是否开启了防火墙,如果开户了防火墙,请添加微信支付营销回调IP:
- 上海电信出口网段 101.226.103.0/2
- 上海联通出口网段 140.207.54.0/25
- 上海CAP出口网段 121.51.58.128/25
# Q:商家券消费门槛字段transaction_minimum不填写为什么会报错?
A:该字段属于必填字段,可以填写为0。