添加商品券批次组
更新时间: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 CouponCodeMode 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 static class CouponCodeCountInfo { 373 @SerializedName("total_count") 374 public Long totalCount; 375 376 @SerializedName("available_count") 377 public Long availableCount; 378 } 379 380 public static class StockUsageRule { 381 @SerializedName("coupon_available_period") 382 public CouponAvailablePeriod couponAvailablePeriod; 383 384 @SerializedName("normal_coupon") 385 public NormalCouponUsageRule normalCoupon; 386 387 @SerializedName("discount_coupon") 388 public DiscountCouponUsageRule discountCoupon; 389 390 @SerializedName("exchange_coupon") 391 public ExchangeCouponUsageRule exchangeCoupon; 392 } 393 394 public static class StockBundleInfo { 395 @SerializedName("stock_bundle_id") 396 public String stockBundleId; 397 398 @SerializedName("stock_bundle_index") 399 public Long stockBundleIndex; 400 } 401 402 public static class StockSentCountInfo { 403 @SerializedName("total_count") 404 public Long totalCount; 405 406 @SerializedName("today_count") 407 public Long todayCount; 408 } 409 410 public enum StockState { 411 @SerializedName("AUDITING") 412 AUDITING, 413 @SerializedName("SENDING") 414 SENDING, 415 @SerializedName("PAUSED") 416 PAUSED, 417 @SerializedName("STOPPED") 418 STOPPED, 419 @SerializedName("DEACTIVATED") 420 DEACTIVATED 421 } 422 423 public static class CouponAvailablePeriod { 424 @SerializedName("available_begin_time") 425 public String availableBeginTime; 426 427 @SerializedName("available_end_time") 428 public String availableEndTime; 429 430 @SerializedName("available_days") 431 public Long availableDays; 432 433 @SerializedName("wait_days_after_receive") 434 public Long waitDaysAfterReceive; 435 436 @SerializedName("weekly_available_period") 437 public FixedWeekPeriod weeklyAvailablePeriod; 438 439 @SerializedName("irregular_available_period_list") 440 public List<TimePeriod> irregularAvailablePeriodList; 441 } 442 443 public static class NormalCouponUsageRule { 444 @SerializedName("threshold") 445 public Long threshold; 446 447 @SerializedName("discount_amount") 448 public Long discountAmount; 449 } 450 451 public static class DiscountCouponUsageRule { 452 @SerializedName("threshold") 453 public Long threshold; 454 455 @SerializedName("percent_off") 456 public Long percentOff; 457 } 458 459 public static class ExchangeCouponUsageRule { 460 @SerializedName("threshold") 461 public Long threshold; 462 463 @SerializedName("exchange_price") 464 public Long exchangePrice; 465 } 466 467 public enum CouponUsageMethod { 468 @SerializedName("OFFLINE") 469 OFFLINE, 470 @SerializedName("MINI_PROGRAM") 471 MINI_PROGRAM, 472 @SerializedName("APP") 473 APP, 474 @SerializedName("PAYMENT_CODE") 475 PAYMENT_CODE 476 } 477 478 public static class CouponAvailableStoreInfo { 479 @SerializedName("description") 480 public String description; 481 482 @SerializedName("mini_program_appid") 483 public String miniProgramAppid; 484 485 @SerializedName("mini_program_path") 486 public String miniProgramPath; 487 } 488 489 public enum CouponCodeDisplayMode { 490 @SerializedName("INVISIBLE") 491 INVISIBLE, 492 @SerializedName("BARCODE") 493 BARCODE, 494 @SerializedName("QRCODE") 495 QRCODE 496 } 497 498 public static class EntranceMiniProgram { 499 @SerializedName("appid") 500 public String appid; 501 502 @SerializedName("path") 503 public String path; 504 505 @SerializedName("entrance_wording") 506 public String entranceWording; 507 508 @SerializedName("guidance_wording") 509 public String guidanceWording; 510 } 511 512 public static class EntranceOfficialAccount { 513 @SerializedName("appid") 514 public String appid; 515 } 516 517 public static class EntranceFinder { 518 @SerializedName("finder_id") 519 public String finderId; 520 521 @SerializedName("finder_video_id") 522 public String finderVideoId; 523 524 @SerializedName("finder_video_cover_image_url") 525 public String finderVideoCoverImageUrl; 526 } 527 528 public static class FixedWeekPeriod { 529 @SerializedName("day_list") 530 public List<WeekEnum> dayList; 531 532 @SerializedName("day_period_list") 533 public List<PeriodOfTheDay> dayPeriodList; 534 } 535 536 public static class TimePeriod { 537 @SerializedName("begin_time") 538 public String beginTime; 539 540 @SerializedName("end_time") 541 public String endTime; 542 } 543 544 public enum WeekEnum { 545 @SerializedName("MONDAY") 546 MONDAY, 547 @SerializedName("TUESDAY") 548 TUESDAY, 549 @SerializedName("WEDNESDAY") 550 WEDNESDAY, 551 @SerializedName("THURSDAY") 552 THURSDAY, 553 @SerializedName("FRIDAY") 554 FRIDAY, 555 @SerializedName("SATURDAY") 556 SATURDAY, 557 @SerializedName("SUNDAY") 558 SUNDAY 559 } 560 561 public static class PeriodOfTheDay { 562 @SerializedName("begin_time") 563 public Long beginTime; 564 565 @SerializedName("end_time") 566 public Long endTime; 567 } 568 569} 570
需配合微信支付工具库 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 *CouponCodeMode `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 CouponCodeCountInfo struct { 298 TotalCount *int64 `json:"total_count,omitempty"` 299 AvailableCount *int64 `json:"available_count,omitempty"` 300} 301 302type StockUsageRule struct { 303 CouponAvailablePeriod *CouponAvailablePeriod `json:"coupon_available_period,omitempty"` 304 NormalCoupon *NormalCouponUsageRule `json:"normal_coupon,omitempty"` 305 DiscountCoupon *DiscountCouponUsageRule `json:"discount_coupon,omitempty"` 306 ExchangeCoupon *ExchangeCouponUsageRule `json:"exchange_coupon,omitempty"` 307} 308 309type StockBundleInfo struct { 310 StockBundleId *string `json:"stock_bundle_id,omitempty"` 311 StockBundleIndex *int64 `json:"stock_bundle_index,omitempty"` 312} 313 314type StockSentCountInfo struct { 315 TotalCount *int64 `json:"total_count,omitempty"` 316 TodayCount *int64 `json:"today_count,omitempty"` 317} 318 319type StockState string 320 321func (e StockState) Ptr() *StockState { 322 return &e 323} 324 325const ( 326 STOCKSTATE_AUDITING StockState = "AUDITING" 327 STOCKSTATE_SENDING StockState = "SENDING" 328 STOCKSTATE_PAUSED StockState = "PAUSED" 329 STOCKSTATE_STOPPED StockState = "STOPPED" 330 STOCKSTATE_DEACTIVATED StockState = "DEACTIVATED" 331) 332 333type CouponAvailablePeriod struct { 334 AvailableBeginTime *string `json:"available_begin_time,omitempty"` 335 AvailableEndTime *string `json:"available_end_time,omitempty"` 336 AvailableDays *int64 `json:"available_days,omitempty"` 337 WaitDaysAfterReceive *int64 `json:"wait_days_after_receive,omitempty"` 338 WeeklyAvailablePeriod *FixedWeekPeriod `json:"weekly_available_period,omitempty"` 339 IrregularAvailablePeriodList []TimePeriod `json:"irregular_available_period_list,omitempty"` 340} 341 342type NormalCouponUsageRule struct { 343 Threshold *int64 `json:"threshold,omitempty"` 344 DiscountAmount *int64 `json:"discount_amount,omitempty"` 345} 346 347type DiscountCouponUsageRule struct { 348 Threshold *int64 `json:"threshold,omitempty"` 349 PercentOff *int64 `json:"percent_off,omitempty"` 350} 351 352type ExchangeCouponUsageRule struct { 353 Threshold *int64 `json:"threshold,omitempty"` 354 ExchangePrice *int64 `json:"exchange_price,omitempty"` 355} 356 357type CouponUsageMethod string 358 359func (e CouponUsageMethod) Ptr() *CouponUsageMethod { 360 return &e 361} 362 363const ( 364 COUPONUSAGEMETHOD_OFFLINE CouponUsageMethod = "OFFLINE" 365 COUPONUSAGEMETHOD_MINI_PROGRAM CouponUsageMethod = "MINI_PROGRAM" 366 COUPONUSAGEMETHOD_APP CouponUsageMethod = "APP" 367 COUPONUSAGEMETHOD_PAYMENT_CODE CouponUsageMethod = "PAYMENT_CODE" 368) 369 370type CouponAvailableStoreInfo struct { 371 Description *string `json:"description,omitempty"` 372 MiniProgramAppid *string `json:"mini_program_appid,omitempty"` 373 MiniProgramPath *string `json:"mini_program_path,omitempty"` 374} 375 376type CouponCodeDisplayMode string 377 378func (e CouponCodeDisplayMode) Ptr() *CouponCodeDisplayMode { 379 return &e 380} 381 382const ( 383 COUPONCODEDISPLAYMODE_INVISIBLE CouponCodeDisplayMode = "INVISIBLE" 384 COUPONCODEDISPLAYMODE_BARCODE CouponCodeDisplayMode = "BARCODE" 385 COUPONCODEDISPLAYMODE_QRCODE CouponCodeDisplayMode = "QRCODE" 386) 387 388type EntranceMiniProgram struct { 389 Appid *string `json:"appid,omitempty"` 390 Path *string `json:"path,omitempty"` 391 EntranceWording *string `json:"entrance_wording,omitempty"` 392 GuidanceWording *string `json:"guidance_wording,omitempty"` 393} 394 395type EntranceOfficialAccount struct { 396 Appid *string `json:"appid,omitempty"` 397} 398 399type EntranceFinder struct { 400 FinderId *string `json:"finder_id,omitempty"` 401 FinderVideoId *string `json:"finder_video_id,omitempty"` 402 FinderVideoCoverImageUrl *string `json:"finder_video_cover_image_url,omitempty"` 403} 404 405type FixedWeekPeriod struct { 406 DayList []WeekEnum `json:"day_list,omitempty"` 407 DayPeriodList []PeriodOfTheDay `json:"day_period_list,omitempty"` 408} 409 410type TimePeriod struct { 411 BeginTime *string `json:"begin_time,omitempty"` 412 EndTime *string `json:"end_time,omitempty"` 413} 414 415type WeekEnum string 416 417func (e WeekEnum) Ptr() *WeekEnum { 418 return &e 419} 420 421const ( 422 WEEKENUM_MONDAY WeekEnum = "MONDAY" 423 WEEKENUM_TUESDAY WeekEnum = "TUESDAY" 424 WEEKENUM_WEDNESDAY WeekEnum = "WEDNESDAY" 425 WEEKENUM_THURSDAY WeekEnum = "THURSDAY" 426 WEEKENUM_FRIDAY WeekEnum = "FRIDAY" 427 WEEKENUM_SATURDAY WeekEnum = "SATURDAY" 428 WEEKENUM_SUNDAY WeekEnum = "SUNDAY" 429) 430 431type PeriodOfTheDay struct { 432 BeginTime *int64 `json:"begin_time,omitempty"` 433 EndTime *int64 `json:"end_time,omitempty"` 434} 435
应答参数
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 | 请求超过接口频率限制 | 请稍后使用原参数重试 |


