创建投放计划
更新时间:2025.09.27创建投放计划
接口说明
支持商户:【普通服务商】
请求方式:【POST】/v3/marketing/partner/delivery-plan/delivery-plans
请求域名:【主域名】https://api.mch.weixin.qq.com 使用该域名将访问就近的接入点
【备域名】https://api2.mch.weixin.qq.com 使用该域名将访问异地的接入点 ,指引点击查看
请求参数
Header HTTP头参数
Authorization 必填 string
请参考签名认证生成认证信息
Accept 必填 string
请设置为application/json
Content-Type 必填 string
请设置为application/json
body 包体参数
out_request_no 必填 string(40)
【创建请求单号】 创建投放计划的请求流水号,品牌侧需保持唯一性,可使用 数字、大小写字母、下划线_、短横线- 组成,长度在6-40个字符之间
brand_id 必填 string
【创建投放计划的品牌ID】 创建投放计划的品牌ID,可登录品牌经营平台查看品牌 ID 信息
product_coupon_id 必填 string
【商品券ID】 投放的商品券ID,通过请求创建商品券接口获得,具体可查看创建商品券
stock_id 必填 string
【批次ID】 投放的商品券批次ID,通过请求创建商品券接口获得,具体可查看创建商品券
reuse_coupon_config 必填 boolean
【是否复用商品券和批次信息】 是:表示从商品券和批次获取信息自动填充plan_name、total_count、user_limit、daily_limit、delivery_start_time、delivery_end_time,若商品券或批次信息发生变化,会自动更新投放计划以上字段信息。
否:表示自定义传入plan_name、total_count、user_limit、daily_limit、delivery_start_time、delivery_end_time,其中plan_name、total_count、delivery_start_time、delivery_end_time必填
plan_name 选填 string(30)
【投放计划名称】 投放计划名称,该名称会用于C端展示,场景说明详见产品介绍,建议与商品券名称保持一致,12个中文字符以内。
total_count 选填 integer
【投放总库存数量】 用于约定投放计划的总投放库存额度,创建投放计划的券可用库存需在 10000 以上;该字段可选填,若不填写,则表示投放计划层面不限制总投放库存。
user_limit 选填 integer
【单用户限领】 约定了投放计划单用户维度的限领数量; 非必填,如创建时未填写, 表示投放计划层不限制,且后续修改不支持修改。
daily_limit 选填 integer
【单日限领】 约定了投放计划单日维度的限领数量;非必填,如未填写, 表示投放计划层不限制,且后续修改不支持修改。
delivery_start_time 选填 string
【开始可用时间】 【投放开始时间】 投放生效的开始时间,遵循[rfc3339]( https://datatracker.ietf.org/doc/html/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]( https://datatracker.ietf.org/doc/html/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秒。如未填写表示生效时间将以批次结束时间为准,且后续修改不支持设置结束时间。
recommend_word 选填 string(9)
【营销标签】 用于在优惠左上角展示的运营推荐语信息 自定义文案,不超过 9 个中文字符或18 个英文字符
请求示例
POST
1curl -X POST \ 2 https://api.mch.weixin.qq.com/v3/marketing/partner/delivery-plan/delivery-plans \ 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" : "asdf-1234-40016", 8 "brand_id" : "40016", 9 "product_coupon_id" : "701146876221757924829193824428", 10 "stock_id" : "701246876221757924829194755312", 11 "reuse_coupon_config" : false, 12 "plan_name" : "冬季饮料投放", 13 "total_count" : 1, 14 "user_limit" : 1, 15 "daily_limit" : 1, 16 "delivery_start_time" : "2025-01-01T00:00:00+08:00", 17 "delivery_end_time" : "2025-01-01T00:00:00+08:00", 18 "recommend_word" : "天天有惊喜" 19 }' 20
需配合微信支付工具库 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 CreateDeliveryPlan { 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/delivery-plan/delivery-plans"; 29 30 public static void main(String[] args) { 31 // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/v3/partner/4013080340 32 CreateDeliveryPlan client = new CreateDeliveryPlan( 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 CreateDeliveryPlanRequest request = new CreateDeliveryPlanRequest(); 41 request.outRequestNo = "asdf-1234-40016"; 42 request.brandId = "40016"; 43 request.productCouponId = "701146876221757924829193824428"; 44 request.stockId = "701246876221757924829194755312"; 45 request.reuseCouponConfig = false; 46 request.planName = "冬季饮料投放"; 47 request.totalCount = 1L; 48 request.userLimit = 1L; 49 request.dailyLimit = 1L; 50 request.deliveryStartTime = "2025-01-01T00:00:00+08:00"; 51 request.deliveryEndTime = "2025-01-01T00:00:00+08:00"; 52 request.recommendWord = "天天有惊喜"; 53 try { 54 CreateDeliveryPlanReponse response = client.run(request); 55 // TODO: 请求成功,继续业务逻辑 56 System.out.println(response); 57 } catch (WXPayUtility.ApiException e) { 58 // TODO: 请求失败,根据状态码执行不同的逻辑 59 e.printStackTrace(); 60 } 61 } 62 63 public CreateDeliveryPlanReponse run(CreateDeliveryPlanRequest request) { 64 String uri = PATH; 65 String reqBody = WXPayUtility.toJson(request); 66 67 Request.Builder reqBuilder = new Request.Builder().url(HOST + uri); 68 reqBuilder.addHeader("Accept", "application/json"); 69 reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId); 70 reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody)); 71 reqBuilder.addHeader("Content-Type", "application/json"); 72 RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody); 73 reqBuilder.method(METHOD, requestBody); 74 Request httpRequest = reqBuilder.build(); 75 76 // 发送HTTP请求 77 OkHttpClient client = new OkHttpClient.Builder().build(); 78 try (Response httpResponse = client.newCall(httpRequest).execute()) { 79 String respBody = WXPayUtility.extractBody(httpResponse); 80 if (httpResponse.code() >= 200 && httpResponse.code() < 300) { 81 // 2XX 成功,验证应答签名 82 WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey, 83 httpResponse.headers(), respBody); 84 85 // 从HTTP应答报文构建返回数据 86 return WXPayUtility.fromJson(respBody, CreateDeliveryPlanReponse.class); 87 } else { 88 throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers()); 89 } 90 } catch (IOException e) { 91 throw new UncheckedIOException("Sending request to " + uri + " failed.", e); 92 } 93 } 94 95 private final String mchid; 96 private final String certificateSerialNo; 97 private final PrivateKey privateKey; 98 private final String wechatPayPublicKeyId; 99 private final PublicKey wechatPayPublicKey; 100 101 public CreateDeliveryPlan(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) { 102 this.mchid = mchid; 103 this.certificateSerialNo = certificateSerialNo; 104 this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath); 105 this.wechatPayPublicKeyId = wechatPayPublicKeyId; 106 this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath); 107 } 108 109 public static class CreateDeliveryPlanRequest { 110 @SerializedName("out_request_no") 111 public String outRequestNo; 112 113 @SerializedName("brand_id") 114 public String brandId; 115 116 @SerializedName("product_coupon_id") 117 public String productCouponId; 118 119 @SerializedName("stock_id") 120 public String stockId; 121 122 @SerializedName("reuse_coupon_config") 123 public Boolean reuseCouponConfig; 124 125 @SerializedName("plan_name") 126 public String planName; 127 128 @SerializedName("total_count") 129 public Long totalCount; 130 131 @SerializedName("user_limit") 132 public Long userLimit; 133 134 @SerializedName("daily_limit") 135 public Long dailyLimit; 136 137 @SerializedName("delivery_start_time") 138 public String deliveryStartTime; 139 140 @SerializedName("delivery_end_time") 141 public String deliveryEndTime; 142 143 @SerializedName("recommend_word") 144 public String recommendWord; 145 } 146 147 public static class CreateDeliveryPlanReponse { 148 @SerializedName("plan") 149 public DeliveryPlan plan; 150 } 151 152 public static class DeliveryPlan { 153 @SerializedName("plan_id") 154 public String planId; 155 156 @SerializedName("plan_name") 157 public String planName; 158 159 @SerializedName("plan_state") 160 public PlanState planState; 161 162 @SerializedName("delivery_start_time") 163 public String deliveryStartTime; 164 165 @SerializedName("delivery_end_time") 166 public String deliveryEndTime; 167 168 @SerializedName("stock_id") 169 public String stockId; 170 171 @SerializedName("product_coupon_id") 172 public String productCouponId; 173 174 @SerializedName("recommend_word") 175 public String recommendWord; 176 177 @SerializedName("brand_id") 178 public String brandId; 179 180 @SerializedName("total_count") 181 public Long totalCount; 182 183 @SerializedName("user_limit") 184 public Long userLimit; 185 186 @SerializedName("daily_limit") 187 public Long dailyLimit; 188 189 @SerializedName("reuse_coupon_config") 190 public Boolean reuseCouponConfig; 191 } 192 193 public enum PlanState { 194 @SerializedName("PLAN_CREATING") 195 PLAN_CREATING, 196 @SerializedName("PLAN_CREATED") 197 PLAN_CREATED, 198 @SerializedName("PLAN_TERMINATING") 199 PLAN_TERMINATING, 200 @SerializedName("PLAN_TERMINATED") 201 PLAN_TERMINATED, 202 @SerializedName("PLAN_EXPIRED") 203 PLAN_EXPIRED, 204 @SerializedName("PLAN_DELIVERING") 205 PLAN_DELIVERING, 206 @SerializedName("PLAN_PAUSED") 207 PLAN_PAUSED 208 } 209 210} 211
需配合微信支付工具库 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) 11 12func main() { 13 // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/v3/partner/4013080340 14 config, err := wxpay_utility.CreateMchConfig( 15 "19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340 16 "1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号,如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924 17 "/path/to/apiclient_key.pem", // 商户API证书私钥文件路径,本地文件路径 18 "PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID,如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589 19 "/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径 20 ) 21 if err != nil { 22 fmt.Println(err) 23 return 24 } 25 26 request := &CreateDeliveryPlanRequest{ 27 OutRequestNo: wxpay_utility.String("asdf-1234-40016"), 28 BrandId: wxpay_utility.String("40016"), 29 ProductCouponId: wxpay_utility.String("701146876221757924829193824428"), 30 StockId: wxpay_utility.String("701246876221757924829194755312"), 31 ReuseCouponConfig: wxpay_utility.Bool(false), 32 PlanName: wxpay_utility.String("冬季饮料投放"), 33 TotalCount: wxpay_utility.Int64(1), 34 UserLimit: wxpay_utility.Int64(1), 35 DailyLimit: wxpay_utility.Int64(1), 36 DeliveryStartTime: wxpay_utility.String("2025-01-01T00:00:00+08:00"), 37 DeliveryEndTime: wxpay_utility.String("2025-01-01T00:00:00+08:00"), 38 RecommendWord: wxpay_utility.String("天天有惊喜"), 39 } 40 41 response, err := CreateDeliveryPlan(config, request) 42 if err != nil { 43 fmt.Printf("请求失败: %+v\n", err) 44 // TODO: 请求失败,根据状态码执行不同的处理 45 return 46 } 47 48 // TODO: 请求成功,继续业务逻辑 49 fmt.Printf("请求成功: %+v\n", response) 50} 51 52func CreateDeliveryPlan(config *wxpay_utility.MchConfig, request *CreateDeliveryPlanRequest) (response *CreateDeliveryPlanReponse, err error) { 53 const ( 54 host = "https://api.mch.weixin.qq.com" 55 method = "POST" 56 path = "/v3/marketing/partner/delivery-plan/delivery-plans" 57 ) 58 59 reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path)) 60 if err != nil { 61 return nil, err 62 } 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 := &CreateDeliveryPlanReponse{} 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 CreateDeliveryPlanRequest struct { 116 OutRequestNo *string `json:"out_request_no,omitempty"` 117 BrandId *string `json:"brand_id,omitempty"` 118 ProductCouponId *string `json:"product_coupon_id,omitempty"` 119 StockId *string `json:"stock_id,omitempty"` 120 ReuseCouponConfig *bool `json:"reuse_coupon_config,omitempty"` 121 PlanName *string `json:"plan_name,omitempty"` 122 TotalCount *int64 `json:"total_count,omitempty"` 123 UserLimit *int64 `json:"user_limit,omitempty"` 124 DailyLimit *int64 `json:"daily_limit,omitempty"` 125 DeliveryStartTime *string `json:"delivery_start_time,omitempty"` 126 DeliveryEndTime *string `json:"delivery_end_time,omitempty"` 127 RecommendWord *string `json:"recommend_word,omitempty"` 128} 129 130type CreateDeliveryPlanReponse struct { 131 Plan *DeliveryPlan `json:"plan,omitempty"` 132} 133 134type DeliveryPlan struct { 135 PlanId *string `json:"plan_id,omitempty"` 136 PlanName *string `json:"plan_name,omitempty"` 137 PlanState *PlanState `json:"plan_state,omitempty"` 138 DeliveryStartTime *string `json:"delivery_start_time,omitempty"` 139 DeliveryEndTime *string `json:"delivery_end_time,omitempty"` 140 StockId *string `json:"stock_id,omitempty"` 141 ProductCouponId *string `json:"product_coupon_id,omitempty"` 142 RecommendWord *string `json:"recommend_word,omitempty"` 143 BrandId *string `json:"brand_id,omitempty"` 144 TotalCount *int64 `json:"total_count,omitempty"` 145 UserLimit *int64 `json:"user_limit,omitempty"` 146 DailyLimit *int64 `json:"daily_limit,omitempty"` 147 ReuseCouponConfig *bool `json:"reuse_coupon_config,omitempty"` 148} 149 150type PlanState string 151 152func (e PlanState) Ptr() *PlanState { 153 return &e 154} 155 156const ( 157 PLANSTATE_PLAN_CREATING PlanState = "PLAN_CREATING" 158 PLANSTATE_PLAN_CREATED PlanState = "PLAN_CREATED" 159 PLANSTATE_PLAN_TERMINATING PlanState = "PLAN_TERMINATING" 160 PLANSTATE_PLAN_TERMINATED PlanState = "PLAN_TERMINATED" 161 PLANSTATE_PLAN_EXPIRED PlanState = "PLAN_EXPIRED" 162 PLANSTATE_PLAN_DELIVERING PlanState = "PLAN_DELIVERING" 163 PLANSTATE_PLAN_PAUSED PlanState = "PLAN_PAUSED" 164) 165
应答参数
200 OK
plan 必填 object
【投放计划详情】 创建成功的投放计划详情
| 属性 | |
plan_id 必填 string(32) 【投放计划ID】 投放计划ID plan_name 必填 string(30) 【投放计划名称】 投放计划名称 plan_state 必填 string 【投放计划状态】 投放计划状态,已终止、已过期是终态。 可选取值
delivery_start_time 选填 string 【投放开始时间】 投放开始时间,遵循 [rfc3339]( https://datatracker.ietf.org/doc/html/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]( https://datatracker.ietf.org/doc/html/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" : "PLAN_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
错误码
以下是本接口返回的错误码列表。详细错误码规则,请参考微信支付接口规则-错误码和错误提示
