添加商品券批次组
更新时间:2025.11.20服务商可以通过该接口为已有的「多次优惠」商品券添加更多批次组,每个批次组创建时会批量创建多个商品券批次。同一个商品券的多个批次组可以实现品牌方多样化的投放需求。
前置条件:已创建商品券且商品券的 usage_mode 为 PROGRESSIVE_BUNDLE
频率限制:20/s
接口说明
支持商户:【普通服务商】
请求方式:【POST】/v3/marketing/partner/product-coupon/product-coupons/{product_coupon_id}/stock-bundles
请求域名:【主域名】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
path 路径参数
product_coupon_id 必填 string
【商品券ID】 商品券的唯一标识,创建商品券时由微信支付生成
body 包体参数
out_request_no 必填 string(40)
【创建请求单号】 品牌创建批次请求流水号,品牌侧需保持唯一性,可使用 数字、大小写字母、下划线_、短横线- 组成,长度在6-40个字符之间
stock_bundle 必填 object
【批次组】 为商品券创建的批次组详情
| 属性 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
remark 选填 string(20) 【备注】 仅配置品牌方可见,用于自定义信息,最多20个UTF-8字符 coupon_code_mode 必填 string 【券Code分配模式】 决定发券时用户商品券Code如何产生,批次组内每一个批次都会设置为此值 可选取值
stock_send_rule 必填 object 【发放规则】 批次的发放规则
progressive_bundle_usage_rule 选填 object 【多次优惠批次组使用规则】 包含组合内部每一个批次的优惠规则,会根据内部的优惠规则列表依次创建批次放入批次组,当且仅当
usage_rule_display_info 必填 object 【券使用规则展示信息】 券使用规则展示信息,批次组内每一个批次都会设置为此值
coupon_display_info 必填 object 【用户商品券展示信息】 用户商品券在卡包中的展示详情,包括引导用户的自定义入口,批次组内每一个批次都会设置为此值
notify_config 必填 object 【事件通知配置】 发生券相关事件时,微信支付会向品牌方发送通知,需要提供通知相关配置,批次组内每一个批次都会设置为此值
store_scope 必填 string 【可用门店范围】 控制该批次可以在品牌下哪些门店使用,批次组内每一个批次都会设置为此值 可选取值
|
brand_id 必填 string
【品牌ID】 微信支付为品牌方分配的唯一标识,该品牌应与服务商存在授权关系
请求示例
POST
1curl -X POST \ 2 https://api.mch.weixin.qq.com/v3/marketing/partner/product-coupon/product-coupons/200000001/stock-bundles \ 3 -H "Authorization: WECHATPAY2-SHA256-RSA2048 mchid=\"1900000001\",..." \ 4 -H "Accept: application/json" \ 5 -H "Content-Type: application/json" \ 6 -d '{ 7 "out_request_no" : "34657_20250101_123456", 8 "stock_bundle" : { 9 "remark" : "满减券", 10 "coupon_code_mode" : "UPLOAD", 11 "stock_send_rule" : { 12 "max_count" : 10000000, 13 "max_count_per_day" : 10000, 14 "max_count_per_user" : 1 15 }, 16 "progressive_bundle_usage_rule" : { 17 "coupon_available_period" : { 18 "available_begin_time" : "2025-01-01T00:00:00+08:00", 19 "available_end_time" : "2025-10-01T00:00:00+08:00", 20 "available_days" : 10, 21 "wait_days_after_receive" : 1, 22 "weekly_available_period" : { 23 "day_list" : [ 24 "MONDAY" 25 ], 26 "day_period_list" : [ 27 { 28 "begin_time" : 60, 29 "end_time" : 86399 30 } 31 ] 32 }, 33 "irregular_available_period_list" : [ 34 { 35 "begin_time" : "2025-01-01T00:00:00+08:00", 36 "end_time" : "2025-10-01T00:00:00+08:00" 37 } 38 ] 39 }, 40 "normal_coupon_list" : [ 41 { 42 "threshold" : 10000, 43 "discount_amount" : 100 44 } 45 ], 46 "discount_coupon_list" : [ 47 { 48 "threshold" : 10000, 49 "percent_off" : 30 50 } 51 ], 52 "exchange_coupon_list" : [ 53 { 54 "threshold" : 10000, 55 "exchange_price" : 100 56 } 57 ] 58 }, 59 "usage_rule_display_info" : { 60 "coupon_usage_method_list" : [ 61 "MINI_PROGRAM" 62 ], 63 "mini_program_appid" : "wx1234567890", 64 "mini_program_path" : "/pages/index/product", 65 "app_path" : "https://www.example.com/jump-to-app", 66 "usage_description" : "全场可用", 67 "coupon_available_store_info" : { 68 "description" : "可在上海市区的所有门店使用,详细列表参考小程序内信息为准", 69 "mini_program_appid" : "wx1234567890", 70 "mini_program_path" : "/pages/index/store-list" 71 } 72 }, 73 "coupon_display_info" : { 74 "code_display_mode" : "QRCODE", 75 "background_color" : "Color010", 76 "entrance_mini_program" : { 77 "appid" : "wx1234567890", 78 "path" : "/pages/index/product", 79 "entrance_wording" : "欢迎选购", 80 "guidance_wording" : "获取更多优惠" 81 }, 82 "entrance_official_account" : { 83 "appid" : "wx1234567890" 84 }, 85 "entrance_finder" : { 86 "finder_id" : "gh_12345678", 87 "finder_video_id" : "UDFsdf24df34dD456Hdf34", 88 "finder_video_cover_image_url" : "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx" 89 } 90 }, 91 "notify_config" : { 92 "notify_appid" : "wx4fd12345678" 93 }, 94 "store_scope" : "SPECIFIC" 95 }, 96 "brand_id" : "120344" 97 }' 98
需配合微信支付工具库 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 CreateStockBundle { 26 private static String HOST = "https://api.mch.weixin.qq.com"; 27 private static String METHOD = "POST"; 28 private static String PATH = "/v3/marketing/partner/product-coupon/product-coupons/{product_coupon_id}/stock-bundles"; 29 30 public static void main(String[] args) { 31 // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/v3/partner/4013080340 32 CreateStockBundle client = new CreateStockBundle( 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 CreateStockBundleRequest request = new CreateStockBundleRequest(); 41 request.productCouponId = "200000001"; 42 request.outRequestNo = "34657_20250101_123456"; 43 request.stockBundle = new StockBundleForCreate(); 44 request.stockBundle.remark = "满减券"; 45 request.stockBundle.couponCodeMode = CouponCodeMode.UPLOAD; 46 request.stockBundle.stockSendRule = new StockSendRule(); 47 request.stockBundle.stockSendRule.maxCount = 10000000L; 48 request.stockBundle.stockSendRule.maxCountPerDay = 10000L; 49 request.stockBundle.stockSendRule.maxCountPerUser = 1L; 50 request.stockBundle.progressiveBundleUsageRule = new StockBundleUsageRule(); 51 request.stockBundle.progressiveBundleUsageRule.couponAvailablePeriod = new CouponAvailablePeriod(); 52 request.stockBundle.progressiveBundleUsageRule.couponAvailablePeriod.availableBeginTime = "2025-01-01T00:00:00+08:00"; 53 request.stockBundle.progressiveBundleUsageRule.couponAvailablePeriod.availableEndTime = "2025-10-01T00:00:00+08:00"; 54 request.stockBundle.progressiveBundleUsageRule.couponAvailablePeriod.availableDays = 10L; 55 request.stockBundle.progressiveBundleUsageRule.couponAvailablePeriod.waitDaysAfterReceive = 1L; 56 request.stockBundle.progressiveBundleUsageRule.couponAvailablePeriod.weeklyAvailablePeriod = new FixedWeekPeriod(); 57 request.stockBundle.progressiveBundleUsageRule.couponAvailablePeriod.weeklyAvailablePeriod.dayList = new ArrayList<>(); 58 { 59 request.stockBundle.progressiveBundleUsageRule.couponAvailablePeriod.weeklyAvailablePeriod.dayList.add(WeekEnum.MONDAY); 60 }; 61 request.stockBundle.progressiveBundleUsageRule.couponAvailablePeriod.weeklyAvailablePeriod.dayPeriodList = new ArrayList<>(); 62 { 63 PeriodOfTheDay dayPeriodListItem = new PeriodOfTheDay(); 64 dayPeriodListItem.beginTime = 60L; 65 dayPeriodListItem.endTime = 86399L; 66 request.stockBundle.progressiveBundleUsageRule.couponAvailablePeriod.weeklyAvailablePeriod.dayPeriodList.add(dayPeriodListItem); 67 }; 68 request.stockBundle.progressiveBundleUsageRule.couponAvailablePeriod.irregularAvailablePeriodList = new ArrayList<>(); 69 { 70 TimePeriod irregularAvailablePeriodListItem = new TimePeriod(); 71 irregularAvailablePeriodListItem.beginTime = "2025-01-01T00:00:00+08:00"; 72 irregularAvailablePeriodListItem.endTime = "2025-10-01T00:00:00+08:00"; 73 request.stockBundle.progressiveBundleUsageRule.couponAvailablePeriod.irregularAvailablePeriodList.add(irregularAvailablePeriodListItem); 74 }; 75 request.stockBundle.progressiveBundleUsageRule.normalCouponList = new ArrayList<>(); 76 { 77 NormalCouponUsageRule normalCouponListItem = new NormalCouponUsageRule(); 78 normalCouponListItem.threshold = 10000L; 79 normalCouponListItem.discountAmount = 100L; 80 request.stockBundle.progressiveBundleUsageRule.normalCouponList.add(normalCouponListItem); 81 }; 82 request.stockBundle.progressiveBundleUsageRule.discountCouponList = new ArrayList<>(); 83 { 84 DiscountCouponUsageRule discountCouponListItem = new DiscountCouponUsageRule(); 85 discountCouponListItem.threshold = 10000L; 86 discountCouponListItem.percentOff = 30L; 87 request.stockBundle.progressiveBundleUsageRule.discountCouponList.add(discountCouponListItem); 88 }; 89 request.stockBundle.progressiveBundleUsageRule.exchangeCouponList = new ArrayList<>(); 90 { 91 ExchangeCouponUsageRule exchangeCouponListItem = new ExchangeCouponUsageRule(); 92 exchangeCouponListItem.threshold = 10000L; 93 exchangeCouponListItem.exchangePrice = 100L; 94 request.stockBundle.progressiveBundleUsageRule.exchangeCouponList.add(exchangeCouponListItem); 95 }; 96 request.stockBundle.usageRuleDisplayInfo = new UsageRuleDisplayInfo(); 97 request.stockBundle.usageRuleDisplayInfo.couponUsageMethodList = new ArrayList<>(); 98 { 99 request.stockBundle.usageRuleDisplayInfo.couponUsageMethodList.add(CouponUsageMethod.OFFLINE); 100 }; 101 request.stockBundle.usageRuleDisplayInfo.miniProgramAppid = "wx1234567890"; 102 request.stockBundle.usageRuleDisplayInfo.miniProgramPath = "/pages/index/product"; 103 request.stockBundle.usageRuleDisplayInfo.appPath = "https://www.example.com/jump-to-app"; 104 request.stockBundle.usageRuleDisplayInfo.usageDescription = "全场可用"; 105 request.stockBundle.usageRuleDisplayInfo.couponAvailableStoreInfo = new CouponAvailableStoreInfo(); 106 request.stockBundle.usageRuleDisplayInfo.couponAvailableStoreInfo.description = "可在上海市区的所有门店使用,详细列表参考小程序内信息为准"; 107 request.stockBundle.usageRuleDisplayInfo.couponAvailableStoreInfo.miniProgramAppid = "wx1234567890"; 108 request.stockBundle.usageRuleDisplayInfo.couponAvailableStoreInfo.miniProgramPath = "/pages/index/store-list"; 109 request.stockBundle.couponDisplayInfo = new CouponDisplayInfo(); 110 request.stockBundle.couponDisplayInfo.codeDisplayMode = CouponCodeDisplayMode.QRCODE; 111 request.stockBundle.couponDisplayInfo.backgroundColor = "Color010"; 112 request.stockBundle.couponDisplayInfo.entranceMiniProgram = new EntranceMiniProgram(); 113 request.stockBundle.couponDisplayInfo.entranceMiniProgram.appid = "wx1234567890"; 114 request.stockBundle.couponDisplayInfo.entranceMiniProgram.path = "/pages/index/product"; 115 request.stockBundle.couponDisplayInfo.entranceMiniProgram.entranceWording = "欢迎选购"; 116 request.stockBundle.couponDisplayInfo.entranceMiniProgram.guidanceWording = "获取更多优惠"; 117 request.stockBundle.couponDisplayInfo.entranceOfficialAccount = new EntranceOfficialAccount(); 118 request.stockBundle.couponDisplayInfo.entranceOfficialAccount.appid = "wx1234567890"; 119 request.stockBundle.couponDisplayInfo.entranceFinder = new EntranceFinder(); 120 request.stockBundle.couponDisplayInfo.entranceFinder.finderId = "gh_12345678"; 121 request.stockBundle.couponDisplayInfo.entranceFinder.finderVideoId = "UDFsdf24df34dD456Hdf34"; 122 request.stockBundle.couponDisplayInfo.entranceFinder.finderVideoCoverImageUrl = "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx"; 123 request.stockBundle.notifyConfig = new NotifyConfig(); 124 request.stockBundle.notifyConfig.notifyAppid = "wx4fd12345678"; 125 request.stockBundle.storeScope = StockStoreScope.SPECIFIC; 126 request.brandId = "120344"; 127 try { 128 StockBundleEntity response = client.run(request); 129 // TODO: 请求成功,继续业务逻辑 130 System.out.println(response); 131 } catch (WXPayUtility.ApiException e) { 132 // TODO: 请求失败,根据状态码执行不同的逻辑 133 e.printStackTrace(); 134 } 135 } 136 137 public StockBundleEntity run(CreateStockBundleRequest request) { 138 String uri = PATH; 139 uri = uri.replace("{product_coupon_id}", WXPayUtility.urlEncode(request.productCouponId)); 140 String reqBody = WXPayUtility.toJson(request); 141 142 Request.Builder reqBuilder = new Request.Builder().url(HOST + uri); 143 reqBuilder.addHeader("Accept", "application/json"); 144 reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId); 145 reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody)); 146 reqBuilder.addHeader("Content-Type", "application/json"); 147 RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody); 148 reqBuilder.method(METHOD, requestBody); 149 Request httpRequest = reqBuilder.build(); 150 151 // 发送HTTP请求 152 OkHttpClient client = new OkHttpClient.Builder().build(); 153 try (Response httpResponse = client.newCall(httpRequest).execute()) { 154 String respBody = WXPayUtility.extractBody(httpResponse); 155 if (httpResponse.code() >= 200 && httpResponse.code() < 300) { 156 // 2XX 成功,验证应答签名 157 WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey, 158 httpResponse.headers(), respBody); 159 160 // 从HTTP应答报文构建返回数据 161 return WXPayUtility.fromJson(respBody, StockBundleEntity.class); 162 } else { 163 throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers()); 164 } 165 } catch (IOException e) { 166 throw new UncheckedIOException("Sending request to " + uri + " failed.", e); 167 } 168 } 169 170 private final String mchid; 171 private final String certificateSerialNo; 172 private final PrivateKey privateKey; 173 private final String wechatPayPublicKeyId; 174 private final PublicKey wechatPayPublicKey; 175 176 public CreateStockBundle(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) { 177 this.mchid = mchid; 178 this.certificateSerialNo = certificateSerialNo; 179 this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath); 180 this.wechatPayPublicKeyId = wechatPayPublicKeyId; 181 this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath); 182 } 183 184 public static class CreateStockBundleRequest { 185 @SerializedName("out_request_no") 186 public String outRequestNo; 187 188 @SerializedName("product_coupon_id") 189 @Expose(serialize = false) 190 public String productCouponId; 191 192 @SerializedName("stock_bundle") 193 public StockBundleForCreate stockBundle; 194 195 @SerializedName("brand_id") 196 public String brandId; 197 } 198 199 public static class StockBundleEntity { 200 @SerializedName("stock_bundle_id") 201 public String stockBundleId; 202 203 @SerializedName("stock_list") 204 public List<StockEntityInBundle> stockList = new ArrayList<StockEntityInBundle>(); 205 } 206 207 public static class StockBundleForCreate { 208 @SerializedName("remark") 209 public String remark; 210 211 @SerializedName("coupon_code_mode") 212 public CouponCodeMode couponCodeMode; 213 214 @SerializedName("stock_send_rule") 215 public StockSendRule stockSendRule; 216 217 @SerializedName("progressive_bundle_usage_rule") 218 public StockBundleUsageRule progressiveBundleUsageRule; 219 220 @SerializedName("usage_rule_display_info") 221 public UsageRuleDisplayInfo usageRuleDisplayInfo; 222 223 @SerializedName("coupon_display_info") 224 public CouponDisplayInfo couponDisplayInfo; 225 226 @SerializedName("notify_config") 227 public NotifyConfig notifyConfig; 228 229 @SerializedName("store_scope") 230 public StockStoreScope storeScope; 231 } 232 233 public static class StockEntityInBundle { 234 @SerializedName("product_coupon_id") 235 public String productCouponId; 236 237 @SerializedName("stock_id") 238 public String stockId; 239 240 @SerializedName("remark") 241 public String remark; 242 243 @SerializedName("coupon_code_mode") 244 public ProgressiveBundleCouponCodeMode couponCodeMode; 245 246 @SerializedName("coupon_code_count_info") 247 public CouponCodeCountInfo couponCodeCountInfo; 248 249 @SerializedName("stock_send_rule") 250 public StockSendRule stockSendRule; 251 252 @SerializedName("progressive_bundle_usage_rule") 253 public StockUsageRule progressiveBundleUsageRule; 254 255 @SerializedName("stock_bundle_info") 256 public StockBundleInfo stockBundleInfo; 257 258 @SerializedName("usage_rule_display_info") 259 public UsageRuleDisplayInfo usageRuleDisplayInfo; 260 261 @SerializedName("coupon_display_info") 262 public CouponDisplayInfo couponDisplayInfo; 263 264 @SerializedName("notify_config") 265 public NotifyConfig notifyConfig; 266 267 @SerializedName("store_scope") 268 public StockStoreScope storeScope; 269 270 @SerializedName("sent_count_info") 271 public StockSentCountInfo sentCountInfo; 272 273 @SerializedName("state") 274 public StockState state; 275 276 @SerializedName("deactivate_request_no") 277 public String deactivateRequestNo; 278 279 @SerializedName("deactivate_time") 280 public String deactivateTime; 281 282 @SerializedName("deactivate_reason") 283 public String deactivateReason; 284 285 @SerializedName("brand_id") 286 public String brandId; 287 } 288 289 public enum CouponCodeMode { 290 @SerializedName("WECHATPAY") 291 WECHATPAY, 292 @SerializedName("UPLOAD") 293 UPLOAD 294 } 295 296 public static class StockSendRule { 297 @SerializedName("max_count") 298 public Long maxCount; 299 300 @SerializedName("max_count_per_day") 301 public Long maxCountPerDay; 302 303 @SerializedName("max_count_per_user") 304 public Long maxCountPerUser; 305 } 306 307 public static class StockBundleUsageRule { 308 @SerializedName("coupon_available_period") 309 public CouponAvailablePeriod couponAvailablePeriod; 310 311 @SerializedName("normal_coupon_list") 312 public List<NormalCouponUsageRule> normalCouponList; 313 314 @SerializedName("discount_coupon_list") 315 public List<DiscountCouponUsageRule> discountCouponList; 316 317 @SerializedName("exchange_coupon_list") 318 public List<ExchangeCouponUsageRule> exchangeCouponList; 319 } 320 321 public static class UsageRuleDisplayInfo { 322 @SerializedName("coupon_usage_method_list") 323 public List<CouponUsageMethod> couponUsageMethodList = new ArrayList<CouponUsageMethod>(); 324 325 @SerializedName("mini_program_appid") 326 public String miniProgramAppid; 327 328 @SerializedName("mini_program_path") 329 public String miniProgramPath; 330 331 @SerializedName("app_path") 332 public String appPath; 333 334 @SerializedName("usage_description") 335 public String usageDescription; 336 337 @SerializedName("coupon_available_store_info") 338 public CouponAvailableStoreInfo couponAvailableStoreInfo; 339 } 340 341 public static class CouponDisplayInfo { 342 @SerializedName("code_display_mode") 343 public CouponCodeDisplayMode codeDisplayMode; 344 345 @SerializedName("background_color") 346 public String backgroundColor; 347 348 @SerializedName("entrance_mini_program") 349 public EntranceMiniProgram entranceMiniProgram; 350 351 @SerializedName("entrance_official_account") 352 public EntranceOfficialAccount entranceOfficialAccount; 353 354 @SerializedName("entrance_finder") 355 public EntranceFinder entranceFinder; 356 } 357 358 public static class NotifyConfig { 359 @SerializedName("notify_appid") 360 public String notifyAppid; 361 } 362 363 public enum StockStoreScope { 364 @SerializedName("NONE") 365 NONE, 366 @SerializedName("ALL") 367 ALL, 368 @SerializedName("SPECIFIC") 369 SPECIFIC 370 } 371 372 public enum ProgressiveBundleCouponCodeMode { 373 @SerializedName("WECHATPAY") 374 WECHATPAY, 375 @SerializedName("UPLOAD") 376 UPLOAD 377 } 378 379 public static class CouponCodeCountInfo { 380 @SerializedName("total_count") 381 public Long totalCount; 382 383 @SerializedName("available_count") 384 public Long availableCount; 385 } 386 387 public static class StockUsageRule { 388 @SerializedName("coupon_available_period") 389 public CouponAvailablePeriod couponAvailablePeriod; 390 391 @SerializedName("normal_coupon") 392 public NormalCouponUsageRule normalCoupon; 393 394 @SerializedName("discount_coupon") 395 public DiscountCouponUsageRule discountCoupon; 396 397 @SerializedName("exchange_coupon") 398 public ExchangeCouponUsageRule exchangeCoupon; 399 } 400 401 public static class StockBundleInfo { 402 @SerializedName("stock_bundle_id") 403 public String stockBundleId; 404 405 @SerializedName("stock_bundle_index") 406 public Long stockBundleIndex; 407 } 408 409 public static class StockSentCountInfo { 410 @SerializedName("total_count") 411 public Long totalCount; 412 413 @SerializedName("today_count") 414 public Long todayCount; 415 } 416 417 public enum StockState { 418 @SerializedName("AUDITING") 419 AUDITING, 420 @SerializedName("SENDING") 421 SENDING, 422 @SerializedName("PAUSED") 423 PAUSED, 424 @SerializedName("STOPPED") 425 STOPPED, 426 @SerializedName("DEACTIVATED") 427 DEACTIVATED 428 } 429 430 public static class CouponAvailablePeriod { 431 @SerializedName("available_begin_time") 432 public String availableBeginTime; 433 434 @SerializedName("available_end_time") 435 public String availableEndTime; 436 437 @SerializedName("available_days") 438 public Long availableDays; 439 440 @SerializedName("wait_days_after_receive") 441 public Long waitDaysAfterReceive; 442 443 @SerializedName("weekly_available_period") 444 public FixedWeekPeriod weeklyAvailablePeriod; 445 446 @SerializedName("irregular_available_period_list") 447 public List<TimePeriod> irregularAvailablePeriodList; 448 } 449 450 public static class NormalCouponUsageRule { 451 @SerializedName("threshold") 452 public Long threshold; 453 454 @SerializedName("discount_amount") 455 public Long discountAmount; 456 } 457 458 public static class DiscountCouponUsageRule { 459 @SerializedName("threshold") 460 public Long threshold; 461 462 @SerializedName("percent_off") 463 public Long percentOff; 464 } 465 466 public static class ExchangeCouponUsageRule { 467 @SerializedName("threshold") 468 public Long threshold; 469 470 @SerializedName("exchange_price") 471 public Long exchangePrice; 472 } 473 474 public enum CouponUsageMethod { 475 @SerializedName("OFFLINE") 476 OFFLINE, 477 @SerializedName("MINI_PROGRAM") 478 MINI_PROGRAM, 479 @SerializedName("APP") 480 APP, 481 @SerializedName("PAYMENT_CODE") 482 PAYMENT_CODE 483 } 484 485 public static class CouponAvailableStoreInfo { 486 @SerializedName("description") 487 public String description; 488 489 @SerializedName("mini_program_appid") 490 public String miniProgramAppid; 491 492 @SerializedName("mini_program_path") 493 public String miniProgramPath; 494 } 495 496 public enum CouponCodeDisplayMode { 497 @SerializedName("INVISIBLE") 498 INVISIBLE, 499 @SerializedName("BARCODE") 500 BARCODE, 501 @SerializedName("QRCODE") 502 QRCODE 503 } 504 505 public static class EntranceMiniProgram { 506 @SerializedName("appid") 507 public String appid; 508 509 @SerializedName("path") 510 public String path; 511 512 @SerializedName("entrance_wording") 513 public String entranceWording; 514 515 @SerializedName("guidance_wording") 516 public String guidanceWording; 517 } 518 519 public static class EntranceOfficialAccount { 520 @SerializedName("appid") 521 public String appid; 522 } 523 524 public static class EntranceFinder { 525 @SerializedName("finder_id") 526 public String finderId; 527 528 @SerializedName("finder_video_id") 529 public String finderVideoId; 530 531 @SerializedName("finder_video_cover_image_url") 532 public String finderVideoCoverImageUrl; 533 } 534 535 public static class FixedWeekPeriod { 536 @SerializedName("day_list") 537 public List<WeekEnum> dayList; 538 539 @SerializedName("day_period_list") 540 public List<PeriodOfTheDay> dayPeriodList; 541 } 542 543 public static class TimePeriod { 544 @SerializedName("begin_time") 545 public String beginTime; 546 547 @SerializedName("end_time") 548 public String endTime; 549 } 550 551 public enum WeekEnum { 552 @SerializedName("MONDAY") 553 MONDAY, 554 @SerializedName("TUESDAY") 555 TUESDAY, 556 @SerializedName("WEDNESDAY") 557 WEDNESDAY, 558 @SerializedName("THURSDAY") 559 THURSDAY, 560 @SerializedName("FRIDAY") 561 FRIDAY, 562 @SerializedName("SATURDAY") 563 SATURDAY, 564 @SerializedName("SUNDAY") 565 SUNDAY 566 } 567 568 public static class PeriodOfTheDay { 569 @SerializedName("begin_time") 570 public Long beginTime; 571 572 @SerializedName("end_time") 573 public Long endTime; 574 } 575 576} 577
需配合微信支付工具库 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 "strings" 11 "time" 12) 13 14func main() { 15 // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/v3/partner/4013080340 16 config, err := wxpay_utility.CreateMchConfig( 17 "19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340 18 "1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号,如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924 19 "/path/to/apiclient_key.pem", // 商户API证书私钥文件路径,本地文件路径 20 "PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID,如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589 21 "/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径 22 ) 23 if err != nil { 24 fmt.Println(err) 25 return 26 } 27 28 request := &CreateStockBundleRequest{ 29 ProductCouponId: wxpay_utility.String("200000001"), 30 OutRequestNo: wxpay_utility.String("34657_20250101_123456"), 31 StockBundle: &StockBundleForCreate{ 32 Remark: wxpay_utility.String("满减券"), 33 CouponCodeMode: COUPONCODEMODE_UPLOAD.Ptr(), 34 StockSendRule: &StockSendRule{ 35 MaxCount: wxpay_utility.Int64(10000000), 36 MaxCountPerDay: wxpay_utility.Int64(10000), 37 MaxCountPerUser: wxpay_utility.Int64(1), 38 }, 39 ProgressiveBundleUsageRule: &StockBundleUsageRule{ 40 CouponAvailablePeriod: &CouponAvailablePeriod{ 41 AvailableBeginTime: wxpay_utility.String("2025-01-01T00:00:00+08:00"), 42 AvailableEndTime: wxpay_utility.String("2025-10-01T00:00:00+08:00"), 43 AvailableDays: wxpay_utility.Int64(10), 44 WaitDaysAfterReceive: wxpay_utility.Int64(1), 45 WeeklyAvailablePeriod: &FixedWeekPeriod{ 46 DayList: []WeekEnum{WEEKENUM_MONDAY}, 47 DayPeriodList: []PeriodOfTheDay{PeriodOfTheDay{ 48 BeginTime: wxpay_utility.Int64(60), 49 EndTime: wxpay_utility.Int64(86399), 50 }}, 51 }, 52 IrregularAvailablePeriodList: []TimePeriod{TimePeriod{ 53 BeginTime: wxpay_utility.String("2025-01-01T00:00:00+08:00"), 54 EndTime: wxpay_utility.String("2025-10-01T00:00:00+08:00"), 55 }}, 56 }, 57 NormalCouponList: []NormalCouponUsageRule{NormalCouponUsageRule{ 58 Threshold: wxpay_utility.Int64(10000), 59 DiscountAmount: wxpay_utility.Int64(100), 60 }}, 61 DiscountCouponList: []DiscountCouponUsageRule{DiscountCouponUsageRule{ 62 Threshold: wxpay_utility.Int64(10000), 63 PercentOff: wxpay_utility.Int64(30), 64 }}, 65 ExchangeCouponList: []ExchangeCouponUsageRule{ExchangeCouponUsageRule{ 66 Threshold: wxpay_utility.Int64(10000), 67 ExchangePrice: wxpay_utility.Int64(100), 68 }}, 69 }, 70 UsageRuleDisplayInfo: &UsageRuleDisplayInfo{ 71 CouponUsageMethodList: []CouponUsageMethod{COUPONUSAGEMETHOD_OFFLINE}, 72 MiniProgramAppid: wxpay_utility.String("wx1234567890"), 73 MiniProgramPath: wxpay_utility.String("/pages/index/product"), 74 AppPath: wxpay_utility.String("https://www.example.com/jump-to-app"), 75 UsageDescription: wxpay_utility.String("全场可用"), 76 CouponAvailableStoreInfo: &CouponAvailableStoreInfo{ 77 Description: wxpay_utility.String("可在上海市区的所有门店使用,详细列表参考小程序内信息为准"), 78 MiniProgramAppid: wxpay_utility.String("wx1234567890"), 79 MiniProgramPath: wxpay_utility.String("/pages/index/store-list"), 80 }, 81 }, 82 CouponDisplayInfo: &CouponDisplayInfo{ 83 CodeDisplayMode: COUPONCODEDISPLAYMODE_QRCODE.Ptr(), 84 BackgroundColor: wxpay_utility.String("Color010"), 85 EntranceMiniProgram: &EntranceMiniProgram{ 86 Appid: wxpay_utility.String("wx1234567890"), 87 Path: wxpay_utility.String("/pages/index/product"), 88 EntranceWording: wxpay_utility.String("欢迎选购"), 89 GuidanceWording: wxpay_utility.String("获取更多优惠"), 90 }, 91 EntranceOfficialAccount: &EntranceOfficialAccount{ 92 Appid: wxpay_utility.String("wx1234567890"), 93 }, 94 EntranceFinder: &EntranceFinder{ 95 FinderId: wxpay_utility.String("gh_12345678"), 96 FinderVideoId: wxpay_utility.String("UDFsdf24df34dD456Hdf34"), 97 FinderVideoCoverImageUrl: wxpay_utility.String("https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx"), 98 }, 99 }, 100 NotifyConfig: &NotifyConfig{ 101 NotifyAppid: wxpay_utility.String("wx4fd12345678"), 102 }, 103 StoreScope: STOCKSTORESCOPE_SPECIFIC.Ptr(), 104 }, 105 BrandId: wxpay_utility.String("120344"), 106 } 107 108 response, err := CreateStockBundle(config, request) 109 if err != nil { 110 fmt.Printf("请求失败: %+v\n", err) 111 // TODO: 请求失败,根据状态码执行不同的处理 112 return 113 } 114 115 // TODO: 请求成功,继续业务逻辑 116 fmt.Printf("请求成功: %+v\n", response) 117} 118 119func CreateStockBundle(config *wxpay_utility.MchConfig, request *CreateStockBundleRequest) (response *StockBundleEntity, err error) { 120 const ( 121 host = "https://api.mch.weixin.qq.com" 122 method = "POST" 123 path = "/v3/marketing/partner/product-coupon/product-coupons/{product_coupon_id}/stock-bundles" 124 ) 125 126 reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path)) 127 if err != nil { 128 return nil, err 129 } 130 reqUrl.Path = strings.Replace(reqUrl.Path, "{product_coupon_id}", url.PathEscape(*request.ProductCouponId), -1) 131 reqBody, err := json.Marshal(request) 132 if err != nil { 133 return nil, err 134 } 135 httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody)) 136 if err != nil { 137 return nil, err 138 } 139 httpRequest.Header.Set("Accept", "application/json") 140 httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId()) 141 httpRequest.Header.Set("Content-Type", "application/json") 142 authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody) 143 if err != nil { 144 return nil, err 145 } 146 httpRequest.Header.Set("Authorization", authorization) 147 148 client := &http.Client{} 149 httpResponse, err := client.Do(httpRequest) 150 if err != nil { 151 return nil, err 152 } 153 respBody, err := wxpay_utility.ExtractResponseBody(httpResponse) 154 if err != nil { 155 return nil, err 156 } 157 if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 { 158 // 2XX 成功,验证应答签名 159 err = wxpay_utility.ValidateResponse( 160 config.WechatPayPublicKeyId(), 161 config.WechatPayPublicKey(), 162 &httpResponse.Header, 163 respBody, 164 ) 165 if err != nil { 166 return nil, err 167 } 168 response := &StockBundleEntity{} 169 if err := json.Unmarshal(respBody, response); err != nil { 170 return nil, err 171 } 172 173 return response, nil 174 } else { 175 return nil, wxpay_utility.NewApiException( 176 httpResponse.StatusCode, 177 httpResponse.Header, 178 respBody, 179 ) 180 } 181} 182 183type CreateStockBundleRequest struct { 184 OutRequestNo *string `json:"out_request_no,omitempty"` 185 ProductCouponId *string `json:"product_coupon_id,omitempty"` 186 StockBundle *StockBundleForCreate `json:"stock_bundle,omitempty"` 187 BrandId *string `json:"brand_id,omitempty"` 188} 189 190func (o *CreateStockBundleRequest) MarshalJSON() ([]byte, error) { 191 type Alias CreateStockBundleRequest 192 a := &struct { 193 ProductCouponId *string `json:"product_coupon_id,omitempty"` 194 *Alias 195 }{ 196 // 序列化时移除非 Body 字段 197 ProductCouponId: nil, 198 Alias: (*Alias)(o), 199 } 200 return json.Marshal(a) 201} 202 203type StockBundleEntity struct { 204 StockBundleId *string `json:"stock_bundle_id,omitempty"` 205 StockList []StockEntityInBundle `json:"stock_list,omitempty"` 206} 207 208type StockBundleForCreate struct { 209 Remark *string `json:"remark,omitempty"` 210 CouponCodeMode *CouponCodeMode `json:"coupon_code_mode,omitempty"` 211 StockSendRule *StockSendRule `json:"stock_send_rule,omitempty"` 212 ProgressiveBundleUsageRule *StockBundleUsageRule `json:"progressive_bundle_usage_rule,omitempty"` 213 UsageRuleDisplayInfo *UsageRuleDisplayInfo `json:"usage_rule_display_info,omitempty"` 214 CouponDisplayInfo *CouponDisplayInfo `json:"coupon_display_info,omitempty"` 215 NotifyConfig *NotifyConfig `json:"notify_config,omitempty"` 216 StoreScope *StockStoreScope `json:"store_scope,omitempty"` 217} 218 219type StockEntityInBundle struct { 220 ProductCouponId *string `json:"product_coupon_id,omitempty"` 221 StockId *string `json:"stock_id,omitempty"` 222 Remark *string `json:"remark,omitempty"` 223 CouponCodeMode *ProgressiveBundleCouponCodeMode `json:"coupon_code_mode,omitempty"` 224 CouponCodeCountInfo *CouponCodeCountInfo `json:"coupon_code_count_info,omitempty"` 225 StockSendRule *StockSendRule `json:"stock_send_rule,omitempty"` 226 ProgressiveBundleUsageRule *StockUsageRule `json:"progressive_bundle_usage_rule,omitempty"` 227 StockBundleInfo *StockBundleInfo `json:"stock_bundle_info,omitempty"` 228 UsageRuleDisplayInfo *UsageRuleDisplayInfo `json:"usage_rule_display_info,omitempty"` 229 CouponDisplayInfo *CouponDisplayInfo `json:"coupon_display_info,omitempty"` 230 NotifyConfig *NotifyConfig `json:"notify_config,omitempty"` 231 StoreScope *StockStoreScope `json:"store_scope,omitempty"` 232 SentCountInfo *StockSentCountInfo `json:"sent_count_info,omitempty"` 233 State *StockState `json:"state,omitempty"` 234 DeactivateRequestNo *string `json:"deactivate_request_no,omitempty"` 235 DeactivateTime *time.Time `json:"deactivate_time,omitempty"` 236 DeactivateReason *string `json:"deactivate_reason,omitempty"` 237 BrandId *string `json:"brand_id,omitempty"` 238} 239 240type CouponCodeMode string 241 242func (e CouponCodeMode) Ptr() *CouponCodeMode { 243 return &e 244} 245 246const ( 247 COUPONCODEMODE_WECHATPAY CouponCodeMode = "WECHATPAY" 248 COUPONCODEMODE_UPLOAD CouponCodeMode = "UPLOAD" 249) 250 251type StockSendRule struct { 252 MaxCount *int64 `json:"max_count,omitempty"` 253 MaxCountPerDay *int64 `json:"max_count_per_day,omitempty"` 254 MaxCountPerUser *int64 `json:"max_count_per_user,omitempty"` 255} 256 257type StockBundleUsageRule struct { 258 CouponAvailablePeriod *CouponAvailablePeriod `json:"coupon_available_period,omitempty"` 259 NormalCouponList []NormalCouponUsageRule `json:"normal_coupon_list,omitempty"` 260 DiscountCouponList []DiscountCouponUsageRule `json:"discount_coupon_list,omitempty"` 261 ExchangeCouponList []ExchangeCouponUsageRule `json:"exchange_coupon_list,omitempty"` 262} 263 264type UsageRuleDisplayInfo struct { 265 CouponUsageMethodList []CouponUsageMethod `json:"coupon_usage_method_list,omitempty"` 266 MiniProgramAppid *string `json:"mini_program_appid,omitempty"` 267 MiniProgramPath *string `json:"mini_program_path,omitempty"` 268 AppPath *string `json:"app_path,omitempty"` 269 UsageDescription *string `json:"usage_description,omitempty"` 270 CouponAvailableStoreInfo *CouponAvailableStoreInfo `json:"coupon_available_store_info,omitempty"` 271} 272 273type CouponDisplayInfo struct { 274 CodeDisplayMode *CouponCodeDisplayMode `json:"code_display_mode,omitempty"` 275 BackgroundColor *string `json:"background_color,omitempty"` 276 EntranceMiniProgram *EntranceMiniProgram `json:"entrance_mini_program,omitempty"` 277 EntranceOfficialAccount *EntranceOfficialAccount `json:"entrance_official_account,omitempty"` 278 EntranceFinder *EntranceFinder `json:"entrance_finder,omitempty"` 279} 280 281type NotifyConfig struct { 282 NotifyAppid *string `json:"notify_appid,omitempty"` 283} 284 285type StockStoreScope string 286 287func (e StockStoreScope) Ptr() *StockStoreScope { 288 return &e 289} 290 291const ( 292 STOCKSTORESCOPE_NONE StockStoreScope = "NONE" 293 STOCKSTORESCOPE_ALL StockStoreScope = "ALL" 294 STOCKSTORESCOPE_SPECIFIC StockStoreScope = "SPECIFIC" 295) 296 297type ProgressiveBundleCouponCodeMode string 298 299func (e ProgressiveBundleCouponCodeMode) Ptr() *ProgressiveBundleCouponCodeMode { 300 return &e 301} 302 303const ( 304 PROGRESSIVEBUNDLECOUPONCODEMODE_WECHATPAY ProgressiveBundleCouponCodeMode = "WECHATPAY" 305 PROGRESSIVEBUNDLECOUPONCODEMODE_UPLOAD ProgressiveBundleCouponCodeMode = "UPLOAD" 306) 307 308type CouponCodeCountInfo struct { 309 TotalCount *int64 `json:"total_count,omitempty"` 310 AvailableCount *int64 `json:"available_count,omitempty"` 311} 312 313type StockUsageRule struct { 314 CouponAvailablePeriod *CouponAvailablePeriod `json:"coupon_available_period,omitempty"` 315 NormalCoupon *NormalCouponUsageRule `json:"normal_coupon,omitempty"` 316 DiscountCoupon *DiscountCouponUsageRule `json:"discount_coupon,omitempty"` 317 ExchangeCoupon *ExchangeCouponUsageRule `json:"exchange_coupon,omitempty"` 318} 319 320type StockBundleInfo struct { 321 StockBundleId *string `json:"stock_bundle_id,omitempty"` 322 StockBundleIndex *int64 `json:"stock_bundle_index,omitempty"` 323} 324 325type StockSentCountInfo struct { 326 TotalCount *int64 `json:"total_count,omitempty"` 327 TodayCount *int64 `json:"today_count,omitempty"` 328} 329 330type StockState string 331 332func (e StockState) Ptr() *StockState { 333 return &e 334} 335 336const ( 337 STOCKSTATE_AUDITING StockState = "AUDITING" 338 STOCKSTATE_SENDING StockState = "SENDING" 339 STOCKSTATE_PAUSED StockState = "PAUSED" 340 STOCKSTATE_STOPPED StockState = "STOPPED" 341 STOCKSTATE_DEACTIVATED StockState = "DEACTIVATED" 342) 343 344type CouponAvailablePeriod struct { 345 AvailableBeginTime *string `json:"available_begin_time,omitempty"` 346 AvailableEndTime *string `json:"available_end_time,omitempty"` 347 AvailableDays *int64 `json:"available_days,omitempty"` 348 WaitDaysAfterReceive *int64 `json:"wait_days_after_receive,omitempty"` 349 WeeklyAvailablePeriod *FixedWeekPeriod `json:"weekly_available_period,omitempty"` 350 IrregularAvailablePeriodList []TimePeriod `json:"irregular_available_period_list,omitempty"` 351} 352 353type NormalCouponUsageRule struct { 354 Threshold *int64 `json:"threshold,omitempty"` 355 DiscountAmount *int64 `json:"discount_amount,omitempty"` 356} 357 358type DiscountCouponUsageRule struct { 359 Threshold *int64 `json:"threshold,omitempty"` 360 PercentOff *int64 `json:"percent_off,omitempty"` 361} 362 363type ExchangeCouponUsageRule struct { 364 Threshold *int64 `json:"threshold,omitempty"` 365 ExchangePrice *int64 `json:"exchange_price,omitempty"` 366} 367 368type CouponUsageMethod string 369 370func (e CouponUsageMethod) Ptr() *CouponUsageMethod { 371 return &e 372} 373 374const ( 375 COUPONUSAGEMETHOD_OFFLINE CouponUsageMethod = "OFFLINE" 376 COUPONUSAGEMETHOD_MINI_PROGRAM CouponUsageMethod = "MINI_PROGRAM" 377 COUPONUSAGEMETHOD_APP CouponUsageMethod = "APP" 378 COUPONUSAGEMETHOD_PAYMENT_CODE CouponUsageMethod = "PAYMENT_CODE" 379) 380 381type CouponAvailableStoreInfo struct { 382 Description *string `json:"description,omitempty"` 383 MiniProgramAppid *string `json:"mini_program_appid,omitempty"` 384 MiniProgramPath *string `json:"mini_program_path,omitempty"` 385} 386 387type CouponCodeDisplayMode string 388 389func (e CouponCodeDisplayMode) Ptr() *CouponCodeDisplayMode { 390 return &e 391} 392 393const ( 394 COUPONCODEDISPLAYMODE_INVISIBLE CouponCodeDisplayMode = "INVISIBLE" 395 COUPONCODEDISPLAYMODE_BARCODE CouponCodeDisplayMode = "BARCODE" 396 COUPONCODEDISPLAYMODE_QRCODE CouponCodeDisplayMode = "QRCODE" 397) 398 399type EntranceMiniProgram struct { 400 Appid *string `json:"appid,omitempty"` 401 Path *string `json:"path,omitempty"` 402 EntranceWording *string `json:"entrance_wording,omitempty"` 403 GuidanceWording *string `json:"guidance_wording,omitempty"` 404} 405 406type EntranceOfficialAccount struct { 407 Appid *string `json:"appid,omitempty"` 408} 409 410type EntranceFinder struct { 411 FinderId *string `json:"finder_id,omitempty"` 412 FinderVideoId *string `json:"finder_video_id,omitempty"` 413 FinderVideoCoverImageUrl *string `json:"finder_video_cover_image_url,omitempty"` 414} 415 416type FixedWeekPeriod struct { 417 DayList []WeekEnum `json:"day_list,omitempty"` 418 DayPeriodList []PeriodOfTheDay `json:"day_period_list,omitempty"` 419} 420 421type TimePeriod struct { 422 BeginTime *string `json:"begin_time,omitempty"` 423 EndTime *string `json:"end_time,omitempty"` 424} 425 426type WeekEnum string 427 428func (e WeekEnum) Ptr() *WeekEnum { 429 return &e 430} 431 432const ( 433 WEEKENUM_MONDAY WeekEnum = "MONDAY" 434 WEEKENUM_TUESDAY WeekEnum = "TUESDAY" 435 WEEKENUM_WEDNESDAY WeekEnum = "WEDNESDAY" 436 WEEKENUM_THURSDAY WeekEnum = "THURSDAY" 437 WEEKENUM_FRIDAY WeekEnum = "FRIDAY" 438 WEEKENUM_SATURDAY WeekEnum = "SATURDAY" 439 WEEKENUM_SUNDAY WeekEnum = "SUNDAY" 440) 441 442type PeriodOfTheDay struct { 443 BeginTime *int64 `json:"begin_time,omitempty"` 444 EndTime *int64 `json:"end_time,omitempty"` 445} 446
应答参数
200 OK
stock_bundle_id 必填 string(40)
【批次组ID】 商品券批次组的唯一标识,由微信支付生成
stock_list 必填 array[object]
【批次列表】 批次组内批次列表
| 属性 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
product_coupon_id 必填 string(40) 【商品券ID】 商品券的唯一标识,由微信支付生成 stock_id 必填 string(40) 【批次ID】 商品券批次的唯一标识,由微信支付生成 remark 选填 string(20) 【备注】 仅配置品牌可见,用于自定义信息 coupon_code_mode 必填 string 【券Code分配模式】 决定发券时用户商品券Code如何产生 可选取值
coupon_code_count_info 选填 object 【品牌方预上传的券Code数量信息】 当且仅当
stock_send_rule 必填 object 【发放规则】 发放规则
progressive_bundle_usage_rule 选填 object 【多次优惠使用规则】 本批次属于某个多次优惠批次组,这里记录的是本批次的使用规则,当且仅当
stock_bundle_info 必填 object 【批次组信息】 批次所在批次组信息
usage_rule_display_info 必填 object 【券使用规则展示信息】 券使用规则展示信息
coupon_display_info 必填 object 【用户商品券展示信息】 用户商品券在卡包中的展示详情,包括引导用户的自定义入口
notify_config 必填 object 【事件通知配置】 发生券相关事件时,微信支付会向服务商发送通知,需要提供通知相关配置
store_scope 必填 string 【可用门店范围】 控制该批次可以在品牌下哪些门店使用 可选取值
sent_count_info 必填 object 【已发放次数】 本批次已发放次数
state 必填 string 【批次状态】 商品券批次状态 可选取值
deactivate_request_no 选填 string(128) 【失效请求单号】 当且仅当 deactivate_time 选填 string 【失效时间】 当且仅当 deactivate_reason 选填 string(150) 【失效原因】 当且仅当 brand_id 必填 string 【品牌ID】 微信支付为品牌方分配的唯一标识,该品牌应与服务商存在授权关系 |
应答示例
200 OK
1{ 2 "stock_bundle_id" : "123456789", 3 "stock_list" : [ 4 { 5 "product_coupon_id" : "200000001", 6 "stock_id" : "123456789", 7 "remark" : "满减券", 8 "coupon_code_mode" : "UPLOAD", 9 "coupon_code_count_info" : { 10 "total_count" : 10000, 11 "available_count" : 999 12 }, 13 "stock_send_rule" : { 14 "max_count" : 10000000, 15 "max_count_per_day" : 10000, 16 "max_count_per_user" : 1 17 }, 18 "progressive_bundle_usage_rule" : { 19 "coupon_available_period" : { 20 "available_begin_time" : "2025-01-01T00:00:00+08:00", 21 "available_end_time" : "2025-10-01T00:00:00+08:00", 22 "available_days" : 10, 23 "wait_days_after_receive" : 1, 24 "weekly_available_period" : { 25 "day_list" : [ 26 "MONDAY" 27 ], 28 "day_period_list" : [ 29 { 30 "begin_time" : 60, 31 "end_time" : 86399 32 } 33 ] 34 }, 35 "irregular_available_period_list" : [ 36 { 37 "begin_time" : "2025-01-01T00:00:00+08:00", 38 "end_time" : "2025-10-01T00:00:00+08:00" 39 } 40 ] 41 }, 42 "normal_coupon" : { 43 "threshold" : 10000, 44 "discount_amount" : 100 45 }, 46 "discount_coupon" : { 47 "threshold" : 10000, 48 "percent_off" : 30 49 }, 50 "exchange_coupon" : { 51 "threshold" : 10000, 52 "exchange_price" : 100 53 } 54 }, 55 "stock_bundle_info" : { 56 "stock_bundle_id" : "123456789", 57 "stock_bundle_index" : 0 58 }, 59 "usage_rule_display_info" : { 60 "coupon_usage_method_list" : [ 61 "MINI_PROGRAM" 62 ], 63 "mini_program_appid" : "wx1234567890", 64 "mini_program_path" : "/pages/index/product", 65 "app_path" : "https://www.example.com/jump-to-app", 66 "usage_description" : "全场可用", 67 "coupon_available_store_info" : { 68 "description" : "可在上海市区的所有门店使用,详细列表参考小程序内信息为准", 69 "mini_program_appid" : "wx1234567890", 70 "mini_program_path" : "/pages/index/store-list" 71 } 72 }, 73 "coupon_display_info" : { 74 "code_display_mode" : "QRCODE", 75 "background_color" : "Color010", 76 "entrance_mini_program" : { 77 "appid" : "wx1234567890", 78 "path" : "/pages/index/product", 79 "entrance_wording" : "欢迎选购", 80 "guidance_wording" : "获取更多优惠" 81 }, 82 "entrance_official_account" : { 83 "appid" : "wx1234567890" 84 }, 85 "entrance_finder" : { 86 "finder_id" : "gh_12345678", 87 "finder_video_id" : "UDFsdf24df34dD456Hdf34", 88 "finder_video_cover_image_url" : "https://wxpaylogo.qpic.cn/wxpaylogo/xxxxx/xxx" 89 } 90 }, 91 "notify_config" : { 92 "notify_appid" : "wx4fd12345678" 93 }, 94 "store_scope" : "SPECIFIC", 95 "sent_count_info" : { 96 "total_count" : 100, 97 "today_count" : 10 98 }, 99 "state" : "SENDING", 100 "deactivate_request_no" : "1002600620019090123143254436", 101 "deactivate_time" : "2025-01-01T00:00+08:00", 102 "deactivate_reason" : "批次信息有误,重新创建", 103 "brand_id" : "120344" 104 } 105 ] 106} 107
错误码
以下是本接口返回的错误码列表。详细错误码规则,请参考微信支付接口规则-错误码和错误提示
状态码 | 错误码 | 描述 | 解决方案 |
|---|---|---|---|
400 | PARAM_ERROR | 参数错误 | 请根据错误提示正确传入参数 |
400 | INVALID_REQUEST | HTTP 请求不符合微信支付 APIv3 接口规则 | 请参阅 接口规则 |
401 | SIGN_ERROR | 验证不通过 | 请参阅 签名常见问题 |
500 | SYSTEM_ERROR | 系统异常,请稍后重试 | 请稍后重试 |
400 | INVALID_REQUEST | 传入参数不符合业务规则 | 请参考文档中对每个字段的要求以及组合要求,确认请求参数是否满足 |
400 | ALREADY_EXISTS | 商品券批次组已存在 | 确认 out_request_no 字段是否重复使用,确保不同请求的 out_request_no 唯一 |
404 | NOT_FOUND | 未找到 product_coupon_id 对应的商品券 | 请确认 product_coupon_id 存在且属于当前品牌 |
429 | RATELIMIT_EXCEEDED | 请求超过接口频率限制 | 请稍后使用原参数重试 |

