批次组批量取消关联门店
更新时间:2025.11.27品牌方可以通过该接口取消品牌的门店列表与商品券批次组内所有批次的关联关系
前置条件:
已创建
usage_mode为PROGRESSIVE_BUNDLE的商品券对应的批次组批次组内批次的
store_scope为SPECIFIC批次组内批次未失效或过期
频率限制:20/s
接口说明
支持商户:【品牌商户】
请求方式:【POST】/brand/marketing/product-coupon/product-coupons/{product_coupon_id}/stock-bundles/{stock_bundle_id}/disassociate-stores
请求域名:【主域名】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
Wechatpay-Serial 必填 string
【微信支付公钥ID】 请传入brand_id对应的微信支付公钥ID,接口将会校验两者的关联关系,参考微信支付公钥产品简介及使用说明获取微信支付公钥ID和相关的介绍。以下两种场景将使用到微信支付公钥: 1、接收到接口的返回内容,需要使用微信支付公钥进行验签; 2、调用含有敏感信息参数(如姓名、身份证号码)的接口时,需要使用微信支付公钥加密敏感信息后再传输参数,加密指引请参考微信支付公钥加密敏感信息指引。
path 路径参数
product_coupon_id 必填 string
【商品券ID】 商品券的唯一标识,创建商品券时由微信支付生成
stock_bundle_id 必填 string
【批次组ID】 商品券批次组的唯一标识,【创建商品券(多次优惠)】或【添加商品券批次组】时由微信支付生成,本接口会同步取消关联门店信息到批次组内所有批次。请确保该批次组属于 product_coupon_id 对应的商品券,且 store_scope 为 SPECIFIC,否则无法取消关联门店
body 包体参数
store_list 必填 array[object]
【门店列表】 商户欲取消关联的门店列表,
单次最多可批量取消200个门店
| 属性 | |
store_id 必填 string 【门店ID】 门店的唯一标识,调用【创建品牌门店API】时由微信支付生成 |
请求示例
POST
1curl -X POST \ 2 https://api.mch.weixin.qq.com/brand/marketing/product-coupon/product-coupons/200000001/stock-bundles/123456789/disassociate-stores \ 3 -H "Authorization: WECHATPAY-BRAND-SHA256-RSA2048 brand_id=\"XXXX\",..." \ 4 -H "Accept: application/json" \ 5 -H "Wechatpay-Serial: PUB_KEY_ID_XXXX" \ 6 -H "Content-Type: application/json" \ 7 -d '{ 8 "store_list" : [ 9 { 10 "store_id" : "100000001" 11 } 12 ] 13 }' 14
需配合微信支付工具库 WXPayUtility 使用,请参考Java
1package com.java.demo; 2 3import com.java.utils.WXPayBrandUtility; // 引用微信支付工具库,参考:https://pay.weixin.qq.com/doc/brand/4015826861 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 DisassociateStoresForStockBundle { 26 private static String HOST = "https://api.mch.weixin.qq.com"; 27 private static String METHOD = "POST"; 28 private static String PATH = "/brand/marketing/product-coupon/product-coupons/{product_coupon_id}/stock-bundles/{stock_bundle_id}/disassociate-stores"; 29 30 public static void main(String[] args) { 31 // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/brand/4015415289 32 DisassociateStoresForStockBundle client = new DisassociateStoresForStockBundle( 33 "xxxxxxxx", // 品牌ID,是由微信支付系统生成并分配给每个品牌方的唯一标识符,品牌ID获取方式参考 https://pay.weixin.qq.com/doc/brand/4015415289 34 "1DDE55AD98Exxxxxxxxxx", // 品牌API证书序列号,如何获取请参考 https://pay.weixin.qq.com/doc/brand/4015407570 35 "/path/to/apiclient_key.pem", // 品牌API证书私钥文件路径,本地文件路径 36 "PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID,如何获取请参考 https://pay.weixin.qq.com/doc/brand/4015453439 37 "/path/to/wxp_pub.pem" // 微信支付公钥文件路径,本地文件路径 38 ); 39 40 DisassociateStoresForStockBundleRequest request = new DisassociateStoresForStockBundleRequest(); 41 request.productCouponId = "200000001"; 42 request.stockBundleId = "123456789"; 43 request.storeList = new ArrayList<>(); 44 { 45 StoreInfo storeListItem = new StoreInfo(); 46 storeListItem.storeId = "100000001"; 47 request.storeList.add(storeListItem); 48 }; 49 try { 50 DisassociateStoresResponse response = client.run(request); 51 // TODO: 请求成功,继续业务逻辑 52 System.out.println(response); 53 } catch (WXPayBrandUtility.ApiException e) { 54 // TODO: 请求失败,根据状态码执行不同的逻辑 55 e.printStackTrace(); 56 } 57 } 58 59 public DisassociateStoresResponse run(DisassociateStoresForStockBundleRequest request) { 60 String uri = PATH; 61 uri = uri.replace("{product_coupon_id}", WXPayBrandUtility.urlEncode(request.productCouponId)); 62 uri = uri.replace("{stock_bundle_id}", WXPayBrandUtility.urlEncode(request.stockBundleId)); 63 String reqBody = WXPayBrandUtility.toJson(request); 64 65 Request.Builder reqBuilder = new Request.Builder().url(HOST + uri); 66 reqBuilder.addHeader("Accept", "application/json"); 67 reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId); 68 reqBuilder.addHeader("Authorization", WXPayBrandUtility.buildAuthorization(brand_id, certificateSerialNo,privateKey, METHOD, uri, reqBody)); 69 reqBuilder.addHeader("Content-Type", "application/json"); 70 RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody); 71 reqBuilder.method(METHOD, requestBody); 72 Request httpRequest = reqBuilder.build(); 73 74 // 发送HTTP请求 75 OkHttpClient client = new OkHttpClient.Builder().build(); 76 try (Response httpResponse = client.newCall(httpRequest).execute()) { 77 String respBody = WXPayBrandUtility.extractBody(httpResponse); 78 if (httpResponse.code() >= 200 && httpResponse.code() < 300) { 79 // 2XX 成功,验证应答签名 80 WXPayBrandUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey, 81 httpResponse.headers(), respBody); 82 83 // 从HTTP应答报文构建返回数据 84 return WXPayBrandUtility.fromJson(respBody, DisassociateStoresResponse.class); 85 } else { 86 throw new WXPayBrandUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers()); 87 } 88 } catch (IOException e) { 89 throw new UncheckedIOException("Sending request to " + uri + " failed.", e); 90 } 91 } 92 93 private final String brand_id; 94 private final String certificateSerialNo; 95 private final PrivateKey privateKey; 96 private final String wechatPayPublicKeyId; 97 private final PublicKey wechatPayPublicKey; 98 99 public DisassociateStoresForStockBundle(String brand_id, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) { 100 this.brand_id = brand_id; 101 this.certificateSerialNo = certificateSerialNo; 102 this.privateKey = WXPayBrandUtility.loadPrivateKeyFromPath(privateKeyFilePath); 103 this.wechatPayPublicKeyId = wechatPayPublicKeyId; 104 this.wechatPayPublicKey = WXPayBrandUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath); 105 } 106 107 public static class DisassociateStoresForStockBundleRequest { 108 @SerializedName("product_coupon_id") 109 @Expose(serialize = false) 110 public String productCouponId; 111 112 @SerializedName("stock_bundle_id") 113 @Expose(serialize = false) 114 public String stockBundleId; 115 116 @SerializedName("store_list") 117 public List<StoreInfo> storeList = new ArrayList<StoreInfo>(); 118 } 119 120 public static class DisassociateStoresResponse { 121 @SerializedName("total_count") 122 public Long totalCount; 123 124 @SerializedName("success_store_list") 125 public List<StoreInfo> successStoreList; 126 127 @SerializedName("failed_store_list") 128 public List<FailedStoreInfo> failedStoreList; 129 } 130 131 public static class StoreInfo { 132 @SerializedName("store_id") 133 public String storeId; 134 } 135 136 public static class FailedStoreInfo { 137 @SerializedName("store_id") 138 public String storeId; 139 140 @SerializedName("code") 141 public String code; 142 143 @SerializedName("message") 144 public String message; 145 } 146 147} 148
需配合微信支付工具库 wxpay_utility 使用,请参考Go
1package main 2 3import ( 4 "bytes" 5 "demo/wxpay_brand_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/brand/4015826866 6 "encoding/json" 7 "fmt" 8 "net/http" 9 "net/url" 10 "strings" 11) 12 13func main() { 14 // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/brand/4015415289 15 config, err := wxpay_brand_utility.CreateBrandConfig( 16 "xxxxxxxx", // 品牌ID,是由微信支付系统生成并分配给每个品牌方的唯一标识符,品牌ID获取方式参考 https://pay.weixin.qq.com/doc/brand/4015415289 17 "1DDE55AD98Exxxxxxxxxx", // 品牌API证书序列号,如何获取请参考 https://pay.weixin.qq.com/doc/brand/4015407570 18 "/path/to/apiclient_key.pem", // 品牌API证书私钥文件路径,本地文件路径 19 "PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID,如何获取请参考 https://pay.weixin.qq.com/doc/brand/4015453439 20 "/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径 21 ) 22 if err != nil { 23 fmt.Println(err) 24 return 25 } 26 27 request := &DisassociateStoresForStockBundleRequest{ 28 ProductCouponId: wxpay_brand_utility.String("200000001"), 29 StockBundleId: wxpay_brand_utility.String("123456789"), 30 StoreList: []StoreInfo{StoreInfo{ 31 StoreId: wxpay_brand_utility.String("100000001"), 32 }}, 33 } 34 35 response, err := DisassociateStoresForStockBundle(config, request) 36 if err != nil { 37 fmt.Printf("请求失败: %+v\n", err) 38 // TODO: 请求失败,根据状态码执行不同的处理 39 return 40 } 41 42 // TODO: 请求成功,继续业务逻辑 43 fmt.Printf("请求成功: %+v\n", response) 44} 45 46func DisassociateStoresForStockBundle(config *wxpay_brand_utility.BrandConfig, request *DisassociateStoresForStockBundleRequest) (response *DisassociateStoresResponse, err error) { 47 const ( 48 host = "https://api.mch.weixin.qq.com" 49 method = "POST" 50 path = "/brand/marketing/product-coupon/product-coupons/{product_coupon_id}/stock-bundles/{stock_bundle_id}/disassociate-stores" 51 ) 52 53 reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path)) 54 if err != nil { 55 return nil, err 56 } 57 reqUrl.Path = strings.Replace(reqUrl.Path, "{product_coupon_id}", url.PathEscape(*request.ProductCouponId), -1) 58 reqUrl.Path = strings.Replace(reqUrl.Path, "{stock_bundle_id}", url.PathEscape(*request.StockBundleId), -1) 59 reqBody, err := json.Marshal(request) 60 if err != nil { 61 return nil, err 62 } 63 httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody)) 64 if err != nil { 65 return nil, err 66 } 67 httpRequest.Header.Set("Accept", "application/json") 68 httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId()) 69 httpRequest.Header.Set("Content-Type", "application/json") 70 authorization, err := wxpay_brand_utility.BuildAuthorization(config.BrandId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody) 71 if err != nil { 72 return nil, err 73 } 74 httpRequest.Header.Set("Authorization", authorization) 75 76 client := &http.Client{} 77 httpResponse, err := client.Do(httpRequest) 78 if err != nil { 79 return nil, err 80 } 81 respBody, err := wxpay_brand_utility.ExtractResponseBody(httpResponse) 82 if err != nil { 83 return nil, err 84 } 85 if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 { 86 // 2XX 成功,验证应答签名 87 err = wxpay_brand_utility.ValidateResponse( 88 config.WechatPayPublicKeyId(), 89 config.WechatPayPublicKey(), 90 &httpResponse.Header, 91 respBody, 92 ) 93 if err != nil { 94 return nil, err 95 } 96 response := &DisassociateStoresResponse{} 97 if err := json.Unmarshal(respBody, response); err != nil { 98 return nil, err 99 } 100 101 return response, nil 102 } else { 103 return nil, wxpay_brand_utility.NewApiException( 104 httpResponse.StatusCode, 105 httpResponse.Header, 106 respBody, 107 ) 108 } 109} 110 111type DisassociateStoresForStockBundleRequest struct { 112 ProductCouponId *string `json:"product_coupon_id,omitempty"` 113 StockBundleId *string `json:"stock_bundle_id,omitempty"` 114 StoreList []StoreInfo `json:"store_list,omitempty"` 115} 116 117func (o *DisassociateStoresForStockBundleRequest) MarshalJSON() ([]byte, error) { 118 type Alias DisassociateStoresForStockBundleRequest 119 a := &struct { 120 ProductCouponId *string `json:"product_coupon_id,omitempty"` 121 StockBundleId *string `json:"stock_bundle_id,omitempty"` 122 *Alias 123 }{ 124 // 序列化时移除非 Body 字段 125 ProductCouponId: nil, 126 StockBundleId: nil, 127 Alias: (*Alias)(o), 128 } 129 return json.Marshal(a) 130} 131 132type DisassociateStoresResponse struct { 133 TotalCount *int64 `json:"total_count,omitempty"` 134 SuccessStoreList []StoreInfo `json:"success_store_list,omitempty"` 135 FailedStoreList []FailedStoreInfo `json:"failed_store_list,omitempty"` 136} 137 138type StoreInfo struct { 139 StoreId *string `json:"store_id,omitempty"` 140} 141 142type FailedStoreInfo struct { 143 StoreId *string `json:"store_id,omitempty"` 144 Code *string `json:"code,omitempty"` 145 Message *string `json:"message,omitempty"` 146} 147
应答参数
200 OK
total_count 必填 integer
【去重后门店总数】 系统会自动对请求中的门店去重,这里是去重后的门店总数
success_store_list 选填 array[object]
【取消关联成功的门店列表】 取消关联成功的门店列表
| 属性 | |
store_id 必填 string 【门店ID】 门店的唯一标识,调用【创建品牌门店API】时由微信支付生成 |
failed_store_list 选填 array[object]
【取消关联失败的门店列表】 每个取消关联失败门店的详细错误信息
| 属性 | |
store_id 必填 string 【门店ID】 取消关联失败的门店ID code 必填 string(40) 【失败错误码】 门店取消关联失败的错误码 message 必填 string(200) 【失败错误信息】 门店取消关联失败的错误描述 |
应答示例
200 OK
1{ 2 "total_count" : 10, 3 "success_store_list" : [ 4 { 5 "store_id" : "100000001" 6 } 7 ], 8 "failed_store_list" : [ 9 { 10 "store_id" : "100000001", 11 "code" : "INVALID_REQUEST", 12 "message" : "门店ID非法或不属于当前品牌" 13 } 14 ] 15} 16
错误码
以下是本接口返回的错误码列表。详细错误码规则,请参考微信支付接口规则-错误码和错误提示

