建立合作关系
更新时间:2024.08.26建立合作关系接口主要为商户提供营销资源的授权能力,可授权给其他商户或小程序,方便商户间的互利合作。
接口说明
支持商户:【普通商户】
请求方式:【POST】/v3/marketing/partnerships/build
请求域名:【主域名】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
Idempotency-Key 必填 string
【业务请求幂等值】商户侧需保持唯一性,可包含英文字母,数字,|,_,*,-等内容,不允许出现其他不合法符号
body 包体参数
partner 必填 object
【合作方信息】合作方信息
属性 | |
type 必填 string 【合作方类别】合作方类别,枚举值见文档 可选取值:
appid 选填 string(32) 【合作方Appid】合作方Appid,合作方类别为APPID时必填 merchant_id 选填 string(15) 【合作方商户ID】合作方商户ID,合作方类别为MERCHANT时必填 |
authorized_data 必填 object
【被授权数据】被授权数据
属性 | |
business_type 必填 string 【授权业务类别】授权业务类别,枚举值见文档 可选取值:
stock_id 选填 string(20) 【授权批次ID】授权批次ID,授权业务类别为券批次时必填 |
请求示例
POST
1curl -X POST \ 2 https://api.mch.weixin.qq.com/v3/marketing/partnerships/build \ 3 -H "Idempotency-Key: buildreq_001" \ 4 -H "Authorization: WECHATPAY2-SHA256-RSA2048 mchid=\"1900000001\",..." \ 5 -H "Accept: application/json" \ 6 -H "Content-Type: application/json" \ 7 -d '{ 8 "partner" : { 9 "type" : "APPID", 10 "appid" : "wx4e1916a585d1f4e9", 11 "merchant_id" : "2480029552" 12 }, 13 "authorized_data" : { 14 "business_type" : "FAVOR_STOCK", 15 "stock_id" : "2433405" 16 } 17 }' 18
需配合微信支付工具库 WXPayUtility 使用,请参考Java
1package com.java.demo; 2 3import com.java.utils.WXPayUtility; // 引用微信支付工具库,参考:https://pay.weixin.qq.com/doc/v3/merchant/4014931831 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 BuildPartnerships { 26 private static String HOST = "https://api.mch.weixin.qq.com"; 27 private static String METHOD = "POST"; 28 private static String PATH = "/v3/marketing/partnerships/build"; 29 30 public static void main(String[] args) { 31 // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/v3/merchant/4013070756 32 BuildPartnerships client = new BuildPartnerships( 33 "19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/merchant/4013070756 34 "1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号,如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013053053 35 "/path/to/apiclient_key.pem", // 商户API证书私钥文件路径,本地文件路径 36 "PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID,如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013038816 37 "/path/to/wxp_pub.pem" // 微信支付公钥文件路径,本地文件路径 38 ); 39 40 BuildPartnershipsRequest request = new BuildPartnershipsRequest(); 41 request.idempotencyKey = "buildreq_001"; 42 request.partner = new PartnerInfo(); 43 request.partner.type = PartnerType.APPID; 44 request.partner.appid = "wx4e1916a585d1f4e9"; 45 request.partner.merchantId = "2480029552"; 46 request.authorizedData = new AuthorizedData(); 47 request.authorizedData.businessType = AuthBusinessType.FAVOR_STOCK; 48 request.authorizedData.stockId = "2433405"; 49 try { 50 BuildPartnershipsResponse response = client.run(request); 51 // TODO: 请求成功,继续业务逻辑 52 System.out.println(response); 53 } catch (WXPayUtility.ApiException e) { 54 // TODO: 请求失败,根据状态码执行不同的逻辑 55 e.printStackTrace(); 56 } 57 } 58 59 public BuildPartnershipsResponse run(BuildPartnershipsRequest request) { 60 String uri = PATH; 61 String reqBody = WXPayUtility.toJson(request); 62 63 Request.Builder reqBuilder = new Request.Builder().url(HOST + uri); 64 reqBuilder.addHeader("Idempotency-Key", request.idempotencyKey); 65 reqBuilder.addHeader("Accept", "application/json"); 66 reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId); 67 reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody)); 68 reqBuilder.addHeader("Content-Type", "application/json"); 69 RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody); 70 reqBuilder.method(METHOD, requestBody); 71 Request httpRequest = reqBuilder.build(); 72 73 // 发送HTTP请求 74 OkHttpClient client = new OkHttpClient.Builder().build(); 75 try (Response httpResponse = client.newCall(httpRequest).execute()) { 76 String respBody = WXPayUtility.extractBody(httpResponse); 77 if (httpResponse.code() >= 200 && httpResponse.code() < 300) { 78 // 2XX 成功,验证应答签名 79 WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey, 80 httpResponse.headers(), respBody); 81 82 // 从HTTP应答报文构建返回数据 83 return WXPayUtility.fromJson(respBody, BuildPartnershipsResponse.class); 84 } else { 85 throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers()); 86 } 87 } catch (IOException e) { 88 throw new UncheckedIOException("Sending request to " + uri + " failed.", e); 89 } 90 } 91 92 private final String mchid; 93 private final String certificateSerialNo; 94 private final PrivateKey privateKey; 95 private final String wechatPayPublicKeyId; 96 private final PublicKey wechatPayPublicKey; 97 98 public BuildPartnerships(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) { 99 this.mchid = mchid; 100 this.certificateSerialNo = certificateSerialNo; 101 this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath); 102 this.wechatPayPublicKeyId = wechatPayPublicKeyId; 103 this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath); 104 } 105 106 public static class BuildPartnershipsRequest { 107 @SerializedName("partner") 108 public PartnerInfo partner; 109 110 @SerializedName("authorized_data") 111 public AuthorizedData authorizedData; 112 113 @SerializedName("Idempotency-Key") 114 @Expose(serialize = false) 115 public String idempotencyKey; 116 } 117 118 public static class BuildPartnershipsResponse { 119 @SerializedName("partner") 120 public PartnerInfo partner; 121 122 @SerializedName("authorized_data") 123 public AuthorizedData authorizedData; 124 125 @SerializedName("state") 126 public State state; 127 128 @SerializedName("build_time") 129 public String buildTime; 130 131 @SerializedName("create_time") 132 public String createTime; 133 134 @SerializedName("update_time") 135 public String updateTime; 136 } 137 138 public static class PartnerInfo { 139 @SerializedName("type") 140 public PartnerType type; 141 142 @SerializedName("appid") 143 public String appid; 144 145 @SerializedName("merchant_id") 146 public String merchantId; 147 } 148 149 public static class AuthorizedData { 150 @SerializedName("business_type") 151 public AuthBusinessType businessType; 152 153 @SerializedName("stock_id") 154 public String stockId; 155 } 156 157 public enum State { 158 @SerializedName("ESTABLISHED") 159 ESTABLISHED, 160 @SerializedName("TERMINATED") 161 TERMINATED 162 } 163 164 public enum PartnerType { 165 @SerializedName("APPID") 166 APPID, 167 @SerializedName("MERCHANT") 168 MERCHANT 169 } 170 171 public enum AuthBusinessType { 172 @SerializedName("FAVOR_STOCK") 173 FAVOR_STOCK, 174 @SerializedName("BUSIFAVOR_STOCK") 175 BUSIFAVOR_STOCK 176 } 177 178} 179
需配合微信支付工具库 wxpay_utility 使用,请参考Go
1package main 2 3import ( 4 "bytes" 5 "demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/merchant/4015119334 6 "encoding/json" 7 "fmt" 8 "net/http" 9 "net/url" 10) 11 12func main() { 13 // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/v3/merchant/4013070756 14 config, err := wxpay_utility.CreateMchConfig( 15 "19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/merchant/4013070756 16 "1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号,如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013053053 17 "/path/to/apiclient_key.pem", // 商户API证书私钥文件路径,本地文件路径 18 "PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID,如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013038816 19 "/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径 20 ) 21 if err != nil { 22 fmt.Println(err) 23 return 24 } 25 26 request := &BuildPartnershipsRequest{ 27 IdempotencyKey: wxpay_utility.String("buildreq_001"), 28 Partner: &PartnerInfo{ 29 Type: PARTNERTYPE_APPID.Ptr(), 30 Appid: wxpay_utility.String("wx4e1916a585d1f4e9"), 31 MerchantId: wxpay_utility.String("2480029552"), 32 }, 33 AuthorizedData: &AuthorizedData{ 34 BusinessType: AUTHBUSINESSTYPE_FAVOR_STOCK.Ptr(), 35 StockId: wxpay_utility.String("2433405"), 36 }, 37 } 38 39 response, err := BuildPartnerships(config, request) 40 if err != nil { 41 fmt.Printf("请求失败: %+v\n", err) 42 // TODO: 请求失败,根据状态码执行不同的处理 43 return 44 } 45 46 // TODO: 请求成功,继续业务逻辑 47 fmt.Printf("请求成功: %+v\n", response) 48} 49 50func BuildPartnerships(config *wxpay_utility.MchConfig, request *BuildPartnershipsRequest) (response *BuildPartnershipsResponse, err error) { 51 const ( 52 host = "https://api.mch.weixin.qq.com" 53 method = "POST" 54 path = "/v3/marketing/partnerships/build" 55 ) 56 57 reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path)) 58 if err != nil { 59 return nil, err 60 } 61 reqBody, err := json.Marshal(request) 62 if err != nil { 63 return nil, err 64 } 65 httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody)) 66 if err != nil { 67 return nil, err 68 } 69 httpRequest.Header.Set(Idempotency-Key, request.IdempotencyKey) 70 httpRequest.Header.Set("Accept", "application/json") 71 httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId()) 72 httpRequest.Header.Set("Content-Type", "application/json") 73 authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody) 74 if err != nil { 75 return nil, err 76 } 77 httpRequest.Header.Set("Authorization", authorization) 78 79 client := &http.Client{} 80 httpResponse, err := client.Do(httpRequest) 81 if err != nil { 82 return nil, err 83 } 84 respBody, err := wxpay_utility.ExtractResponseBody(httpResponse) 85 if err != nil { 86 return nil, err 87 } 88 if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 { 89 // 2XX 成功,验证应答签名 90 err = wxpay_utility.ValidateResponse( 91 config.WechatPayPublicKeyId(), 92 config.WechatPayPublicKey(), 93 &httpResponse.Header, 94 respBody, 95 ) 96 if err != nil { 97 return nil, err 98 } 99 response := &BuildPartnershipsResponse{} 100 if err := json.Unmarshal(respBody, response); err != nil { 101 return nil, err 102 } 103 104 return response, nil 105 } else { 106 return nil, wxpay_utility.NewApiException( 107 httpResponse.StatusCode, 108 httpResponse.Header, 109 respBody, 110 ) 111 } 112} 113 114type BuildPartnershipsRequest struct { 115 Partner *PartnerInfo `json:"partner,omitempty"` 116 AuthorizedData *AuthorizedData `json:"authorized_data,omitempty"` 117 IdempotencyKey *string `json:"Idempotency-Key,omitempty"` 118} 119 120func (o *BuildPartnershipsRequest) MarshalJSON() ([]byte, error) { 121 type Alias BuildPartnershipsRequest 122 a := &struct { 123 IdempotencyKey *string `json:"Idempotency-Key,omitempty"` 124 *Alias 125 }{ 126 // 序列化时移除非 Body 字段 127 IdempotencyKey: nil, 128 Alias: (*Alias)(o), 129 } 130 return json.Marshal(a) 131} 132 133type BuildPartnershipsResponse struct { 134 Partner *PartnerInfo `json:"partner,omitempty"` 135 AuthorizedData *AuthorizedData `json:"authorized_data,omitempty"` 136 State *State `json:"state,omitempty"` 137 BuildTime *string `json:"build_time,omitempty"` 138 CreateTime *string `json:"create_time,omitempty"` 139 UpdateTime *string `json:"update_time,omitempty"` 140} 141 142type PartnerInfo struct { 143 Type *PartnerType `json:"type,omitempty"` 144 Appid *string `json:"appid,omitempty"` 145 MerchantId *string `json:"merchant_id,omitempty"` 146} 147 148type AuthorizedData struct { 149 BusinessType *AuthBusinessType `json:"business_type,omitempty"` 150 StockId *string `json:"stock_id,omitempty"` 151} 152 153type State string 154 155func (e State) Ptr() *State { 156 return &e 157} 158 159const ( 160 STATE_ESTABLISHED State = "ESTABLISHED" 161 STATE_TERMINATED State = "TERMINATED" 162) 163 164type PartnerType string 165 166func (e PartnerType) Ptr() *PartnerType { 167 return &e 168} 169 170const ( 171 PARTNERTYPE_APPID PartnerType = "APPID" 172 PARTNERTYPE_MERCHANT PartnerType = "MERCHANT" 173) 174 175type AuthBusinessType string 176 177func (e AuthBusinessType) Ptr() *AuthBusinessType { 178 return &e 179} 180 181const ( 182 AUTHBUSINESSTYPE_FAVOR_STOCK AuthBusinessType = "FAVOR_STOCK" 183 AUTHBUSINESSTYPE_BUSIFAVOR_STOCK AuthBusinessType = "BUSIFAVOR_STOCK" 184) 185
应答参数
|
partner 必填 object
【合作方信息】合作方信息
属性 | |
type 必填 string 【合作方类别】合作方类别,枚举值见文档 可选取值:
appid 选填 string(32) 【合作方Appid】合作方Appid,合作方类别为APPID时必填 merchant_id 选填 string(15) 【合作方商户ID】合作方商户ID,合作方类别为MERCHANT时必填 |
authorized_data 必填 object
【被授权数据】被授权数据
属性 | |
business_type 必填 string 【授权业务类别】授权业务类别,枚举值见文档 可选取值:
stock_id 选填 string(20) 【授权批次ID】授权批次ID,授权业务类别为券批次时必填 |
state 必填 string
【合作状态】合作状态,枚举值见文档
可选取值:
ESTABLISHED
: 合作状态-已建立
TERMINATED
: 合作状态-已终止
build_time 必填 string(32)
【建立合作关系时间】建立合作关系时间,遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss.sss+TIMEZONE,yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.sss表示时分秒毫秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35.120+08:00表示,北京时间2015年5月20日 13点29分35秒。
create_time 必填 string(32)
【创建时间】创建时间,遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss.sss+TIMEZONE,yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.sss表示时分秒毫秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35.120+08:00表示,北京时间2015年5月20日 13点29分35秒。
update_time 必填 string(32)
【更新时间】更新时间,遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss.sss+TIMEZONE,yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.sss表示时分秒毫秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35.120+08:00表示,北京时间2015年5月20日 13点29分35秒。
应答示例
200 OK
1{ 2 "partner" : { 3 "type" : "APPID", 4 "appid" : "wx4e1916a585d1f4e9", 5 "merchant_id" : "2480029552" 6 }, 7 "authorized_data" : { 8 "business_type" : "FAVOR_STOCK", 9 "stock_id" : "2433405" 10 }, 11 "state" : "ESTABLISHED", 12 "build_time" : "2015-05-20T13:29:35.120+08:00", 13 "create_time" : "2015-05-20T13:29:35.120+08:00", 14 "update_time" : "2015-05-20T13:29:35.120+08:00" 15} 16
错误码
公共错误码
状态码 | 错误码 | 描述 | 解决方案 |
---|---|---|---|
400 | PARAM_ERROR | 参数错误 | 请根据错误提示正确传入参数 |
400 | INVALID_REQUEST | HTTP 请求不符合微信支付 APIv3 接口规则 | 请参阅 接口规则 |
401 | SIGN_ERROR | 验证不通过 | 请参阅 签名常见问题 |
500 | SYSTEM_ERROR | 系统异常,请稍后重试 | 请稍后重试 |
业务错误码
状态码 | 错误码 | 描述 | 解决方案 |
---|---|---|---|
400 | APPID_MCHID_NOT_MATCH | appid与mchid不匹配 | 请确认appid是否正确填写 |
400 | INVALID_REQUEST | 请求参数符合参数格式,但不符合业务规则 | 根据错误提示,传入符合业务规则的参数 |
400 | MCH_NOT_EXISTS | 商户号不存在 | 请确认发券商户号信息是否有误 |
401 | SIGN_ERROR | 签名错误或签名信息不完整 | 登录商户平台核对,传入正确信息 |
403 | NO_AUTH | 商户未被授权 | 登录商户平台核对,传入正确信息 |
404 | RESOURCE_NOT_EXISTS | 资源不存在或无可用 | 请确认资源均存在且可用 |
429 | FREQUENCY_LIMITED | 频率超限 | 请求量不要超过接口调用频率限制 |