更新投放计划
更新时间:2025.09.27更新投放计划
接口说明
支持商户:【普通服务商】
请求方式:【PATCH】/v3/marketing/partner/delivery-plan/delivery-plans/{plan_id}
请求域名:【主域名】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 路径参数
plan_id 必填 string(32)
【投放计划ID】 创建生成的投放计划 ID
body 包体参数
modify_content 必填 object
【修改内容】 修改内容,修改哪个字段就填入哪个字段
| 属性 | |
plan_name 选填 string(30) 【投放计划名称】 投放计划,用于内部管理,不做C端展示 delivery_end_time 选填 string 【投放结束时间】 投放结束时间,遵循 rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss表示时分秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35+08:00表示,北京时间2015年5月20日 13点29分35秒。注:活动结束时间仅支持延长,不支持减少。 total_count 选填 integer 【投放总库存数量】 约定了投放计划的总投放库存,创建投放计划的券可用库存需在 10000 以上;非必填,如未填写, 表示投放计划层不限制,投放将以批次库存为准,且后续修改不支持修改投放库存。注:修改后活动库存需大于原库存,不支持减少库存。 user_limit 选填 integer 【单用户限领】 约定了投放计划用户维度的限领;非必填,如未填写,表示投放计划层不限制,且后续修改不支持修改限额。注:修改后单用户限额需大于原单用户限额,不支持减少限额。 daily_limit 选填 integer 【单日限领】 约定了投放计划单用户单日维度的限领;非必填,如未填写, 表示投放计划层不限制,且后续修改不支持修改限领限制。注:修改后活动日限额需大于原限额,不支持减少日限额。 recommend_word 选填 string(9) 【投放计划推荐语】 用于在“今日”二选一卡片左上角等场景展示推荐语 自定义文案,9 个中文字符以内 |
out_request_no 选填 string(40)
【修改请求单号】 修改投放计划的请求流水号,品牌侧需保持唯一性,可使用 数字、大小写字母、下划线_、短横线- 组成,长度在6-40个字符之间
请求示例
PATCH
1curl -X PATCH \ 2 https://api.mch.weixin.qq.com/v3/marketing/partner/delivery-plan/delivery-plans/12000 \ 3 -H "Authorization: WECHATPAY2-SHA256-RSA2048 mchid=\"1900000001\",..." \ 4 -H "Accept: application/json" \ 5 -H "Content-Type: application/json" \ 6 -d '{ 7 "modify_content" : { 8 "plan_name" : "冬季促销", 9 "delivery_end_time" : "2025-01-01T00:00:00+08:00", 10 "total_count" : 1, 11 "user_limit" : 1, 12 "daily_limit" : 1, 13 "recommend_word" : "冬季优惠" 14 }, 15 "out_request_no" : "abcd-1234-1000" 16 }' 17
需配合微信支付工具库 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 UpdateDeliveryPlan { 26 private static String HOST = "https://api.mch.weixin.qq.com"; 27 private static String METHOD = "PATCH"; 28 private static String PATH = "/v3/marketing/partner/delivery-plan/delivery-plans/{plan_id}"; 29 30 public static void main(String[] args) { 31 // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/v3/partner/4013080340 32 UpdateDeliveryPlan client = new UpdateDeliveryPlan( 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 UpdateDeliveryPlanRequest request = new UpdateDeliveryPlanRequest(); 41 request.planId = "12000"; 42 request.modifyContent = new PlanModifyContent(); 43 request.modifyContent.planName = "冬季促销"; 44 request.modifyContent.deliveryEndTime = "2025-01-01T00:00:00+08:00"; 45 request.modifyContent.totalCount = 1L; 46 request.modifyContent.userLimit = 1L; 47 request.modifyContent.dailyLimit = 1L; 48 request.modifyContent.recommendWord = "冬季优惠"; 49 request.outRequestNo = "abcd-1234-1000"; 50 try { 51 UpdateDeliveryPlanResponse response = client.run(request); 52 // TODO: 请求成功,继续业务逻辑 53 System.out.println(response); 54 } catch (WXPayUtility.ApiException e) { 55 // TODO: 请求失败,根据状态码执行不同的逻辑 56 e.printStackTrace(); 57 } 58 } 59 60 public UpdateDeliveryPlanResponse run(UpdateDeliveryPlanRequest request) { 61 String uri = PATH; 62 uri = uri.replace("{plan_id}", WXPayUtility.urlEncode(request.planId)); 63 String reqBody = WXPayUtility.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", WXPayUtility.buildAuthorization(mchid, 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 = WXPayUtility.extractBody(httpResponse); 78 if (httpResponse.code() >= 200 && httpResponse.code() < 300) { 79 // 2XX 成功,验证应答签名 80 WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey, 81 httpResponse.headers(), respBody); 82 83 // 从HTTP应答报文构建返回数据 84 return WXPayUtility.fromJson(respBody, UpdateDeliveryPlanResponse.class); 85 } else { 86 throw new WXPayUtility.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 mchid; 94 private final String certificateSerialNo; 95 private final PrivateKey privateKey; 96 private final String wechatPayPublicKeyId; 97 private final PublicKey wechatPayPublicKey; 98 99 public UpdateDeliveryPlan(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) { 100 this.mchid = mchid; 101 this.certificateSerialNo = certificateSerialNo; 102 this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath); 103 this.wechatPayPublicKeyId = wechatPayPublicKeyId; 104 this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath); 105 } 106 107 public static class UpdateDeliveryPlanRequest { 108 @SerializedName("plan_id") 109 @Expose(serialize = false) 110 public String planId; 111 112 @SerializedName("modify_content") 113 public PlanModifyContent modifyContent; 114 115 @SerializedName("out_request_no") 116 public String outRequestNo; 117 } 118 119 public static class UpdateDeliveryPlanResponse { 120 @SerializedName("plan") 121 public DeliveryPlan plan; 122 } 123 124 public static class PlanModifyContent { 125 @SerializedName("plan_name") 126 public String planName; 127 128 @SerializedName("delivery_end_time") 129 public String deliveryEndTime; 130 131 @SerializedName("total_count") 132 public Long totalCount; 133 134 @SerializedName("user_limit") 135 public Long userLimit; 136 137 @SerializedName("daily_limit") 138 public Long dailyLimit; 139 140 @SerializedName("recommend_word") 141 public String recommendWord; 142 } 143 144 public static class DeliveryPlan { 145 @SerializedName("plan_id") 146 public String planId; 147 148 @SerializedName("plan_name") 149 public String planName; 150 151 @SerializedName("plan_state") 152 public PlanState planState; 153 154 @SerializedName("delivery_start_time") 155 public String deliveryStartTime; 156 157 @SerializedName("delivery_end_time") 158 public String deliveryEndTime; 159 160 @SerializedName("stock_id") 161 public String stockId; 162 163 @SerializedName("product_coupon_id") 164 public String productCouponId; 165 166 @SerializedName("recommend_word") 167 public String recommendWord; 168 169 @SerializedName("brand_id") 170 public String brandId; 171 172 @SerializedName("total_count") 173 public Long totalCount; 174 175 @SerializedName("user_limit") 176 public Long userLimit; 177 178 @SerializedName("daily_limit") 179 public Long dailyLimit; 180 181 @SerializedName("reuse_coupon_config") 182 public Boolean reuseCouponConfig; 183 } 184 185 public enum PlanState { 186 @SerializedName("CREATED") 187 CREATED, 188 @SerializedName("TERMINATED") 189 TERMINATED, 190 @SerializedName("EXPIRED") 191 EXPIRED, 192 @SerializedName("DELIVERING") 193 DELIVERING, 194 @SerializedName("PAUSED") 195 PAUSED 196 } 197 198} 199
需配合微信支付工具库 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) 12 13func main() { 14 // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/v3/partner/4013080340 15 config, err := wxpay_utility.CreateMchConfig( 16 "19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340 17 "1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号,如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924 18 "/path/to/apiclient_key.pem", // 商户API证书私钥文件路径,本地文件路径 19 "PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID,如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589 20 "/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径 21 ) 22 if err != nil { 23 fmt.Println(err) 24 return 25 } 26 27 request := &UpdateDeliveryPlanRequest{ 28 PlanId: wxpay_utility.String("12000"), 29 ModifyContent: &PlanModifyContent{ 30 PlanName: wxpay_utility.String("冬季促销"), 31 DeliveryEndTime: wxpay_utility.String("2025-01-01T00:00:00+08:00"), 32 TotalCount: wxpay_utility.Int64(1), 33 UserLimit: wxpay_utility.Int64(1), 34 DailyLimit: wxpay_utility.Int64(1), 35 RecommendWord: wxpay_utility.String("冬季优惠"), 36 }, 37 OutRequestNo: wxpay_utility.String("abcd-1234-1000"), 38 } 39 40 response, err := UpdateDeliveryPlan(config, request) 41 if err != nil { 42 fmt.Printf("请求失败: %+v\n", err) 43 // TODO: 请求失败,根据状态码执行不同的处理 44 return 45 } 46 47 // TODO: 请求成功,继续业务逻辑 48 fmt.Printf("请求成功: %+v\n", response) 49} 50 51func UpdateDeliveryPlan(config *wxpay_utility.MchConfig, request *UpdateDeliveryPlanRequest) (response *UpdateDeliveryPlanResponse, err error) { 52 const ( 53 host = "https://api.mch.weixin.qq.com" 54 method = "PATCH" 55 path = "/v3/marketing/partner/delivery-plan/delivery-plans/{plan_id}" 56 ) 57 58 reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path)) 59 if err != nil { 60 return nil, err 61 } 62 reqUrl.Path = strings.Replace(reqUrl.Path, "{plan_id}", url.PathEscape(*request.PlanId), -1) 63 reqBody, err := json.Marshal(request) 64 if err != nil { 65 return nil, err 66 } 67 httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody)) 68 if err != nil { 69 return nil, err 70 } 71 httpRequest.Header.Set("Accept", "application/json") 72 httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId()) 73 httpRequest.Header.Set("Content-Type", "application/json") 74 authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody) 75 if err != nil { 76 return nil, err 77 } 78 httpRequest.Header.Set("Authorization", authorization) 79 80 client := &http.Client{} 81 httpResponse, err := client.Do(httpRequest) 82 if err != nil { 83 return nil, err 84 } 85 respBody, err := wxpay_utility.ExtractResponseBody(httpResponse) 86 if err != nil { 87 return nil, err 88 } 89 if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 { 90 // 2XX 成功,验证应答签名 91 err = wxpay_utility.ValidateResponse( 92 config.WechatPayPublicKeyId(), 93 config.WechatPayPublicKey(), 94 &httpResponse.Header, 95 respBody, 96 ) 97 if err != nil { 98 return nil, err 99 } 100 response := &UpdateDeliveryPlanResponse{} 101 if err := json.Unmarshal(respBody, response); err != nil { 102 return nil, err 103 } 104 105 return response, nil 106 } else { 107 return nil, wxpay_utility.NewApiException( 108 httpResponse.StatusCode, 109 httpResponse.Header, 110 respBody, 111 ) 112 } 113} 114 115type UpdateDeliveryPlanRequest struct { 116 PlanId *string `json:"plan_id,omitempty"` 117 ModifyContent *PlanModifyContent `json:"modify_content,omitempty"` 118 OutRequestNo *string `json:"out_request_no,omitempty"` 119} 120 121func (o *UpdateDeliveryPlanRequest) MarshalJSON() ([]byte, error) { 122 type Alias UpdateDeliveryPlanRequest 123 a := &struct { 124 PlanId *string `json:"plan_id,omitempty"` 125 *Alias 126 }{ 127 // 序列化时移除非 Body 字段 128 PlanId: nil, 129 Alias: (*Alias)(o), 130 } 131 return json.Marshal(a) 132} 133 134type UpdateDeliveryPlanResponse struct { 135 Plan *DeliveryPlan `json:"plan,omitempty"` 136} 137 138type PlanModifyContent struct { 139 PlanName *string `json:"plan_name,omitempty"` 140 DeliveryEndTime *string `json:"delivery_end_time,omitempty"` 141 TotalCount *int64 `json:"total_count,omitempty"` 142 UserLimit *int64 `json:"user_limit,omitempty"` 143 DailyLimit *int64 `json:"daily_limit,omitempty"` 144 RecommendWord *string `json:"recommend_word,omitempty"` 145} 146 147type DeliveryPlan struct { 148 PlanId *string `json:"plan_id,omitempty"` 149 PlanName *string `json:"plan_name,omitempty"` 150 PlanState *PlanState `json:"plan_state,omitempty"` 151 DeliveryStartTime *string `json:"delivery_start_time,omitempty"` 152 DeliveryEndTime *string `json:"delivery_end_time,omitempty"` 153 StockId *string `json:"stock_id,omitempty"` 154 ProductCouponId *string `json:"product_coupon_id,omitempty"` 155 RecommendWord *string `json:"recommend_word,omitempty"` 156 BrandId *string `json:"brand_id,omitempty"` 157 TotalCount *int64 `json:"total_count,omitempty"` 158 UserLimit *int64 `json:"user_limit,omitempty"` 159 DailyLimit *int64 `json:"daily_limit,omitempty"` 160 ReuseCouponConfig *bool `json:"reuse_coupon_config,omitempty"` 161} 162 163type PlanState string 164 165func (e PlanState) Ptr() *PlanState { 166 return &e 167} 168 169const ( 170 PLANSTATE_CREATED PlanState = "CREATED" 171 PLANSTATE_TERMINATED PlanState = "TERMINATED" 172 PLANSTATE_EXPIRED PlanState = "EXPIRED" 173 PLANSTATE_DELIVERING PlanState = "DELIVERING" 174 PLANSTATE_PAUSED PlanState = "PAUSED" 175) 176
应答参数
200 OK
plan 必填 object
【投放计划详情】 修改后的投放计划详情
| 属性 | |
plan_id 必填 string(32) 【投放计划ID】 投放计划ID plan_name 必填 string(30) 【投放计划名称】 投放计划名称 plan_state 必填 string 【投放计划状态】 投放计划状态,已终止、已过期是终态。 可选取值
delivery_start_time 必填 string 【投放开始时间】 投放开始时间,遵循 rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss表示时分秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35+08:00表示,北京时间2015年5月20日 13点29分35秒。 delivery_end_time 必填 string 【投放结束时间】 投放结束时间,遵循 rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss表示时分秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35+08:00表示,北京时间2015年5月20日 13点29分35秒。 stock_id 必填 string(40) 【券批次ID】 券批次ID product_coupon_id 必填 string(40) 【商品券ID】 商品券ID recommend_word 选填 string(9) 【营销标签】 用于在优惠左上角展示的运营推荐语信息 自定义文案,不超过 9 个中文字符或18 个英文字符。若创建时未设置则不返回。 brand_id 必填 string(32) 【品牌ID】 创建投放计划的品牌ID,可登录品牌经营平台查看品牌 ID 信息 total_count 必填 integer 【投放总库存数量】 约定了投放计划的总投放库存,创建投放计划的券可用库存需在 10000 以上;非必填,如未填写, 表示投放计划层不限制,投放将以批次库存为准,且后续修改不支持修改投放库存。 user_limit 必填 integer 【单用户限领】 约定了投放计划单用户维度的限领数量; 非必填,如未填写, 表示投放计划层不限制,且后续修改不支持修改。 daily_limit 必填 integer 【单日限领】 用于约定投放计划单日可领取的最大数量,如创建时未填写,则修改时不支持填写。 reuse_coupon_config 必填 boolean 【是否复用商品券和批次信息】 是:从商品券和批次获取信息自动填充plan_name、total_count、user_limit、daily_limit、delivery_start_time、delivery_end_time,若商品券或批次信息发生变化,会自动更新投放计划以上字段信息。 |
应答示例
200 OK
1{ 2 "plan" : { 3 "plan_id" : "12000", 4 "plan_name" : "冬季优惠投放", 5 "plan_state" : "CREATED", 6 "delivery_start_time" : "2025-01-01T00:00:00+08:00", 7 "delivery_end_time" : "2025-01-01T00:00:00+08:00", 8 "stock_id" : "123456789", 9 "product_coupon_id" : "1000000013", 10 "recommend_word" : "天天有惊喜", 11 "brand_id" : "40016", 12 "total_count" : 11000, 13 "user_limit" : 5, 14 "daily_limit" : 100, 15 "reuse_coupon_config" : false 16 } 17} 18
错误码
以下是本接口返回的错误码列表。详细错误码规则,请参考微信支付接口规则-错误码和错误提示

