APP预签约
更新时间:2025.09.19App预签约
接口说明
支持商户:【普通服务商】
请求方式:【POST】/v3/credit-repayment/partner/contracts/app-presign
请求域名:【主域名】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】或【微信支付平台证书序列号】 请求参数中的敏感字段,需要使用微信支付公钥加密(推荐),请参考获取微信支付公钥ID说明以及微信支付公钥加密敏感信息指引;也可以使用微信支付平台证书公钥加密,参考获取平台证书序列号、平台证书加密敏感信息指引
body 包体参数
appid 必填 string(32)
【商户AppID】 商户在微信申请的公众号或移动应用AppID,与服务商商户号绑定。可参考服务商模式开发必要参数说明
plan_id 必填 string(64)
【模板ID】 信贷还款模板ID; 在服务商平台上成功申请模板后系统自动分配的
out_contract_code 必填 string(64)
【服务商签约协议号】 服务商的签约协议号。服务商需保证唯一性。只能是数字、大小写字母的组合
display_name 必填 string(64)
【用户展示名称】 签约用户的名称,用于签约页面展示;需使用用户姓名掩码。掩码规则:只保留最后一个字符,除最后一个字符外全部字符(包括“.”等符号)均使用“*”替代;如姓名长度大于4个字符,统一用3个“*”+1位明文展示,如***G
contract_notify_url 必填 string(256)
【签约结果通知地址】 接收微信支付异步通知回调地址,通知URL必须为HTTPS且可直接可访问的URL,不能携带参数。参考回调通知注意事项
repayment_day 选填 integer
【还款日】 每月还款的日期
repayment_amount_limit 必填 string
【还款金额上限】 每次最多还款金额;单位:分
sub_mchid 选填 string(32)
【子商户号】 微信支付分配的商户号,服务商商户号与子商户号存在父子关系
sub_appid 选填 string(32)
【子商户AppID】 与子商户号绑定的AppID。可参考服务商模式开发必要参数说明
real_identity 必填 object
【用户实名信息】 商家可选择指定用户实名信息。指定用户实名信息后,微信支付系统会校验商户指定的用户实名信息跟用户在微信支付侧的实名信息是否一致。信息一致时才可进行签约;若信息不一致,不能进行本次签约。注:因实名信息不一致导致无法进行签约,微信支付将不会通知签约结果,也不会产生协议或订单信息。
| 属性 | |
identity_type 必填 string 【实名验证类型】 实名验证类型 可选取值
identity_id 必填 string(512) 【加密后的自然人证件号码】 经过加密后的自然人证件号码信息 real_name 必填 string(512) 【加密后的自然人姓名】 经过加密后的自然人姓名信息 |
trade_info 选填 object
【交易信息】 若希望在进行签约后立即进行首次还款,则必须传入交易信息
| 属性 | |
out_trade_no 必填 string(32) 【商户侧交易单号】 商户系统的交易单号,只能是数字、大小写字母。需要保证在同一个商户号下唯一 deduct_amount 必填 string 【还款金额】 单位:分 description 必填 string(127) 【产品描述】 对产品信息的描述,将展示在用户的支付凭证、用户账单详情中。服务商需传递能真实代表产品信息的描述 attach 选填 string(128) 【商户数据包】 商户可传入自定义数据包,该数据对用户不可见,用于存储商户自定义信息。查询API和支付通知中原样返回,并且该字段还会体现在交易账单。 notify_url 必填 string(1024) 【商户回调地址】 商户接收还款结果通知的地址 |
请求示例
POST
1curl -X POST \ 2 https://api.mch.weixin.qq.com/v3/credit-repayment/partner/contracts/app-presign \ 3 -H "Authorization: WECHATPAY2-SHA256-RSA2048 mchid=\"1900000001\",..." \ 4 -H "Accept: application/json" \ 5 -H "Wechatpay-Serial: 5157F09EFDC096DE15EBE81A47057A7232F1B8E1" \ 6 -H "Content-Type: application/json" \ 7 -d '{ 8 "appid" : "wxd678efh567hg6787", 9 "plan_id" : "WxCreditRepaymentPlan12345678", 10 "out_contract_code" : "WxCreditRepayment20200910100000", 11 "display_name" : "*明", 12 "contract_notify_url" : "https://yourapp.com/notify", 13 "repayment_day" : 1, 14 "repayment_amount_limit" : "10000", 15 "sub_mchid" : "1000000109", 16 "sub_appid" : "wxcbda96de0b165489", 17 "real_identity" : { 18 "identity_type" : "REAL_IDENTITY_TYPE_ID_CARD", 19 "identity_id" : "1axtI9EZUr0343c89xQznxau+cRWPKP4YhVAoj/mEoNSgJh0nvuqQJ1cdXZHGUzyBjOtuLeVq+OLOaWGUScSM8+QLBk+kOK8QyR1TUo44YrmIl5KkjWLa3dpNJt+nIkpN1e7yr2mxO9LGqJdeQXDCHvOiUTK6lnAVxWY0ZrF4OQFmHqOCvqTaF3VxD5a8AT3gxyayF04IJSfPV0NheZvWFBHIUeRPf1/WQmJ/wXu2MfAuESB0dLBglT85i0Rws2GopaTUNiBuJBHdg01bR+YZvSYv8EJPyxuyYVh5bg/wSotNTYnVp13OUzMBKu25yOW5+RnunesXwq9ogPnSj7EDA==", 20 "real_name" : "OEimkKuua8igpd+0YDgqF2Z61leeGD7x87j3PhzsBhAK+/lltXENEOf6ThgV7niChzIpDujIpefE2JFZCJFurf6IV5rxNWBbjFeHYyUGAbf8zDx2Wbi7y7BGjApltIhsxAk+LhQ648Kcw4FMidL/79Gh3nHUfSGX+nEl3gtNi24Ilt8Vu0MMXhA1suDzlpbNDDrYnAhb1eeMziSu8jW7lDouwJXjGh9zgFPUuTxfOpteJIZSy8HWR+QPugdXBNouEezDPN8kojKbJHRtjaBJY3n3agkXShI5yvnc+DCYM+4VgNWZpTx9D0w3KAylJPKAAluYMzj4VXzZurjpruDg2A==" 21 }, 22 "trade_info" : { 23 "out_trade_no" : "1217752501201407033233368018", 24 "deduct_amount" : "10000", 25 "description" : "信贷还款", 26 "attach" : "备注信息", 27 "notify_url" : "https://www.test.com" 28 } 29 }' 30
需配合微信支付工具库 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 * App预签约 24 */ 25public class PartnerPresignContractByApp { 26 private static String HOST = "https://api.mch.weixin.qq.com"; 27 private static String METHOD = "POST"; 28 private static String PATH = "/v3/credit-repayment/partner/contracts/app-presign"; 29 30 public static void main(String[] args) { 31 // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/v3/partner/4013080340 32 PartnerPresignContractByApp client = new PartnerPresignContractByApp( 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 PresignContractByAppRequest request = new PresignContractByAppRequest(); 41 request.appid = "wxd678efh567hg6787"; 42 request.planId = "WxCreditRepaymentPlan12345678"; 43 request.outContractCode = "WxCreditRepayment20200910100000"; 44 request.displayName = "*明"; 45 request.contractNotifyUrl = "https://yourapp.com/notify"; 46 request.repaymentDay = 1L; 47 request.repaymentAmountLimit = "10000"; 48 request.subMchid = "1000000109"; 49 request.subAppid = "wxcbda96de0b165489"; 50 request.realIdentity = new RealIdentity(); 51 request.realIdentity.identityType = RealIdentityType.REAL_IDENTITY_TYPE_ID_CARD; 52 request.realIdentity.identityId = client.encrypt("identity_id"); 53 request.realIdentity.realName = client.encrypt("real_name"); 54 request.tradeInfo = new TradeInfo(); 55 request.tradeInfo.outTradeNo = "1217752501201407033233368018"; 56 request.tradeInfo.deductAmount = "10000"; 57 request.tradeInfo.description = "信贷还款"; 58 request.tradeInfo.attach = "备注信息"; 59 request.tradeInfo.notifyUrl = "https://www.test.com"; 60 try { 61 PresignContractByAppResponse response = client.run(request); 62 // TODO: 请求成功,继续业务逻辑 63 System.out.println(response); 64 } catch (WXPayUtility.ApiException e) { 65 // TODO: 请求失败,根据状态码执行不同的逻辑 66 e.printStackTrace(); 67 } 68 } 69 70 public PresignContractByAppResponse run(PresignContractByAppRequest request) { 71 String uri = PATH; 72 String reqBody = WXPayUtility.toJson(request); 73 74 Request.Builder reqBuilder = new Request.Builder().url(HOST + uri); 75 reqBuilder.addHeader("Accept", "application/json"); 76 reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId); 77 reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody)); 78 reqBuilder.addHeader("Content-Type", "application/json"); 79 RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody); 80 reqBuilder.method(METHOD, requestBody); 81 Request httpRequest = reqBuilder.build(); 82 83 // 发送HTTP请求 84 OkHttpClient client = new OkHttpClient.Builder().build(); 85 try (Response httpResponse = client.newCall(httpRequest).execute()) { 86 String respBody = WXPayUtility.extractBody(httpResponse); 87 if (httpResponse.code() >= 200 && httpResponse.code() < 300) { 88 // 2XX 成功,验证应答签名 89 WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey, 90 httpResponse.headers(), respBody); 91 92 // 从HTTP应答报文构建返回数据 93 return WXPayUtility.fromJson(respBody, PresignContractByAppResponse.class); 94 } else { 95 throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers()); 96 } 97 } catch (IOException e) { 98 throw new UncheckedIOException("Sending request to " + uri + " failed.", e); 99 } 100 } 101 102 private final String mchid; 103 private final String certificateSerialNo; 104 private final PrivateKey privateKey; 105 private final String wechatPayPublicKeyId; 106 private final PublicKey wechatPayPublicKey; 107 108 public PartnerPresignContractByApp(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) { 109 this.mchid = mchid; 110 this.certificateSerialNo = certificateSerialNo; 111 this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath); 112 this.wechatPayPublicKeyId = wechatPayPublicKeyId; 113 this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath); 114 } 115 116 public String encrypt(String plainText) { 117 return WXPayUtility.encrypt(this.wechatPayPublicKey, plainText); 118 } 119 120 public static class PresignContractByAppRequest { 121 @SerializedName("appid") 122 public String appid; 123 124 @SerializedName("plan_id") 125 public String planId; 126 127 @SerializedName("out_contract_code") 128 public String outContractCode; 129 130 @SerializedName("display_name") 131 public String displayName; 132 133 @SerializedName("contract_notify_url") 134 public String contractNotifyUrl; 135 136 @SerializedName("repayment_day") 137 public Long repaymentDay; 138 139 @SerializedName("repayment_amount_limit") 140 public String repaymentAmountLimit; 141 142 @SerializedName("sub_mchid") 143 public String subMchid; 144 145 @SerializedName("sub_appid") 146 public String subAppid; 147 148 @SerializedName("real_identity") 149 public RealIdentity realIdentity; 150 151 @SerializedName("trade_info") 152 public TradeInfo tradeInfo; 153 } 154 155 public static class PresignContractByAppResponse { 156 @SerializedName("presign_token") 157 public String presignToken; 158 159 @SerializedName("redirect_service") 160 public String redirectService; 161 } 162 163 public static class RealIdentity { 164 @SerializedName("identity_type") 165 public RealIdentityType identityType; 166 167 @SerializedName("identity_id") 168 public String identityId; 169 170 @SerializedName("real_name") 171 public String realName; 172 } 173 174 public static class TradeInfo { 175 @SerializedName("out_trade_no") 176 public String outTradeNo; 177 178 @SerializedName("deduct_amount") 179 public String deductAmount; 180 181 @SerializedName("description") 182 public String description; 183 184 @SerializedName("attach") 185 public String attach; 186 187 @SerializedName("notify_url") 188 public String notifyUrl; 189 } 190 191 public enum RealIdentityType { 192 @SerializedName("REAL_IDENTITY_TYPE_INVALID") 193 REAL_IDENTITY_TYPE_INVALID, 194 @SerializedName("REAL_IDENTITY_TYPE_ID_CARD") 195 REAL_IDENTITY_TYPE_ID_CARD 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) 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 := &PresignContractByAppRequest{ 27 Appid: wxpay_utility.String("wxd678efh567hg6787"), 28 PlanId: wxpay_utility.String("WxCreditRepaymentPlan12345678"), 29 OutContractCode: wxpay_utility.String("WxCreditRepayment20200910100000"), 30 DisplayName: wxpay_utility.String("*明"), 31 ContractNotifyUrl: wxpay_utility.String("https://yourapp.com/notify"), 32 RepaymentDay: wxpay_utility.Int64(1), 33 RepaymentAmountLimit: wxpay_utility.String("10000"), 34 SubMchid: wxpay_utility.String("1000000109"), 35 SubAppid: wxpay_utility.String("wxcbda96de0b165489"), 36 RealIdentity: &RealIdentity{ 37 IdentityType: REALIDENTITYTYPE_REAL_IDENTITY_TYPE_ID_CARD.Ptr(), 38 IdentityId: wxpay_utility.String("1axtI9EZUr0343c89xQznxau+cRWPKP4YhVAoj/mEoNSgJh0nvuqQJ1cdXZHGUzyBjOtuLeVq+OLOaWGUScSM8+QLBk+kOK8QyR1TUo44YrmIl5KkjWLa3dpNJt+nIkpN1e7yr2mxO9LGqJdeQXDCHvOiUTK6lnAVxWY0ZrF4OQFmHqOCvqTaF3VxD5a8AT3gxyayF04IJSfPV0NheZvWFBHIUeRPf1/WQmJ/wXu2MfAuESB0dLBglT85i0Rws2GopaTUNiBuJBHdg01bR+YZvSYv8EJPyxuyYVh5bg/wSotNTYnVp13OUzMBKu25yOW5+RnunesXwq9ogPnSj7EDA=="), /*请传入wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/ 39 RealName: wxpay_utility.String("OEimkKuua8igpd+0YDgqF2Z61leeGD7x87j3PhzsBhAK+/lltXENEOf6ThgV7niChzIpDujIpefE2JFZCJFurf6IV5rxNWBbjFeHYyUGAbf8zDx2Wbi7y7BGjApltIhsxAk+LhQ648Kcw4FMidL/79Gh3nHUfSGX+nEl3gtNi24Ilt8Vu0MMXhA1suDzlpbNDDrYnAhb1eeMziSu8jW7lDouwJXjGh9zgFPUuTxfOpteJIZSy8HWR+QPugdXBNouEezDPN8kojKbJHRtjaBJY3n3agkXShI5yvnc+DCYM+4VgNWZpTx9D0w3KAylJPKAAluYMzj4VXzZurjpruDg2A=="), /*请传入wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/ 40 }, 41 TradeInfo: &TradeInfo{ 42 OutTradeNo: wxpay_utility.String("1217752501201407033233368018"), 43 DeductAmount: wxpay_utility.String("10000"), 44 Description: wxpay_utility.String("信贷还款"), 45 Attach: wxpay_utility.String("备注信息"), 46 NotifyUrl: wxpay_utility.String("https://www.test.com"), 47 }, 48 } 49 50 response, err := PartnerPresignContractByApp(config, request) 51 if err != nil { 52 fmt.Printf("请求失败: %+v\n", err) 53 // TODO: 请求失败,根据状态码执行不同的处理 54 return 55 } 56 57 // TODO: 请求成功,继续业务逻辑 58 fmt.Printf("请求成功: %+v\n", response) 59} 60 61func PartnerPresignContractByApp(config *wxpay_utility.MchConfig, request *PresignContractByAppRequest) (response *PresignContractByAppResponse, err error) { 62 const ( 63 host = "https://api.mch.weixin.qq.com" 64 method = "POST" 65 path = "/v3/credit-repayment/partner/contracts/app-presign" 66 ) 67 68 reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path)) 69 if err != nil { 70 return nil, err 71 } 72 reqBody, err := json.Marshal(request) 73 if err != nil { 74 return nil, err 75 } 76 httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody)) 77 if err != nil { 78 return nil, err 79 } 80 httpRequest.Header.Set("Accept", "application/json") 81 httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId()) 82 httpRequest.Header.Set("Content-Type", "application/json") 83 authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody) 84 if err != nil { 85 return nil, err 86 } 87 httpRequest.Header.Set("Authorization", authorization) 88 89 client := &http.Client{} 90 httpResponse, err := client.Do(httpRequest) 91 if err != nil { 92 return nil, err 93 } 94 respBody, err := wxpay_utility.ExtractResponseBody(httpResponse) 95 if err != nil { 96 return nil, err 97 } 98 if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 { 99 // 2XX 成功,验证应答签名 100 err = wxpay_utility.ValidateResponse( 101 config.WechatPayPublicKeyId(), 102 config.WechatPayPublicKey(), 103 &httpResponse.Header, 104 respBody, 105 ) 106 if err != nil { 107 return nil, err 108 } 109 response := &PresignContractByAppResponse{} 110 if err := json.Unmarshal(respBody, response); err != nil { 111 return nil, err 112 } 113 114 return response, nil 115 } else { 116 return nil, wxpay_utility.NewApiException( 117 httpResponse.StatusCode, 118 httpResponse.Header, 119 respBody, 120 ) 121 } 122} 123 124type PresignContractByAppRequest struct { 125 Appid *string `json:"appid,omitempty"` 126 PlanId *string `json:"plan_id,omitempty"` 127 OutContractCode *string `json:"out_contract_code,omitempty"` 128 DisplayName *string `json:"display_name,omitempty"` 129 ContractNotifyUrl *string `json:"contract_notify_url,omitempty"` 130 RepaymentDay *int64 `json:"repayment_day,omitempty"` 131 RepaymentAmountLimit *string `json:"repayment_amount_limit,omitempty"` 132 SubMchid *string `json:"sub_mchid,omitempty"` 133 SubAppid *string `json:"sub_appid,omitempty"` 134 RealIdentity *RealIdentity `json:"real_identity,omitempty"` 135 TradeInfo *TradeInfo `json:"trade_info,omitempty"` 136} 137 138type PresignContractByAppResponse struct { 139 PresignToken *string `json:"presign_token,omitempty"` 140 RedirectService *string `json:"redirect_service,omitempty"` 141} 142 143type RealIdentity struct { 144 IdentityType *RealIdentityType `json:"identity_type,omitempty"` 145 IdentityId *string `json:"identity_id,omitempty"` 146 RealName *string `json:"real_name,omitempty"` 147} 148 149type TradeInfo struct { 150 OutTradeNo *string `json:"out_trade_no,omitempty"` 151 DeductAmount *string `json:"deduct_amount,omitempty"` 152 Description *string `json:"description,omitempty"` 153 Attach *string `json:"attach,omitempty"` 154 NotifyUrl *string `json:"notify_url,omitempty"` 155} 156 157type RealIdentityType string 158 159func (e RealIdentityType) Ptr() *RealIdentityType { 160 return &e 161} 162 163const ( 164 REALIDENTITYTYPE_REAL_IDENTITY_TYPE_INVALID RealIdentityType = "REAL_IDENTITY_TYPE_INVALID" 165 REALIDENTITYTYPE_REAL_IDENTITY_TYPE_ID_CARD RealIdentityType = "REAL_IDENTITY_TYPE_ID_CARD" 166) 167
应答参数
200 OK
presign_token 必填 string(128)
【预签约码】 预签约生成的预签约码,用于跳转签约页面;有效期10分钟
redirect_service 必填 string(64)
【跳转到的签约服务提供方】 跳转到的签约服务提供方,用于跳转签约页面
应答示例
200 OK
1{ 2 "presign_token" : "f55a992c06ade13c1e174149b9e18a63cc900b19165a7515a4c4699ffd73e4a8fc839bc5e9d1b919ae0859619c02226e", 3 "redirect_service" : "wxpayRedirectService" 4} 5
错误码
以下是本接口返回的错误码列表。详细错误码规则,请参考微信支付接口规则-错误码和错误提示
