创建商家券
更新时间:2024.11.18商户可以通过该接口创建商家券。微信支付生成商家券批次后并返回商家券批次号给到商户,商户可调用发券接口【小程序发券】、【H5发券】发放该批次商家券。
频率限制:接口级限制1000/min
接口说明
支持商户:【普通服务商】 【渠道商】
请求方式:【POST】/v3/marketing/busifavor/stocks
请求域名:【主域名】https://api.mch.weixin.qq.com 使用该域名将访问就近的接入点
【备域名】https://api2.mch.weixin.qq.com 使用该域名将访问异地的接入点 ,指引点击查看
请求参数
Header HTTP头参数
Authorization 必填 string
请参考签名认证生成认证信息
Accept 必填 string
请设置为application/json
Content-Type 必填 string
请设置为application/json
body 包体参数
stock_name 必填 string(21)
【商家券批次名称】批次名称,字数上限为21个,一个中文汉字/英文字母/数字均占用一个字数。
belong_merchant 必填 string(15)
【批次归属商户号】批次归属于哪个商户。
注:
普通直连模式,该参数为直连商户号;
服务商模式,该参数为子商户号;
间连模式,该参数为子商户号。
comment 选填 string(20)
【批次备注】仅配置商户可见,用于自定义信息。字数上限为20个,一个中文汉字/英文字母/数字均占用一个字数。
goods_name 必填 string(15)
【适用商品范围】用来描述批次在哪些商品可用,会显示在微信卡包中。字数上限为15个,一个中文汉字/英文字母/数字均占用一个字数。
stock_type 必填 string
【批次类型】批次类型
可选取值:
NORMAL
: 固定面额满减券批次DISCOUNT
: 折扣券批次EXCHANGE
: 换购券批次
coupon_use_rule 必填 object
【核销规则】券核销相关规则
属性 | |||||||||||||||||||||||||||||
coupon_available_time 必填 object 【券可核销时间】日期区间内可以使用优惠
fixed_normal_coupon 选填 object 【固定面额满减券使用规则】固定面额满减,折扣券,换购券使用规则三选一,stock_type为NORMAL时必填。
discount_coupon 选填 object 【折扣券使用规则】固定面额满减,折扣券,换购券使用规则三选一,stock_type为DISCOUNT时必填。
exchange_coupon 选填 object 【换购券使用规则】固定面额满减,折扣券,换购券使用规则三选一,stock_type为EXCHANGE时必填。
use_method 必填 string 【核销方式】核销方式 可选取值:
mini_programs_appid 选填 string 【小程序AppID】核销方式为线上小程序核销才有效 mini_programs_path 选填 string 【小程序path】核销方式为线上小程序核销才有效 |
stock_send_rule 必填 object
【发放规则】券发放相关规则
属性 | |
max_amount 选填 integer 【批次总预算】总预算金额,单位分 max_coupons 选填 integer 【批次最大发放个数】批次最大可发放个数限制 max_coupons_per_user 必填 integer 【用户最大可领个数】用户可领个数,每个用户最多100张券。 max_amount_by_day 选填 integer 【单天发放上限金额】单天发放上限金额 max_coupons_by_day 选填 integer 【单天发放上限个数】单天发放上限个数(stock_type为DISCOUNT或EXCHANGE时可传入此字段控制单天发放上限)。 natural_person_limit 选填 boolean 【是否开启自然人限领】不填默认否,枚举值: prevent_api_abuse 选填 boolean 【可疑账号拦截】true-是;false-否,不填默认否 transferable 选填 boolean 【是否允许转赠,暂不开放】不填默认否,枚举值: shareable 选填 boolean 【是否允许分享链接,暂不开放】不填默认否,枚举值: |
out_request_no 必填 string(128)
【商户请求单号】商户创建批次凭据号(格式:商户ID+日期+流水号),商户侧需保持唯一性
custom_entrance 选填 object
【自定义入口】卡详情页面,可选择多种入口引导用户
属性 | |||||
mini_programs_info 选填 object 【小程序入口】需要小程序APPID、path、入口文案、引导文案。如果需要跳转小程序,APPID、path、入口文案为必填,引导文案非必填。
appid 选填 string 【商户公众号AppID】可配置商户公众号,从券详情可跳转至公众号,用户自定义字段。 hall_id 选填 string 【更多优惠入口;营销馆创建地址:https://pay.weixin.qq.com/index.php/xphp/cfav_market/hall#/pages/list/list】填写微信支付营销馆的馆ID,用户自定义字段。营销馆需在商户平台创建。 store_id 选填 string 【可用门店ID】填写代金券可用门店ID code_display_mode 选填 string 【code展示模式】code展示模式 可选取值:
|
display_pattern_info 选填 object
【样式信息】创建批次时的样式信息。
属性 | |||||
description 选填 string(1000) 【使用须知】用于说明详细的活动规则,会展示在代金券详情页。 merchant_logo_url 选填 string 【商户logo】若券归属商户号有认证品牌,则系统将自动拉取对应品牌logo;若券归属商户号不在认证品牌下,需自定义上传logo,未上传时将展示兜底灰色logo样式,影响券详情页用户体验,请及时上传。 商户logo的URL地址,仅支持通过《图片上传API》接口获取的图片URL地址。 1、商户logo大小需为120像素*120像素。 2、支持JPG/JPEG/PNG格式,且图片小于1M。 注:该字段暂不支持修改 merchant_name 选填 string(16) 【商户名称】不支持商户自定义。若券归属商户号有认证品牌,系统将自动拉取认证品牌号下的品牌名称;若券归属商户号不在认证品牌下,则拉取本商户号的商户简称。展示上限12个字符。 background_color 选填 string 【背景颜色】券的背景颜色,可设置10种颜色,色值请参考下方说明。颜色取值为颜色图中的颜色名称。
coupon_image_url 选填 string 【券详情图片】券详情图片,1074像素(宽)*603像素(高),图片大小不超过2M,支持JPG/PNG格式。仅支持通过《图片上传API》接口获取的图片URL地址。* finder_info 选填 object 【视频号相关信息】视频号相关信息
|
coupon_code_mode 必填 string
【券code模式】特殊规则:
1、券code模式为WECHATPAY_MODE时,是微信自动分配券code,商户不需要预存code;适用于多种场景
2、券code模式为MERCHANT_API时,无需调用上传预存code接口,调用发券接口时需指定券code;更多用在商家自有流量场景(例如:商家自有小程序、H5网页等)
3、券code模式为MERCHANT_UPLOAD,需要调用上传预存code接口上传code,调用发券接口时无需指定code;更多适用在微信支付平台流量场景(例如:支付有礼、支付有优惠等)
可选取值:
WECHATPAY_MODE
: 系统分配code,商户无需额外操作MERCHANT_API
: 商户发放时接口指定券codeMERCHANT_UPLOAD
: 商户上传自定义code,发券时系统随机选取上传的券code
notify_config 选填 object
【事件通知配置】事件回调通知商户的配置
属性 | |
notify_appid 选填 string(64) 【事件通知AppID】用于回调通知时,计算返回操作用户的OpenID(诸如领券用户),支持小程序or公众号的AppID;如该字段不填写,则回调通知中涉及到用户身份信息的OpenID与UnionID都将为空。 |
subsidy 选填 boolean
【是否允许营销补差】该批次发放的券是否允许进行补差,默认为false
注:该字段暂未开放
请求示例
POST
1curl -X POST \ 2 https://api.mch.weixin.qq.com/v3/marketing/busifavor/stocks \ 3 -H "Authorization: WECHATPAY2-SHA256-RSA2048 mchid=\"1900000001\",..." \ 4 -H "Accept: application/json" \ 5 -H "Content-Type: application/json" \ 6 -d '{ 7 "stock_name" : "8月1日活动券", 8 "belong_merchant" : "10000098", 9 "comment" : "活动使用", 10 "goods_name" : "填写商家券可适用的商品或服务", 11 "stock_type" : "NORMAL", 12 "coupon_use_rule" : { 13 "coupon_available_time" : { 14 "available_begin_time" : "2015-05-20T13:29:35+08:00", 15 "available_end_time" : "2015-05-20T13:29:35+08:00", 16 "available_day_after_receive" : 3, 17 "available_week" : { 18 "week_day" : [ 19 1 20 ], 21 "available_day_time" : [ 22 { 23 "begin_time" : 3600, 24 "end_time" : 86399 25 } 26 ] 27 }, 28 "irregulary_avaliable_time" : [ 29 { 30 "begin_time" : "2015-05-20T13:29:35+08:00", 31 "end_time" : "2015-05-20T13:29:35+08:00" 32 } 33 ], 34 "wait_days_after_receive" : 7 35 }, 36 "fixed_normal_coupon" : { 37 "discount_amount" : 5, 38 "transaction_minimum" : 100 39 }, 40 "discount_coupon" : { 41 "discount_percent" : 88, 42 "transaction_minimum" : 100 43 }, 44 "exchange_coupon" : { 45 "exchange_price" : 100, 46 "transaction_minimum" : 100 47 }, 48 "use_method" : "OFF_LINE", 49 "mini_programs_appid" : "wx23232232323", 50 "mini_programs_path" : "/path/index/index" 51 }, 52 "stock_send_rule" : { 53 "max_amount" : 100000, 54 "max_coupons" : 100, 55 "max_coupons_per_user" : 5, 56 "max_amount_by_day" : 1000, 57 "max_coupons_by_day" : 100, 58 "natural_person_limit" : false, 59 "prevent_api_abuse" : false, 60 "transferable" : false, 61 "shareable" : false 62 }, 63 "out_request_no" : "100002322019090134234sfdf", 64 "custom_entrance" : { 65 "mini_programs_info" : { 66 "mini_programs_appid" : "wx234545656765876", 67 "mini_programs_path" : "/path/index/index", 68 "entrance_words" : "欢迎选购", 69 "guiding_words" : "获取更多优惠" 70 }, 71 "appid" : "wx324345hgfhfghfg", 72 "hall_id" : "233455656", 73 "store_id" : "233554655", 74 "code_display_mode" : "NOT_SHOW" 75 }, 76 "display_pattern_info" : { 77 "description" : "xxx门店可用", 78 "merchant_logo_url" : "https://xxx", 79 "merchant_name" : "微信支付", 80 "background_color" : "xxxxx", 81 "coupon_image_url" : "图片cdn地址", 82 "finder_info" : { 83 "finder_id" : "sph6Rngt2T4RlUf", 84 "finder_video_id" : "export/UzFfAgtgekIEAQAAAAAAb4MgnPInmAAAAAstQy6ubaLX4KHWvLEZgBPEwIEgVnk9HIP-zNPgMJofG6tpdGPJNg_ojtEjoT94", 85 "finder_video_cover_image_url" : "https://wxpaylogo.qpic.cn/xxx" 86 } 87 }, 88 "coupon_code_mode" : "WECHATPAY_MODE", 89 "notify_config" : { 90 "notify_appid" : "wx23232232323" 91 }, 92 "subsidy" : false 93 }' 94
需配合微信支付工具库 WXPayUtility 使用,请参考Java
1package com.java.demo; 2 3import com.java.utils.WXPayUtility; // 引用微信支付工具库,参考:https://pay.weixin.qq.com/doc/v3/partner/4014985777 4 5import com.google.gson.annotations.SerializedName; 6import com.google.gson.annotations.Expose; 7import okhttp3.MediaType; 8import okhttp3.OkHttpClient; 9import okhttp3.Request; 10import okhttp3.RequestBody; 11import okhttp3.Response; 12 13import java.io.IOException; 14import java.io.UncheckedIOException; 15import java.security.PrivateKey; 16import java.security.PublicKey; 17import java.util.ArrayList; 18import java.util.HashMap; 19import java.util.List; 20import java.util.Map; 21 22/** 23 * 创建商家券 24 */ 25public class CreateBusifavorStock { 26 private static String HOST = "https://api.mch.weixin.qq.com"; 27 private static String METHOD = "POST"; 28 private static String PATH = "/v3/marketing/busifavor/stocks"; 29 30 public static void main(String[] args) { 31 // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/v3/partner/4013080340 32 CreateBusifavorStock client = new CreateBusifavorStock( 33 "19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340 34 "1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号,如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924 35 "/path/to/apiclient_key.pem", // 商户API证书私钥文件路径,本地文件路径 36 "PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID,如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589 37 "/path/to/wxp_pub.pem" // 微信支付公钥文件路径,本地文件路径 38 ); 39 40 CreateBusiFavorStockRequest request = new CreateBusiFavorStockRequest(); 41 request.stockName = "8月1日活动券"; 42 request.belongMerchant = "10000098"; 43 request.comment = "活动使用"; 44 request.goodsName = "填写商家券可适用的商品或服务"; 45 request.stockType = BusiFavorStockType.NORMAL; 46 request.couponUseRule = new CouponUseRule(); 47 request.couponUseRule.couponAvailableTime = new FavorAvailableTime(); 48 request.couponUseRule.couponAvailableTime.availableBeginTime = "2015-05-20T13:29:35+08:00"; 49 request.couponUseRule.couponAvailableTime.availableEndTime = "2015-05-20T13:29:35+08:00"; 50 request.couponUseRule.couponAvailableTime.availableDayAfterReceive = 3L; 51 request.couponUseRule.couponAvailableTime.availableWeek = new AvailableWeek(); 52 request.couponUseRule.couponAvailableTime.availableWeek.weekDay = new ArrayList<>(); 53 { 54 request.couponUseRule.couponAvailableTime.availableWeek.weekDay.add(1L); 55 }; 56 request.couponUseRule.couponAvailableTime.availableWeek.availableDayTime = new ArrayList<>(); 57 { 58 AvailableCurrentDayTime availableDayTimeItem = new AvailableCurrentDayTime(); 59 availableDayTimeItem.beginTime = 3600L; 60 availableDayTimeItem.endTime = 86399L; 61 request.couponUseRule.couponAvailableTime.availableWeek.availableDayTime.add(availableDayTimeItem); 62 }; 63 request.couponUseRule.couponAvailableTime.irregularyAvaliableTime = new ArrayList<>(); 64 { 65 IrregularAvailableTime irregularyAvaliableTimeItem = new IrregularAvailableTime(); 66 irregularyAvaliableTimeItem.beginTime = "2015-05-20T13:29:35+08:00"; 67 irregularyAvaliableTimeItem.endTime = "2015-05-20T13:29:35+08:00"; 68 request.couponUseRule.couponAvailableTime.irregularyAvaliableTime.add(irregularyAvaliableTimeItem); 69 }; 70 request.couponUseRule.couponAvailableTime.waitDaysAfterReceive = 7L; 71 request.couponUseRule.fixedNormalCoupon = new FixedValueStockMsg(); 72 request.couponUseRule.fixedNormalCoupon.discountAmount = 5L; 73 request.couponUseRule.fixedNormalCoupon.transactionMinimum = 100L; 74 request.couponUseRule.discountCoupon = new DiscountMsg(); 75 request.couponUseRule.discountCoupon.discountPercent = 88L; 76 request.couponUseRule.discountCoupon.transactionMinimum = 100L; 77 request.couponUseRule.exchangeCoupon = new ExchangeMsg(); 78 request.couponUseRule.exchangeCoupon.exchangePrice = 100L; 79 request.couponUseRule.exchangeCoupon.transactionMinimum = 100L; 80 request.couponUseRule.useMethod = CouponUseMethod.OFF_LINE; 81 request.couponUseRule.miniProgramsAppid = "wx23232232323"; 82 request.couponUseRule.miniProgramsPath = "/path/index/index"; 83 request.stockSendRule = new StockSendRule(); 84 request.stockSendRule.maxAmount = 100000L; 85 request.stockSendRule.maxCoupons = 100L; 86 request.stockSendRule.maxCouponsPerUser = 5L; 87 request.stockSendRule.maxAmountByDay = 1000L; 88 request.stockSendRule.maxCouponsByDay = 100L; 89 request.stockSendRule.naturalPersonLimit = false; 90 request.stockSendRule.preventApiAbuse = false; 91 request.stockSendRule.transferable = false; 92 request.stockSendRule.shareable = false; 93 request.outRequestNo = "100002322019090134234sfdf"; 94 request.customEntrance = new CustomEntrance(); 95 request.customEntrance.miniProgramsInfo = new MiniAppInfo(); 96 request.customEntrance.miniProgramsInfo.miniProgramsAppid = "wx234545656765876"; 97 request.customEntrance.miniProgramsInfo.miniProgramsPath = "/path/index/index"; 98 request.customEntrance.miniProgramsInfo.entranceWords = "欢迎选购"; 99 request.customEntrance.miniProgramsInfo.guidingWords = "获取更多优惠"; 100 request.customEntrance.appid = "wx324345hgfhfghfg"; 101 request.customEntrance.hallId = "233455656"; 102 request.customEntrance.storeId = "233554655"; 103 request.customEntrance.codeDisplayMode = CodeDisplayMode.NOT_SHOW; 104 request.displayPatternInfo = new DisplayPatternInfo(); 105 request.displayPatternInfo.description = "xxx门店可用"; 106 request.displayPatternInfo.merchantLogoUrl = "https://xxx"; 107 request.displayPatternInfo.merchantName = "微信支付"; 108 request.displayPatternInfo.backgroundColor = "xxxxx"; 109 request.displayPatternInfo.couponImageUrl = "图片cdn地址"; 110 request.displayPatternInfo.finderInfo = new FinderInfo(); 111 request.displayPatternInfo.finderInfo.finderId = "sph6Rngt2T4RlUf"; 112 request.displayPatternInfo.finderInfo.finderVideoId = "export/UzFfAgtgekIEAQAAAAAAb4MgnPInmAAAAAstQy6ubaLX4KHWvLEZgBPEwIEgVnk9HIP-zNPgMJofG6tpdGPJNg_ojtEjoT94"; 113 request.displayPatternInfo.finderInfo.finderVideoCoverImageUrl = "https://wxpaylogo.qpic.cn/xxx"; 114 request.couponCodeMode = CouponCodeMode.WECHATPAY_MODE; 115 request.notifyConfig = new NotifyConfig(); 116 request.notifyConfig.notifyAppid = "wx23232232323"; 117 request.subsidy = false; 118 try { 119 CreateBusiFavorStockResponse response = client.run(request); 120 // TODO: 请求成功,继续业务逻辑 121 System.out.println(response); 122 } catch (WXPayUtility.ApiException e) { 123 // TODO: 请求失败,根据状态码执行不同的逻辑 124 e.printStackTrace(); 125 } 126 } 127 128 public CreateBusiFavorStockResponse run(CreateBusiFavorStockRequest request) { 129 String uri = PATH; 130 String reqBody = WXPayUtility.toJson(request); 131 132 Request.Builder reqBuilder = new Request.Builder().url(HOST + uri); 133 reqBuilder.addHeader("Accept", "application/json"); 134 reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId); 135 reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody)); 136 reqBuilder.addHeader("Content-Type", "application/json"); 137 RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody); 138 reqBuilder.method(METHOD, requestBody); 139 Request httpRequest = reqBuilder.build(); 140 141 // 发送HTTP请求 142 OkHttpClient client = new OkHttpClient.Builder().build(); 143 try (Response httpResponse = client.newCall(httpRequest).execute()) { 144 String respBody = WXPayUtility.extractBody(httpResponse); 145 if (httpResponse.code() >= 200 && httpResponse.code() < 300) { 146 // 2XX 成功,验证应答签名 147 WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey, 148 httpResponse.headers(), respBody); 149 150 // 从HTTP应答报文构建返回数据 151 return WXPayUtility.fromJson(respBody, CreateBusiFavorStockResponse.class); 152 } else { 153 throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers()); 154 } 155 } catch (IOException e) { 156 throw new UncheckedIOException("Sending request to " + uri + " failed.", e); 157 } 158 } 159 160 private final String mchid; 161 private final String certificateSerialNo; 162 private final PrivateKey privateKey; 163 private final String wechatPayPublicKeyId; 164 private final PublicKey wechatPayPublicKey; 165 166 public CreateBusifavorStock(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) { 167 this.mchid = mchid; 168 this.certificateSerialNo = certificateSerialNo; 169 this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath); 170 this.wechatPayPublicKeyId = wechatPayPublicKeyId; 171 this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath); 172 } 173 174 public static class CreateBusiFavorStockRequest { 175 @SerializedName("stock_name") 176 public String stockName; 177 178 @SerializedName("belong_merchant") 179 public String belongMerchant; 180 181 @SerializedName("comment") 182 public String comment; 183 184 @SerializedName("goods_name") 185 public String goodsName; 186 187 @SerializedName("stock_type") 188 public BusiFavorStockType stockType; 189 190 @SerializedName("coupon_use_rule") 191 public CouponUseRule couponUseRule; 192 193 @SerializedName("stock_send_rule") 194 public StockSendRule stockSendRule; 195 196 @SerializedName("out_request_no") 197 public String outRequestNo; 198 199 @SerializedName("custom_entrance") 200 public CustomEntrance customEntrance; 201 202 @SerializedName("display_pattern_info") 203 public DisplayPatternInfo displayPatternInfo; 204 205 @SerializedName("coupon_code_mode") 206 public CouponCodeMode couponCodeMode; 207 208 @SerializedName("notify_config") 209 public NotifyConfig notifyConfig; 210 211 @SerializedName("subsidy") 212 public Boolean subsidy; 213 } 214 215 public static class CreateBusiFavorStockResponse { 216 @SerializedName("stock_id") 217 public String stockId; 218 219 @SerializedName("create_time") 220 public String createTime; 221 } 222 223 public enum BusiFavorStockType { 224 @SerializedName("NORMAL") 225 NORMAL, 226 @SerializedName("DISCOUNT") 227 DISCOUNT, 228 @SerializedName("EXCHANGE") 229 EXCHANGE 230 } 231 232 public static class CouponUseRule { 233 @SerializedName("coupon_available_time") 234 public FavorAvailableTime couponAvailableTime; 235 236 @SerializedName("fixed_normal_coupon") 237 public FixedValueStockMsg fixedNormalCoupon; 238 239 @SerializedName("discount_coupon") 240 public DiscountMsg discountCoupon; 241 242 @SerializedName("exchange_coupon") 243 public ExchangeMsg exchangeCoupon; 244 245 @SerializedName("use_method") 246 public CouponUseMethod useMethod; 247 248 @SerializedName("mini_programs_appid") 249 public String miniProgramsAppid; 250 251 @SerializedName("mini_programs_path") 252 public String miniProgramsPath; 253 } 254 255 public static class StockSendRule { 256 @SerializedName("max_amount") 257 public Long maxAmount; 258 259 @SerializedName("max_coupons") 260 public Long maxCoupons; 261 262 @SerializedName("max_coupons_per_user") 263 public Long maxCouponsPerUser; 264 265 @SerializedName("max_amount_by_day") 266 public Long maxAmountByDay; 267 268 @SerializedName("max_coupons_by_day") 269 public Long maxCouponsByDay; 270 271 @SerializedName("natural_person_limit") 272 public Boolean naturalPersonLimit; 273 274 @SerializedName("prevent_api_abuse") 275 public Boolean preventApiAbuse; 276 277 @SerializedName("transferable") 278 public Boolean transferable; 279 280 @SerializedName("shareable") 281 public Boolean shareable; 282 } 283 284 public static class CustomEntrance { 285 @SerializedName("mini_programs_info") 286 public MiniAppInfo miniProgramsInfo; 287 288 @SerializedName("appid") 289 public String appid; 290 291 @SerializedName("hall_id") 292 public String hallId; 293 294 @SerializedName("store_id") 295 public String storeId; 296 297 @SerializedName("code_display_mode") 298 public CodeDisplayMode codeDisplayMode; 299 } 300 301 public static class DisplayPatternInfo { 302 @SerializedName("description") 303 public String description; 304 305 @SerializedName("merchant_logo_url") 306 public String merchantLogoUrl; 307 308 @SerializedName("merchant_name") 309 public String merchantName; 310 311 @SerializedName("background_color") 312 public String backgroundColor; 313 314 @SerializedName("coupon_image_url") 315 public String couponImageUrl; 316 317 @SerializedName("finder_info") 318 public FinderInfo finderInfo; 319 } 320 321 public enum CouponCodeMode { 322 @SerializedName("WECHATPAY_MODE") 323 WECHATPAY_MODE, 324 @SerializedName("MERCHANT_API") 325 MERCHANT_API, 326 @SerializedName("MERCHANT_UPLOAD") 327 MERCHANT_UPLOAD 328 } 329 330 public static class NotifyConfig { 331 @SerializedName("notify_appid") 332 public String notifyAppid; 333 } 334 335 public static class FavorAvailableTime { 336 @SerializedName("available_begin_time") 337 public String availableBeginTime; 338 339 @SerializedName("available_end_time") 340 public String availableEndTime; 341 342 @SerializedName("available_day_after_receive") 343 public Long availableDayAfterReceive; 344 345 @SerializedName("available_week") 346 public AvailableWeek availableWeek; 347 348 @SerializedName("irregulary_avaliable_time") 349 public List<IrregularAvailableTime> irregularyAvaliableTime; 350 351 @SerializedName("wait_days_after_receive") 352 public Long waitDaysAfterReceive; 353 } 354 355 public static class FixedValueStockMsg { 356 @SerializedName("discount_amount") 357 public Long discountAmount; 358 359 @SerializedName("transaction_minimum") 360 public Long transactionMinimum; 361 } 362 363 public static class DiscountMsg { 364 @SerializedName("discount_percent") 365 public Long discountPercent; 366 367 @SerializedName("transaction_minimum") 368 public Long transactionMinimum; 369 } 370 371 public static class ExchangeMsg { 372 @SerializedName("exchange_price") 373 public Long exchangePrice; 374 375 @SerializedName("transaction_minimum") 376 public Long transactionMinimum; 377 } 378 379 public enum CouponUseMethod { 380 @SerializedName("OFF_LINE") 381 OFF_LINE, 382 @SerializedName("MINI_PROGRAMS") 383 MINI_PROGRAMS, 384 @SerializedName("SELF_CONSUME") 385 SELF_CONSUME, 386 @SerializedName("PAYMENT_CODE") 387 PAYMENT_CODE 388 } 389 390 public static class MiniAppInfo { 391 @SerializedName("mini_programs_appid") 392 public String miniProgramsAppid; 393 394 @SerializedName("mini_programs_path") 395 public String miniProgramsPath; 396 397 @SerializedName("entrance_words") 398 public String entranceWords; 399 400 @SerializedName("guiding_words") 401 public String guidingWords; 402 } 403 404 public enum CodeDisplayMode { 405 @SerializedName("NOT_SHOW") 406 NOT_SHOW, 407 @SerializedName("BARCODE") 408 BARCODE, 409 @SerializedName("QRCODE") 410 QRCODE 411 } 412 413 public static class FinderInfo { 414 @SerializedName("finder_id") 415 public String finderId; 416 417 @SerializedName("finder_video_id") 418 public String finderVideoId; 419 420 @SerializedName("finder_video_cover_image_url") 421 public String finderVideoCoverImageUrl; 422 } 423 424 public static class AvailableWeek { 425 @SerializedName("week_day") 426 public List<Long> weekDay; 427 428 @SerializedName("available_day_time") 429 public List<AvailableCurrentDayTime> availableDayTime; 430 } 431 432 public static class IrregularAvailableTime { 433 @SerializedName("begin_time") 434 public String beginTime; 435 436 @SerializedName("end_time") 437 public String endTime; 438 } 439 440 public static class AvailableCurrentDayTime { 441 @SerializedName("begin_time") 442 public Long beginTime; 443 444 @SerializedName("end_time") 445 public Long endTime; 446 } 447 448} 449
需配合微信支付工具库 wxpay_utility 使用,请参考Go
1package main 2 3import ( 4 "bytes" 5 "demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446 6 "encoding/json" 7 "fmt" 8 "net/http" 9 "net/url" 10 "time" 11) 12 13func main() { 14 // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/v3/partner/4013080340 15 config, err := wxpay_utility.CreateMchConfig( 16 "19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340 17 "1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号,如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924 18 "/path/to/apiclient_key.pem", // 商户API证书私钥文件路径,本地文件路径 19 "PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID,如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589 20 "/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径 21 ) 22 if err != nil { 23 fmt.Println(err) 24 return 25 } 26 27 request := &CreateBusiFavorStockRequest{ 28 StockName: wxpay_utility.String("8月1日活动券"), 29 BelongMerchant: wxpay_utility.String("10000098"), 30 Comment: wxpay_utility.String("活动使用"), 31 GoodsName: wxpay_utility.String("填写商家券可适用的商品或服务"), 32 StockType: BUSIFAVORSTOCKTYPE_NORMAL.Ptr(), 33 CouponUseRule: &CouponUseRule{ 34 CouponAvailableTime: &FavorAvailableTime{ 35 AvailableBeginTime: wxpay_utility.Time(time.Now()), 36 AvailableEndTime: wxpay_utility.Time(time.Now()), 37 AvailableDayAfterReceive: wxpay_utility.Int64(3), 38 AvailableWeek: &AvailableWeek{ 39 WeekDay: []int64{int64(1)}, 40 AvailableDayTime: []AvailableCurrentDayTime{AvailableCurrentDayTime{ 41 BeginTime: wxpay_utility.Int64(3600), 42 EndTime: wxpay_utility.Int64(86399), 43 }}, 44 }, 45 IrregularyAvaliableTime: []IrregularAvailableTime{IrregularAvailableTime{ 46 BeginTime: wxpay_utility.Time(time.Now()), 47 EndTime: wxpay_utility.Time(time.Now()), 48 }}, 49 WaitDaysAfterReceive: wxpay_utility.Int64(7), 50 }, 51 FixedNormalCoupon: &FixedValueStockMsg{ 52 DiscountAmount: wxpay_utility.Int64(5), 53 TransactionMinimum: wxpay_utility.Int64(100), 54 }, 55 DiscountCoupon: &DiscountMsg{ 56 DiscountPercent: wxpay_utility.Int64(88), 57 TransactionMinimum: wxpay_utility.Int64(100), 58 }, 59 ExchangeCoupon: &ExchangeMsg{ 60 ExchangePrice: wxpay_utility.Int64(100), 61 TransactionMinimum: wxpay_utility.Int64(100), 62 }, 63 UseMethod: COUPONUSEMETHOD_OFF_LINE.Ptr(), 64 MiniProgramsAppid: wxpay_utility.String("wx23232232323"), 65 MiniProgramsPath: wxpay_utility.String("/path/index/index"), 66 }, 67 StockSendRule: &StockSendRule{ 68 MaxAmount: wxpay_utility.Int64(100000), 69 MaxCoupons: wxpay_utility.Int64(100), 70 MaxCouponsPerUser: wxpay_utility.Int64(5), 71 MaxAmountByDay: wxpay_utility.Int64(1000), 72 MaxCouponsByDay: wxpay_utility.Int64(100), 73 NaturalPersonLimit: wxpay_utility.Bool(false), 74 PreventApiAbuse: wxpay_utility.Bool(false), 75 Transferable: wxpay_utility.Bool(false), 76 Shareable: wxpay_utility.Bool(false), 77 }, 78 OutRequestNo: wxpay_utility.String("100002322019090134234sfdf"), 79 CustomEntrance: &CustomEntrance{ 80 MiniProgramsInfo: &MiniAppInfo{ 81 MiniProgramsAppid: wxpay_utility.String("wx234545656765876"), 82 MiniProgramsPath: wxpay_utility.String("/path/index/index"), 83 EntranceWords: wxpay_utility.String("欢迎选购"), 84 GuidingWords: wxpay_utility.String("获取更多优惠"), 85 }, 86 Appid: wxpay_utility.String("wx324345hgfhfghfg"), 87 HallId: wxpay_utility.String("233455656"), 88 StoreId: wxpay_utility.String("233554655"), 89 CodeDisplayMode: CODEDISPLAYMODE_NOT_SHOW.Ptr(), 90 }, 91 DisplayPatternInfo: &DisplayPatternInfo{ 92 Description: wxpay_utility.String("xxx门店可用"), 93 MerchantLogoUrl: wxpay_utility.String("https://xxx"), 94 MerchantName: wxpay_utility.String("微信支付"), 95 BackgroundColor: wxpay_utility.String("xxxxx"), 96 CouponImageUrl: wxpay_utility.String("图片cdn地址"), 97 FinderInfo: &FinderInfo{ 98 FinderId: wxpay_utility.String("sph6Rngt2T4RlUf"), 99 FinderVideoId: wxpay_utility.String("export/UzFfAgtgekIEAQAAAAAAb4MgnPInmAAAAAstQy6ubaLX4KHWvLEZgBPEwIEgVnk9HIP-zNPgMJofG6tpdGPJNg_ojtEjoT94"), 100 FinderVideoCoverImageUrl: wxpay_utility.String("https://wxpaylogo.qpic.cn/xxx"), 101 }, 102 }, 103 CouponCodeMode: COUPONCODEMODE_WECHATPAY_MODE.Ptr(), 104 NotifyConfig: &NotifyConfig{ 105 NotifyAppid: wxpay_utility.String("wx23232232323"), 106 }, 107 Subsidy: wxpay_utility.Bool(false), 108 } 109 110 response, err := CreateBusifavorStock(config, request) 111 if err != nil { 112 fmt.Printf("请求失败: %+v\n", err) 113 // TODO: 请求失败,根据状态码执行不同的处理 114 return 115 } 116 117 // TODO: 请求成功,继续业务逻辑 118 fmt.Printf("请求成功: %+v\n", response) 119} 120 121func CreateBusifavorStock(config *wxpay_utility.MchConfig, request *CreateBusiFavorStockRequest) (response *CreateBusiFavorStockResponse, err error) { 122 const ( 123 host = "https://api.mch.weixin.qq.com" 124 method = "POST" 125 path = "/v3/marketing/busifavor/stocks" 126 ) 127 128 reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path)) 129 if err != nil { 130 return nil, err 131 } 132 reqBody, err := json.Marshal(request) 133 if err != nil { 134 return nil, err 135 } 136 httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody)) 137 if err != nil { 138 return nil, err 139 } 140 httpRequest.Header.Set("Accept", "application/json") 141 httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId()) 142 httpRequest.Header.Set("Content-Type", "application/json") 143 authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody) 144 if err != nil { 145 return nil, err 146 } 147 httpRequest.Header.Set("Authorization", authorization) 148 149 client := &http.Client{} 150 httpResponse, err := client.Do(httpRequest) 151 if err != nil { 152 return nil, err 153 } 154 respBody, err := wxpay_utility.ExtractResponseBody(httpResponse) 155 if err != nil { 156 return nil, err 157 } 158 if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 { 159 // 2XX 成功,验证应答签名 160 err = wxpay_utility.ValidateResponse( 161 config.WechatPayPublicKeyId(), 162 config.WechatPayPublicKey(), 163 &httpResponse.Header, 164 respBody, 165 ) 166 if err != nil { 167 return nil, err 168 } 169 response := &CreateBusiFavorStockResponse{} 170 if err := json.Unmarshal(respBody, response); err != nil { 171 return nil, err 172 } 173 174 return response, nil 175 } else { 176 return nil, wxpay_utility.NewApiException( 177 httpResponse.StatusCode, 178 httpResponse.Header, 179 respBody, 180 ) 181 } 182} 183 184type CreateBusiFavorStockRequest struct { 185 StockName *string `json:"stock_name,omitempty"` 186 BelongMerchant *string `json:"belong_merchant,omitempty"` 187 Comment *string `json:"comment,omitempty"` 188 GoodsName *string `json:"goods_name,omitempty"` 189 StockType *BusiFavorStockType `json:"stock_type,omitempty"` 190 CouponUseRule *CouponUseRule `json:"coupon_use_rule,omitempty"` 191 StockSendRule *StockSendRule `json:"stock_send_rule,omitempty"` 192 OutRequestNo *string `json:"out_request_no,omitempty"` 193 CustomEntrance *CustomEntrance `json:"custom_entrance,omitempty"` 194 DisplayPatternInfo *DisplayPatternInfo `json:"display_pattern_info,omitempty"` 195 CouponCodeMode *CouponCodeMode `json:"coupon_code_mode,omitempty"` 196 NotifyConfig *NotifyConfig `json:"notify_config,omitempty"` 197 Subsidy *bool `json:"subsidy,omitempty"` 198} 199 200type CreateBusiFavorStockResponse struct { 201 StockId *string `json:"stock_id,omitempty"` 202 CreateTime *string `json:"create_time,omitempty"` 203} 204 205type BusiFavorStockType string 206 207func (e BusiFavorStockType) Ptr() *BusiFavorStockType { 208 return &e 209} 210 211const ( 212 BUSIFAVORSTOCKTYPE_NORMAL BusiFavorStockType = "NORMAL" 213 BUSIFAVORSTOCKTYPE_DISCOUNT BusiFavorStockType = "DISCOUNT" 214 BUSIFAVORSTOCKTYPE_EXCHANGE BusiFavorStockType = "EXCHANGE" 215) 216 217type CouponUseRule struct { 218 CouponAvailableTime *FavorAvailableTime `json:"coupon_available_time,omitempty"` 219 FixedNormalCoupon *FixedValueStockMsg `json:"fixed_normal_coupon,omitempty"` 220 DiscountCoupon *DiscountMsg `json:"discount_coupon,omitempty"` 221 ExchangeCoupon *ExchangeMsg `json:"exchange_coupon,omitempty"` 222 UseMethod *CouponUseMethod `json:"use_method,omitempty"` 223 MiniProgramsAppid *string `json:"mini_programs_appid,omitempty"` 224 MiniProgramsPath *string `json:"mini_programs_path,omitempty"` 225} 226 227type StockSendRule struct { 228 MaxAmount *int64 `json:"max_amount,omitempty"` 229 MaxCoupons *int64 `json:"max_coupons,omitempty"` 230 MaxCouponsPerUser *int64 `json:"max_coupons_per_user,omitempty"` 231 MaxAmountByDay *int64 `json:"max_amount_by_day,omitempty"` 232 MaxCouponsByDay *int64 `json:"max_coupons_by_day,omitempty"` 233 NaturalPersonLimit *bool `json:"natural_person_limit,omitempty"` 234 PreventApiAbuse *bool `json:"prevent_api_abuse,omitempty"` 235 Transferable *bool `json:"transferable,omitempty"` 236 Shareable *bool `json:"shareable,omitempty"` 237} 238 239type CustomEntrance struct { 240 MiniProgramsInfo *MiniAppInfo `json:"mini_programs_info,omitempty"` 241 Appid *string `json:"appid,omitempty"` 242 HallId *string `json:"hall_id,omitempty"` 243 StoreId *string `json:"store_id,omitempty"` 244 CodeDisplayMode *CodeDisplayMode `json:"code_display_mode,omitempty"` 245} 246 247type DisplayPatternInfo struct { 248 Description *string `json:"description,omitempty"` 249 MerchantLogoUrl *string `json:"merchant_logo_url,omitempty"` 250 MerchantName *string `json:"merchant_name,omitempty"` 251 BackgroundColor *string `json:"background_color,omitempty"` 252 CouponImageUrl *string `json:"coupon_image_url,omitempty"` 253 FinderInfo *FinderInfo `json:"finder_info,omitempty"` 254} 255 256type CouponCodeMode string 257 258func (e CouponCodeMode) Ptr() *CouponCodeMode { 259 return &e 260} 261 262const ( 263 COUPONCODEMODE_WECHATPAY_MODE CouponCodeMode = "WECHATPAY_MODE" 264 COUPONCODEMODE_MERCHANT_API CouponCodeMode = "MERCHANT_API" 265 COUPONCODEMODE_MERCHANT_UPLOAD CouponCodeMode = "MERCHANT_UPLOAD" 266) 267 268type NotifyConfig struct { 269 NotifyAppid *string `json:"notify_appid,omitempty"` 270} 271 272type FavorAvailableTime struct { 273 AvailableBeginTime *time.Time `json:"available_begin_time,omitempty"` 274 AvailableEndTime *time.Time `json:"available_end_time,omitempty"` 275 AvailableDayAfterReceive *int64 `json:"available_day_after_receive,omitempty"` 276 AvailableWeek *AvailableWeek `json:"available_week,omitempty"` 277 IrregularyAvaliableTime []IrregularAvailableTime `json:"irregulary_avaliable_time,omitempty"` 278 WaitDaysAfterReceive *int64 `json:"wait_days_after_receive,omitempty"` 279} 280 281type FixedValueStockMsg struct { 282 DiscountAmount *int64 `json:"discount_amount,omitempty"` 283 TransactionMinimum *int64 `json:"transaction_minimum,omitempty"` 284} 285 286type DiscountMsg struct { 287 DiscountPercent *int64 `json:"discount_percent,omitempty"` 288 TransactionMinimum *int64 `json:"transaction_minimum,omitempty"` 289} 290 291type ExchangeMsg struct { 292 ExchangePrice *int64 `json:"exchange_price,omitempty"` 293 TransactionMinimum *int64 `json:"transaction_minimum,omitempty"` 294} 295 296type CouponUseMethod string 297 298func (e CouponUseMethod) Ptr() *CouponUseMethod { 299 return &e 300} 301 302const ( 303 COUPONUSEMETHOD_OFF_LINE CouponUseMethod = "OFF_LINE" 304 COUPONUSEMETHOD_MINI_PROGRAMS CouponUseMethod = "MINI_PROGRAMS" 305 COUPONUSEMETHOD_SELF_CONSUME CouponUseMethod = "SELF_CONSUME" 306 COUPONUSEMETHOD_PAYMENT_CODE CouponUseMethod = "PAYMENT_CODE" 307) 308 309type MiniAppInfo struct { 310 MiniProgramsAppid *string `json:"mini_programs_appid,omitempty"` 311 MiniProgramsPath *string `json:"mini_programs_path,omitempty"` 312 EntranceWords *string `json:"entrance_words,omitempty"` 313 GuidingWords *string `json:"guiding_words,omitempty"` 314} 315 316type CodeDisplayMode string 317 318func (e CodeDisplayMode) Ptr() *CodeDisplayMode { 319 return &e 320} 321 322const ( 323 CODEDISPLAYMODE_NOT_SHOW CodeDisplayMode = "NOT_SHOW" 324 CODEDISPLAYMODE_BARCODE CodeDisplayMode = "BARCODE" 325 CODEDISPLAYMODE_QRCODE CodeDisplayMode = "QRCODE" 326) 327 328type FinderInfo struct { 329 FinderId *string `json:"finder_id,omitempty"` 330 FinderVideoId *string `json:"finder_video_id,omitempty"` 331 FinderVideoCoverImageUrl *string `json:"finder_video_cover_image_url,omitempty"` 332} 333 334type AvailableWeek struct { 335 WeekDay []int64 `json:"week_day,omitempty"` 336 AvailableDayTime []AvailableCurrentDayTime `json:"available_day_time,omitempty"` 337} 338 339type IrregularAvailableTime struct { 340 BeginTime *time.Time `json:"begin_time,omitempty"` 341 EndTime *time.Time `json:"end_time,omitempty"` 342} 343 344type AvailableCurrentDayTime struct { 345 BeginTime *int64 `json:"begin_time,omitempty"` 346 EndTime *int64 `json:"end_time,omitempty"` 347} 348
应答参数
200 OK
stock_id 必填 string
【批次号】批次号
create_time 必填 string
【创建时间】创建时间,遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE,yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss表示时分秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35+08:00表示,北京时间2015年5月20日 13点29分35秒。
应答示例
200 OK
1{ 2 "stock_id" : "98065001", 3 "create_time" : "2015-05-20T13:29:35+08:00" 4} 5
错误码
公共错误码
状态码 | 错误码 | 描述 | 解决方案 |
---|---|---|---|
400 | PARAM_ERROR | 参数错误 | 请根据错误提示正确传入参数 |
400 | INVALID_REQUEST | HTTP 请求不符合微信支付 APIv3 接口规则 | 请参阅 接口规则 |
401 | SIGN_ERROR | 验证不通过 | 请参阅 签名常见问题 |
500 | SYSTEM_ERROR | 系统异常,请稍后重试 | 请稍后重试 |
业务错误码
状态码 | 错误码 | 描述 | 解决方案 |
---|---|---|---|
400 | APPID_MCHID_NOT_MATCH | AppID与请求方商户无关联关系 | AppID与请求方商户不匹配,请确认AppID与请求方商户是否有关联关系 |
400 | INVALID_REQUEST | 发券模式不合法 | 请更换支持预上传code的批次后重试 |
400 | MCH_NOT_EXISTS | 商户号不存在 | 请确认传入的商户号是否正确 |
400 | RESOURCE_ALREADY_EXISTS | 批次已存在 | 查看out_request_no字段是否重复使用 |
400 | RESOURCE_ALREADY_EXISTS | 券已被其他订单核销 | 请通过查询券API确认券是否已被其他订单核销 |
400 | SYSTEM_ERROR | 系统错误 | 请使用相同参数稍后重新调用 |
403 | NO_AUTH | 无权限 | 查看具体错误信息,确认是否有权限 |
403 | RULE_LIMIT | 券不在有效期内 | 请确认券是否能在当前时间核销 |
404 | RESOURCE_NOT_EXISTS | 查询的资源不存在 | 请检查查询资源的对应ID是否填写正确 |
404 | USER_NOT_EXISTS | OpenID不正确 | 请确认传入的OpenID是否正确 |
429 | FREQUENCY_LIMITED | 频率限制 | 调用太频繁,请降低调用接口频率 |
500 | SYSTEM_ERROR | 系统失败 | 多为网络超时引起,重试 |