提交已注销商户号可用余额提现申请单
更新时间:2025.01.09针对被微信支付平台不收不付管控的电商子商户,如子商户账户内还有可用余额,且无法解脱(例如 营业执照注销吊销),则服务商可为子商户申请走注销提现的流程,将可用余额进行提现操作。在商户号注销后,电商平台可发起提现申请, 审批通过后, 将会按照指定的收款方式返回给商户
请仔细阅读以下注意事项:
◆ 当返回错误码为“SYSTEMERROR”时,请不要更换商户提现申请单号,一定要使用原商户提现申请单号重试,否则可能造成重复支付等资金风险。
◆ 提交时遇到任何错误,请商户务必不要换单重试,请商户调用查询提现申请单状态接口确认提现申请单单据的状态, 再决定是否要换单重试, 避免重复提现
◆ 请商户在自身的系统中合理设置付款频次并做好并发控制,防范错付风险。
◆ 因商户自身系统设置存在问题导致的资金损失,由商户自行承担。
接口说明
支持商户:【平台商户】
请求方式:【POST】/v3/mch_operate/risk/withdrawl-apply
请求域名:【主域名】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 包体参数
sub_mchid 必填 string(32)
【二级商户号】资金出款电商平台二级商户号。即电商平台二级商户号,由微信支付生成并下发。调用该提现接口前,会要求该二级商户号已注销
out_account_type 必填 string
【二级商户号的出款子账户类型】根据实际的出款子账户选择
可选取值:
BASIC_ACCOUNT
: 商户的基本户OPERATE_ACCOUNT
: 商户的运营账户MARGIN_ACCOUNT
: 商户的保证金户
amount 必填 integer
【提现金额】单位:分,提现金额不能超过二级商户号出款子账户的余额
out_request_no 必填 string(32)
【商户提现申请单号】商户提现申请单号,由商户自定义生成,必须是字母数字
payee_type 必填 string
【收款对象类型】根据实际的收款对象选择
可选取值:
CONTRIBUTION_MERCHANT
: 出资商户号收款,即已注销商户号资金提现给商户自己,收款账号类型对公银行卡账户 或 对私银行卡账户
SERVICE_PROVIDER_MERCHANT
: 电商平台收款,即已注销商户号资金提现给服务商,收款账号类型支持电商平台同名对公银行卡账户
OTHER_MERCHANT
: 其他商户号收款,即已注销商户号资金提现给其他商户,其他商户即除电商平台自身或出资商户号以外的商户, 收款账号类型视商户号主体类型,可支持对公或对私银行卡账户
INDIVIDUAL
: 个人收款,即已注销商户号资金提现给个人银行卡(例如 给“达人、主播”),收款账号类型支持对私银行卡账户
payee_mchid 选填 string(32)
【收款对象对应的商户号】当收款对象不为个人时必填。
payee_type为“SERVICE_PROVIDER_MERCHANT电商平台收款”,payee_mchid填写对应电商平台服务商商户号;
payee_type为“CONTRIBUTION_MERCHANT出资商户号收款”,payee_mchid填写对应二级子商户号;
payee_type为“OTHER_MERCHANT其他商户号收款”,payee_mchid填写对应其他第三方收款商户号;
payee_info 必填 object
【收款账号信息】实际的收款账号
属性 | |||||||||
account_type 必填 string 【账户类型】payee_type为“CONTRIBUTION_MERCHANT出资商户号收款”,则支持“对公”与“对私”。对私户名会校验是否与法人姓名一致;对公账户户名如与商户号主体不一致,则会要求提供对应授权函 如payee_type为“SERVICE_PROVIDER_MERCHANT电商平台收款”,则仅支持“对公”,且要求户名与电商平台主体一致 如payee_type为“OTHER_MERCHANT其他商户号收款”,如商户号类型为企业类,仅支持“对公”,且要求户名与商户号主体一致;如商户号类型为个体户类,支持“对公”或“对私”,且对公户名需与商户号主体一致,对私户名需与商户号法人姓名一致 如payee_type为“INDIVIDUAL个人收款”,仅支持对私户,户名不做要求,但需要提供对应函件 可选取值:
bank_account_info 必填 object 【银行账户】对应的银行账户
identity_info 选填 object 【收款人账号对应的证件信息】当收款账户为付款到对私银行卡时,需要提供对私账户开户人的身份证件信息,必填, 以下id_doc_type、identification_name、identification_no 必填
|
proof_media_list 选填 object
【付款申请证明材料】各类证明材料, 填写规则
属性 | |||||
proof_payee_media 选填 array[object] 【申请证明材料】
|
additional_materials 选填 object
【补充材料】1、不在上述证明材料中的其他需要服务商补充的,请填写通过图片上传接口预先上传图片生成好的MediaID
属性 | |
additional_media 选填 array[string] 【补充材料照片】最多可上传10张图片,请填写通过图片上传接口预先上传图片生成好的MediaID |
remark 选填 string(1024)
【备注】付款申请备注,方便服务商备注特殊情况。为了提高审核效率,可在此字段描述“原出资商户主体是否已注销”或其他情况
请求示例
POST
1curl -X POST \ 2 https://api.mch.weixin.qq.com/v3/mch_operate/risk/withdrawl-apply \ 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 "sub_mchid" : "1900000109", 9 "out_account_type" : "BASIC_ACCOUNT", 10 "amount" : 101, 11 "out_request_no" : "2019061122222222122", 12 "payee_type" : "CONTRIBUTION_MERCHANT", 13 "payee_mchid" : "1900000109", 14 "payee_info" : { 15 "account_type" : "ACCOUNT_TYPE_CORPORATE", 16 "bank_account_info" : { 17 "account_name" : "AOZdYGISxo4y44/UgZ69bdu9X+tfMUJ9dl+LetjM45/zMbrYu+wWZ8gn4CTdo+D/m9MrPg+V4sm73oxqdQu/hj7aWyDl4GQtPXVdaztB9jVbVZh3QFzV+BEmytMNQp9dt1uWJktlfdDdLR3AMWyMB377xd+m9bSr/ioDTzagEcGe+vLYiKrzcroQv3OR0p3ppFYoQ3IfYeU/04S4t9rNFL+kyblK2FCCqQ11NdbbHoCrJc7NV4oASq6ZFonjTtgjjgKsadIKHXtb3JZKGZjduGdtkRJJp0/0eow96uY1Pk7Rq79Jtt7+I8juwEc4P4TG5xzchG/5IL9DBd+Z0zZXkw==", 18 "account_bank" : "工商银行", 19 "bank_branch_id" : "402713354941", 20 "bank_name" : "施秉县农村信用合作联社城关信用社", 21 "account_number" : "d+xT+MQCvrLHUVDWv/8MR/dB7TkXM2YYZlokmXzFsWs35NXUot7C0NcxIrUF5FnxqCJHkNgKtxa6RxEYyba1+VBRLnqKG2fSy/Y5qDN08Ej9zHCwJjq52Wg1VG8MRugli9YMI1fI83KGBxhuXyemgS/hqFKsfYGiOkJqjTUpgY5VqjtL2N4l4z11T0ECB/aSyVXUysOFGLVfSrUxMPZy6jWWYGvT1+4P633f+R+ki1gT4WF/2KxZOYmli385ZgVhcR30mr4/G3HBcxi13zp7FnEeOsLlvBmI1PHN4C7Rsu3WL8sPndjXTd75kPkyjqnoMRrEEaYQE8ZRGYoeorwC+w==" 22 }, 23 "identity_info" : { 24 "id_doc_type" : "IDENTIFICATION_TYPE_IDCARD", 25 "identification_name" : "pVd1HJ6zyvPedzGaV+X3qtmrq9bb9tPROvwia4ibL+F6mfjbzQIzfb3HHLEjZ4YiR/cJiCrZxnAqi+pjeKIEdkwzXRAI7FUhrfPK3SNjaBTEu9GmsugMIA9r3x887Q+ODuC8HH2nzAn7NGpE/e3yiHgWhk0ps5k5DP/2qIdGdONoDzZelrxCl/NWWNUyB93K9F+jC1JX2IMttdY+aQ6zBlw0xnOiNW6Hzy7UtC+xriudjD5APomty7/mYNxLMpRSvWKIjOv/69bDnuC4EL5Kz4jBHLiCyOb+tI0m2qhZ9evAM+Jv1z0NVa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg==", 26 "identification_no" : "AOZdYGISxo4y44/UgZ69bdu9X+tfMUJ9dl+LetjM45/zMbrYu+wWZ8gn4CTdo+D/m9MrPg+V4sm73oxqdQu/hj7aWyDl4GQtPXVdaztB9jVbVZh3QFzV+BEmytMNQp9dt1uWJktlfdDdLR3AMWyMB377xd+m9bSr/ioDTzagEcGe+vLYiKrzcroQv3OR0p3ppFYoQ3IfYeU/04S4t9rNFL+kyblK2FCCqQ11NdbbHoCrJc7NV4oASq6ZFonjTtgjjgKsadIKHXtb3JZKGZjduGdtkRJJp0/0eow96uY1Pk7Rq79Jtt7+I8juwEc4P4TG5xzchG/5IL9DBd+Z0zZXkw==" 27 } 28 }, 29 "proof_media_list" : { 30 "proof_payee_media" : [ 31 { 32 "proof_media_type" : "WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_1", 33 "proof_media" : "jTpGmxUX3FBWVQ5NJTZvlKX_gdU4cRz7z5NxpnFuAxhBTEO_PvWkfSCJ3zVIn001D8daLC-ehEuo0BJqRTvDujqhThn4ReFxikqJ5YW6zFQ" 34 } 35 ] 36 }, 37 "additional_materials" : { 38 "additional_media" : [ 39 "jTpGmxUX3FBWVQ5NJTZvlKX_gdU4cRz7z5NxpnFuAxhBTEO_PvWkfSCJ3zVIn001D8daLC-ehEuo0BJqRTvDujqhThn4ReFxikqJ5YW6zFQ" 40 ] 41 }, 42 "remark" : "特殊理由" 43 }' 44
需配合微信支付工具库 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 * 提交已注销商户号可用余额提现申请单API 24 */ 25public class SubmitApply { 26 private static String HOST = "https://api.mch.weixin.qq.com"; 27 private static String METHOD = "POST"; 28 private static String PATH = "/v3/mch_operate/risk/withdrawl-apply"; 29 30 public static void main(String[] args) { 31 // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/v3/partner/4013080340 32 SubmitApply client = new SubmitApply( 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 WithdrawalApplyCreateRequest request = new WithdrawalApplyCreateRequest(); 41 request.subMchid = "1900000109"; 42 request.outAccountType = OutAccountType.BASIC_ACCOUNT; 43 request.amount = 101L; 44 request.outRequestNo = "2019061122222222122"; 45 request.payeeType = PayeeType.CONTRIBUTION_MERCHANT; 46 request.payeeMchid = "1900000109"; 47 request.payeeInfo = new PayeeInfo(); 48 request.payeeInfo.accountType = AccountType.ACCOUNT_TYPE_CORPORATE; 49 request.payeeInfo.bankAccountInfo = new BankAccountInfo(); 50 request.payeeInfo.bankAccountInfo.accountName = client.encrypt("account_name"); 51 request.payeeInfo.bankAccountInfo.accountBank = "工商银行"; 52 request.payeeInfo.bankAccountInfo.bankBranchId = "402713354941"; 53 request.payeeInfo.bankAccountInfo.bankName = "施秉县农村信用合作联社城关信用社"; 54 request.payeeInfo.bankAccountInfo.accountNumber = client.encrypt("account_number"); 55 request.payeeInfo.identityInfo = new IdentityInfo(); 56 request.payeeInfo.identityInfo.idDocType = IdentificationType.IDENTIFICATION_TYPE_IDCARD; 57 request.payeeInfo.identityInfo.identificationName = client.encrypt("identification_name"); 58 request.payeeInfo.identityInfo.identificationNo = client.encrypt("identification_no"); 59 request.proofMediaList = new ProofPayeeMediaInfo(); 60 request.proofMediaList.proofPayeeMedia = new ArrayList<>(); 61 { 62 ProofPayeeMedia proofPayeeMediaItem = new ProofPayeeMedia(); 63 proofPayeeMediaItem.proofMediaType = ProofOfPayeeMediaType.WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_1; 64 proofPayeeMediaItem.proofMedia = "jTpGmxUX3FBWVQ5NJTZvlKX_gdU4cRz7z5NxpnFuAxhBTEO_PvWkfSCJ3zVIn001D8daLC-ehEuo0BJqRTvDujqhThn4ReFxikqJ5YW6zFQ"; 65 request.proofMediaList.proofPayeeMedia.add(proofPayeeMediaItem); 66 }; 67 request.additionalMaterials = new AdditionalMediaInfo(); 68 request.additionalMaterials.additionalMedia = new ArrayList<>(); 69 { 70 request.additionalMaterials.additionalMedia.add("jTpGmxUX3FBWVQ5NJTZvlKX_gdU4cRz7z5NxpnFuAxhBTEO_PvWkfSCJ3zVIn001D8daLC-ehEuo0BJqRTvDujqhThn4ReFxikqJ5YW6zFQ"); 71 }; 72 request.remark = "特殊理由"; 73 try { 74 WithdrawalApplyCreateResponse response = client.run(request); 75 // TODO: 请求成功,继续业务逻辑 76 System.out.println(response); 77 } catch (WXPayUtility.ApiException e) { 78 // TODO: 请求失败,根据状态码执行不同的逻辑 79 e.printStackTrace(); 80 } 81 } 82 83 public WithdrawalApplyCreateResponse run(WithdrawalApplyCreateRequest request) { 84 String uri = PATH; 85 String reqBody = WXPayUtility.toJson(request); 86 87 Request.Builder reqBuilder = new Request.Builder().url(HOST + uri); 88 reqBuilder.addHeader("Accept", "application/json"); 89 reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId); 90 reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody)); 91 reqBuilder.addHeader("Content-Type", "application/json"); 92 RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody); 93 reqBuilder.method(METHOD, requestBody); 94 Request httpRequest = reqBuilder.build(); 95 96 // 发送HTTP请求 97 OkHttpClient client = new OkHttpClient.Builder().build(); 98 try (Response httpResponse = client.newCall(httpRequest).execute()) { 99 String respBody = WXPayUtility.extractBody(httpResponse); 100 if (httpResponse.code() >= 200 && httpResponse.code() < 300) { 101 // 2XX 成功,验证应答签名 102 WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey, 103 httpResponse.headers(), respBody); 104 105 // 从HTTP应答报文构建返回数据 106 return WXPayUtility.fromJson(respBody, WithdrawalApplyCreateResponse.class); 107 } else { 108 throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers()); 109 } 110 } catch (IOException e) { 111 throw new UncheckedIOException("Sending request to " + uri + " failed.", e); 112 } 113 } 114 115 private final String mchid; 116 private final String certificateSerialNo; 117 private final PrivateKey privateKey; 118 private final String wechatPayPublicKeyId; 119 private final PublicKey wechatPayPublicKey; 120 121 public SubmitApply(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) { 122 this.mchid = mchid; 123 this.certificateSerialNo = certificateSerialNo; 124 this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath); 125 this.wechatPayPublicKeyId = wechatPayPublicKeyId; 126 this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath); 127 } 128 129 public String encrypt(String plainText) { 130 return WXPayUtility.encrypt(this.wechatPayPublicKey, plainText); 131 } 132 133 public static class WithdrawalApplyCreateRequest { 134 @SerializedName("sub_mchid") 135 public String subMchid; 136 137 @SerializedName("out_account_type") 138 public OutAccountType outAccountType; 139 140 @SerializedName("amount") 141 public Long amount; 142 143 @SerializedName("out_request_no") 144 public String outRequestNo; 145 146 @SerializedName("payee_type") 147 public PayeeType payeeType; 148 149 @SerializedName("payee_mchid") 150 public String payeeMchid; 151 152 @SerializedName("payee_info") 153 public PayeeInfo payeeInfo; 154 155 @SerializedName("proof_media_list") 156 public ProofPayeeMediaInfo proofMediaList; 157 158 @SerializedName("additional_materials") 159 public AdditionalMediaInfo additionalMaterials; 160 161 @SerializedName("remark") 162 public String remark; 163 } 164 165 public static class WithdrawalApplyCreateResponse { 166 @SerializedName("applyment_id") 167 public String applymentId; 168 169 @SerializedName("out_request_no") 170 public String outRequestNo; 171 } 172 173 public enum OutAccountType { 174 @SerializedName("BASIC_ACCOUNT") 175 BASIC_ACCOUNT, 176 @SerializedName("OPERATE_ACCOUNT") 177 OPERATE_ACCOUNT, 178 @SerializedName("MARGIN_ACCOUNT") 179 MARGIN_ACCOUNT 180 } 181 182 public enum PayeeType { 183 @SerializedName("CONTRIBUTION_MERCHANT") 184 CONTRIBUTION_MERCHANT, 185 @SerializedName("SERVICE_PROVIDER_MERCHANT") 186 SERVICE_PROVIDER_MERCHANT, 187 @SerializedName("OTHER_MERCHANT") 188 OTHER_MERCHANT, 189 @SerializedName("INDIVIDUAL") 190 INDIVIDUAL 191 } 192 193 public static class PayeeInfo { 194 @SerializedName("account_type") 195 public AccountType accountType; 196 197 @SerializedName("bank_account_info") 198 public BankAccountInfo bankAccountInfo; 199 200 @SerializedName("identity_info") 201 public IdentityInfo identityInfo; 202 } 203 204 public static class ProofPayeeMediaInfo { 205 @SerializedName("proof_payee_media") 206 public List<ProofPayeeMedia> proofPayeeMedia; 207 } 208 209 public static class AdditionalMediaInfo { 210 @SerializedName("additional_media") 211 public List<String> additionalMedia; 212 } 213 214 public enum AccountType { 215 @SerializedName("ACCOUNT_TYPE_CORPORATE") 216 ACCOUNT_TYPE_CORPORATE, 217 @SerializedName("ACCOUNT_TYPE_PERSONAL") 218 ACCOUNT_TYPE_PERSONAL 219 } 220 221 public static class BankAccountInfo { 222 @SerializedName("account_name") 223 public String accountName; 224 225 @SerializedName("account_bank") 226 public String accountBank; 227 228 @SerializedName("bank_branch_id") 229 public String bankBranchId; 230 231 @SerializedName("bank_name") 232 public String bankName; 233 234 @SerializedName("account_number") 235 public String accountNumber; 236 } 237 238 public static class IdentityInfo { 239 @SerializedName("id_doc_type") 240 public IdentificationType idDocType; 241 242 @SerializedName("identification_name") 243 public String identificationName; 244 245 @SerializedName("identification_no") 246 public String identificationNo; 247 } 248 249 public static class ProofPayeeMedia { 250 @SerializedName("proof_media_type") 251 public ProofOfPayeeMediaType proofMediaType; 252 253 @SerializedName("proof_media") 254 public String proofMedia; 255 } 256 257 public enum IdentificationType { 258 @SerializedName("IDENTIFICATION_TYPE_IDCARD") 259 IDENTIFICATION_TYPE_IDCARD, 260 @SerializedName("IDENTIFICATION_TYPE_OVERSEA_PASSPORT") 261 IDENTIFICATION_TYPE_OVERSEA_PASSPORT, 262 @SerializedName("IDENTIFICATION_TYPE_HONGKONG_PASSPORT") 263 IDENTIFICATION_TYPE_HONGKONG_PASSPORT, 264 @SerializedName("IDENTIFICATION_TYPE_MACAO_PASSPORT") 265 IDENTIFICATION_TYPE_MACAO_PASSPORT, 266 @SerializedName("IDENTIFICATION_TYPE_TAIWAN_PASSPORT") 267 IDENTIFICATION_TYPE_TAIWAN_PASSPORT, 268 @SerializedName("IDENTIFICATION_TYPE_FOREIGN_RESIDENT") 269 IDENTIFICATION_TYPE_FOREIGN_RESIDENT, 270 @SerializedName("IDENTIFICATION_TYPE_HONGKONG_MACAO_RESIDENT") 271 IDENTIFICATION_TYPE_HONGKONG_MACAO_RESIDENT, 272 @SerializedName("IDENTIFICATION_TYPE_TAIWAN_RESIDENT") 273 IDENTIFICATION_TYPE_TAIWAN_RESIDENT 274 } 275 276 public enum ProofOfPayeeMediaType { 277 @SerializedName("WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_1") 278 WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_1, 279 @SerializedName("WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_2") 280 WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_2, 281 @SerializedName("WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_3") 282 WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_3, 283 @SerializedName("WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_4") 284 WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_4, 285 @SerializedName("WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_5") 286 WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_5, 287 @SerializedName("MISSING_OFFICIAL_SEAL_LETTER") 288 MISSING_OFFICIAL_SEAL_LETTER, 289 @SerializedName("CERTIFICATE_OF_ACCOUNT_CANCELLATION") 290 CERTIFICATE_OF_ACCOUNT_CANCELLATION, 291 @SerializedName("INDUSTRIAL_AND_COMMERCIAL_CANCELLATION_CERTIFICATE") 292 INDUSTRIAL_AND_COMMERCIAL_CANCELLATION_CERTIFICATE, 293 @SerializedName("BASIC_TRANSACTION_INFORMATION") 294 BASIC_TRANSACTION_INFORMATION, 295 @SerializedName("LEGAL_ID_CARD") 296 LEGAL_ID_CARD, 297 @SerializedName("ID_CARD") 298 ID_CARD, 299 @SerializedName("BUSINESS_LICENSE_PHOTO") 300 BUSINESS_LICENSE_PHOTO, 301 @SerializedName("PAYEE_ID_CARD") 302 PAYEE_ID_CARD, 303 @SerializedName("WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_6") 304 WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_6, 305 @SerializedName("WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_7") 306 WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_7, 307 @SerializedName("WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_8") 308 WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_8 309 } 310 311} 312
需配合微信支付工具库 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 := &WithdrawalApplyCreateRequest{ 27 SubMchid: wxpay_utility.String("1900000109"), 28 OutAccountType: OUTACCOUNTTYPE_BASIC_ACCOUNT.Ptr(), 29 Amount: wxpay_utility.Int64(101), 30 OutRequestNo: wxpay_utility.String("2019061122222222122"), 31 PayeeType: PAYEETYPE_CONTRIBUTION_MERCHANT.Ptr(), 32 PayeeMchid: wxpay_utility.String("1900000109"), 33 PayeeInfo: &PayeeInfo{ 34 AccountType: ACCOUNTTYPE_ACCOUNT_TYPE_CORPORATE.Ptr(), 35 BankAccountInfo: &BankAccountInfo{ 36 AccountName: wxpay_utility.String("AOZdYGISxo4y44/UgZ69bdu9X+tfMUJ9dl+LetjM45/zMbrYu+wWZ8gn4CTdo+D/m9MrPg+V4sm73oxqdQu/hj7aWyDl4GQtPXVdaztB9jVbVZh3QFzV+BEmytMNQp9dt1uWJktlfdDdLR3AMWyMB377xd+m9bSr/ioDTzagEcGe+vLYiKrzcroQv3OR0p3ppFYoQ3IfYeU/04S4t9rNFL+kyblK2FCCqQ11NdbbHoCrJc7NV4oASq6ZFonjTtgjjgKsadIKHXtb3JZKGZjduGdtkRJJp0/0eow96uY1Pk7Rq79Jtt7+I8juwEc4P4TG5xzchG/5IL9DBd+Z0zZXkw=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/ 37 AccountBank: wxpay_utility.String("工商银行"), 38 BankBranchId: wxpay_utility.String("402713354941"), 39 BankName: wxpay_utility.String("施秉县农村信用合作联社城关信用社"), 40 AccountNumber: wxpay_utility.String("d+xT+MQCvrLHUVDWv/8MR/dB7TkXM2YYZlokmXzFsWs35NXUot7C0NcxIrUF5FnxqCJHkNgKtxa6RxEYyba1+VBRLnqKG2fSy/Y5qDN08Ej9zHCwJjq52Wg1VG8MRugli9YMI1fI83KGBxhuXyemgS/hqFKsfYGiOkJqjTUpgY5VqjtL2N4l4z11T0ECB/aSyVXUysOFGLVfSrUxMPZy6jWWYGvT1+4P633f+R+ki1gT4WF/2KxZOYmli385ZgVhcR30mr4/G3HBcxi13zp7FnEeOsLlvBmI1PHN4C7Rsu3WL8sPndjXTd75kPkyjqnoMRrEEaYQE8ZRGYoeorwC+w=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/ 41 }, 42 IdentityInfo: &IdentityInfo{ 43 IdDocType: IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_IDCARD.Ptr(), 44 IdentificationName: wxpay_utility.String("pVd1HJ6zyvPedzGaV+X3qtmrq9bb9tPROvwia4ibL+F6mfjbzQIzfb3HHLEjZ4YiR/cJiCrZxnAqi+pjeKIEdkwzXRAI7FUhrfPK3SNjaBTEu9GmsugMIA9r3x887Q+ODuC8HH2nzAn7NGpE/e3yiHgWhk0ps5k5DP/2qIdGdONoDzZelrxCl/NWWNUyB93K9F+jC1JX2IMttdY+aQ6zBlw0xnOiNW6Hzy7UtC+xriudjD5APomty7/mYNxLMpRSvWKIjOv/69bDnuC4EL5Kz4jBHLiCyOb+tI0m2qhZ9evAM+Jv1z0NVa8MRtelw/wDa4SzfeespQO/0kjiwfqdfg=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/ 45 IdentificationNo: wxpay_utility.String("AOZdYGISxo4y44/UgZ69bdu9X+tfMUJ9dl+LetjM45/zMbrYu+wWZ8gn4CTdo+D/m9MrPg+V4sm73oxqdQu/hj7aWyDl4GQtPXVdaztB9jVbVZh3QFzV+BEmytMNQp9dt1uWJktlfdDdLR3AMWyMB377xd+m9bSr/ioDTzagEcGe+vLYiKrzcroQv3OR0p3ppFYoQ3IfYeU/04S4t9rNFL+kyblK2FCCqQ11NdbbHoCrJc7NV4oASq6ZFonjTtgjjgKsadIKHXtb3JZKGZjduGdtkRJJp0/0eow96uY1Pk7Rq79Jtt7+I8juwEc4P4TG5xzchG/5IL9DBd+Z0zZXkw=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/ 46 }, 47 }, 48 ProofMediaList: &ProofPayeeMediaInfo{ 49 ProofPayeeMedia: []ProofPayeeMedia{ProofPayeeMedia{ 50 ProofMediaType: PROOFOFPAYEEMEDIATYPE_WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_1.Ptr(), 51 ProofMedia: wxpay_utility.String("jTpGmxUX3FBWVQ5NJTZvlKX_gdU4cRz7z5NxpnFuAxhBTEO_PvWkfSCJ3zVIn001D8daLC-ehEuo0BJqRTvDujqhThn4ReFxikqJ5YW6zFQ"), 52 }}, 53 }, 54 AdditionalMaterials: &AdditionalMediaInfo{ 55 AdditionalMedia: []string{"jTpGmxUX3FBWVQ5NJTZvlKX_gdU4cRz7z5NxpnFuAxhBTEO_PvWkfSCJ3zVIn001D8daLC-ehEuo0BJqRTvDujqhThn4ReFxikqJ5YW6zFQ"}, 56 }, 57 Remark: wxpay_utility.String("特殊理由"), 58 } 59 60 response, err := SubmitApply(config, request) 61 if err != nil { 62 fmt.Printf("请求失败: %+v\n", err) 63 // TODO: 请求失败,根据状态码执行不同的处理 64 return 65 } 66 67 // TODO: 请求成功,继续业务逻辑 68 fmt.Printf("请求成功: %+v\n", response) 69} 70 71func SubmitApply(config *wxpay_utility.MchConfig, request *WithdrawalApplyCreateRequest) (response *WithdrawalApplyCreateResponse, err error) { 72 const ( 73 host = "https://api.mch.weixin.qq.com" 74 method = "POST" 75 path = "/v3/mch_operate/risk/withdrawl-apply" 76 ) 77 78 reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path)) 79 if err != nil { 80 return nil, err 81 } 82 reqBody, err := json.Marshal(request) 83 if err != nil { 84 return nil, err 85 } 86 httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody)) 87 if err != nil { 88 return nil, err 89 } 90 httpRequest.Header.Set("Accept", "application/json") 91 httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId()) 92 httpRequest.Header.Set("Content-Type", "application/json") 93 authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody) 94 if err != nil { 95 return nil, err 96 } 97 httpRequest.Header.Set("Authorization", authorization) 98 99 client := &http.Client{} 100 httpResponse, err := client.Do(httpRequest) 101 if err != nil { 102 return nil, err 103 } 104 respBody, err := wxpay_utility.ExtractResponseBody(httpResponse) 105 if err != nil { 106 return nil, err 107 } 108 if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 { 109 // 2XX 成功,验证应答签名 110 err = wxpay_utility.ValidateResponse( 111 config.WechatPayPublicKeyId(), 112 config.WechatPayPublicKey(), 113 &httpResponse.Header, 114 respBody, 115 ) 116 if err != nil { 117 return nil, err 118 } 119 response := &WithdrawalApplyCreateResponse{} 120 if err := json.Unmarshal(respBody, response); err != nil { 121 return nil, err 122 } 123 124 return response, nil 125 } else { 126 return nil, wxpay_utility.NewApiException( 127 httpResponse.StatusCode, 128 httpResponse.Header, 129 respBody, 130 ) 131 } 132} 133 134type WithdrawalApplyCreateRequest struct { 135 SubMchid *string `json:"sub_mchid,omitempty"` 136 OutAccountType *OutAccountType `json:"out_account_type,omitempty"` 137 Amount *int64 `json:"amount,omitempty"` 138 OutRequestNo *string `json:"out_request_no,omitempty"` 139 PayeeType *PayeeType `json:"payee_type,omitempty"` 140 PayeeMchid *string `json:"payee_mchid,omitempty"` 141 PayeeInfo *PayeeInfo `json:"payee_info,omitempty"` 142 ProofMediaList *ProofPayeeMediaInfo `json:"proof_media_list,omitempty"` 143 AdditionalMaterials *AdditionalMediaInfo `json:"additional_materials,omitempty"` 144 Remark *string `json:"remark,omitempty"` 145} 146 147type WithdrawalApplyCreateResponse struct { 148 ApplymentId *string `json:"applyment_id,omitempty"` 149 OutRequestNo *string `json:"out_request_no,omitempty"` 150} 151 152type OutAccountType string 153 154func (e OutAccountType) Ptr() *OutAccountType { 155 return &e 156} 157 158const ( 159 OUTACCOUNTTYPE_BASIC_ACCOUNT OutAccountType = "BASIC_ACCOUNT" 160 OUTACCOUNTTYPE_OPERATE_ACCOUNT OutAccountType = "OPERATE_ACCOUNT" 161 OUTACCOUNTTYPE_MARGIN_ACCOUNT OutAccountType = "MARGIN_ACCOUNT" 162) 163 164type PayeeType string 165 166func (e PayeeType) Ptr() *PayeeType { 167 return &e 168} 169 170const ( 171 PAYEETYPE_CONTRIBUTION_MERCHANT PayeeType = "CONTRIBUTION_MERCHANT" 172 PAYEETYPE_SERVICE_PROVIDER_MERCHANT PayeeType = "SERVICE_PROVIDER_MERCHANT" 173 PAYEETYPE_OTHER_MERCHANT PayeeType = "OTHER_MERCHANT" 174 PAYEETYPE_INDIVIDUAL PayeeType = "INDIVIDUAL" 175) 176 177type PayeeInfo struct { 178 AccountType *AccountType `json:"account_type,omitempty"` 179 BankAccountInfo *BankAccountInfo `json:"bank_account_info,omitempty"` 180 IdentityInfo *IdentityInfo `json:"identity_info,omitempty"` 181} 182 183type ProofPayeeMediaInfo struct { 184 ProofPayeeMedia []ProofPayeeMedia `json:"proof_payee_media,omitempty"` 185} 186 187type AdditionalMediaInfo struct { 188 AdditionalMedia []string `json:"additional_media,omitempty"` 189} 190 191type AccountType string 192 193func (e AccountType) Ptr() *AccountType { 194 return &e 195} 196 197const ( 198 ACCOUNTTYPE_ACCOUNT_TYPE_CORPORATE AccountType = "ACCOUNT_TYPE_CORPORATE" 199 ACCOUNTTYPE_ACCOUNT_TYPE_PERSONAL AccountType = "ACCOUNT_TYPE_PERSONAL" 200) 201 202type BankAccountInfo struct { 203 AccountName *string `json:"account_name,omitempty"` 204 AccountBank *string `json:"account_bank,omitempty"` 205 BankBranchId *string `json:"bank_branch_id,omitempty"` 206 BankName *string `json:"bank_name,omitempty"` 207 AccountNumber *string `json:"account_number,omitempty"` 208} 209 210type IdentityInfo struct { 211 IdDocType *IdentificationType `json:"id_doc_type,omitempty"` 212 IdentificationName *string `json:"identification_name,omitempty"` 213 IdentificationNo *string `json:"identification_no,omitempty"` 214} 215 216type ProofPayeeMedia struct { 217 ProofMediaType *ProofOfPayeeMediaType `json:"proof_media_type,omitempty"` 218 ProofMedia *string `json:"proof_media,omitempty"` 219} 220 221type IdentificationType string 222 223func (e IdentificationType) Ptr() *IdentificationType { 224 return &e 225} 226 227const ( 228 IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_IDCARD IdentificationType = "IDENTIFICATION_TYPE_IDCARD" 229 IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_OVERSEA_PASSPORT IdentificationType = "IDENTIFICATION_TYPE_OVERSEA_PASSPORT" 230 IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_HONGKONG_PASSPORT IdentificationType = "IDENTIFICATION_TYPE_HONGKONG_PASSPORT" 231 IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_MACAO_PASSPORT IdentificationType = "IDENTIFICATION_TYPE_MACAO_PASSPORT" 232 IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_TAIWAN_PASSPORT IdentificationType = "IDENTIFICATION_TYPE_TAIWAN_PASSPORT" 233 IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_FOREIGN_RESIDENT IdentificationType = "IDENTIFICATION_TYPE_FOREIGN_RESIDENT" 234 IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_HONGKONG_MACAO_RESIDENT IdentificationType = "IDENTIFICATION_TYPE_HONGKONG_MACAO_RESIDENT" 235 IDENTIFICATIONTYPE_IDENTIFICATION_TYPE_TAIWAN_RESIDENT IdentificationType = "IDENTIFICATION_TYPE_TAIWAN_RESIDENT" 236) 237 238type ProofOfPayeeMediaType string 239 240func (e ProofOfPayeeMediaType) Ptr() *ProofOfPayeeMediaType { 241 return &e 242} 243 244const ( 245 PROOFOFPAYEEMEDIATYPE_WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_1 ProofOfPayeeMediaType = "WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_1" 246 PROOFOFPAYEEMEDIATYPE_WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_2 ProofOfPayeeMediaType = "WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_2" 247 PROOFOFPAYEEMEDIATYPE_WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_3 ProofOfPayeeMediaType = "WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_3" 248 PROOFOFPAYEEMEDIATYPE_WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_4 ProofOfPayeeMediaType = "WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_4" 249 PROOFOFPAYEEMEDIATYPE_WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_5 ProofOfPayeeMediaType = "WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_5" 250 PROOFOFPAYEEMEDIATYPE_MISSING_OFFICIAL_SEAL_LETTER ProofOfPayeeMediaType = "MISSING_OFFICIAL_SEAL_LETTER" 251 PROOFOFPAYEEMEDIATYPE_CERTIFICATE_OF_ACCOUNT_CANCELLATION ProofOfPayeeMediaType = "CERTIFICATE_OF_ACCOUNT_CANCELLATION" 252 PROOFOFPAYEEMEDIATYPE_INDUSTRIAL_AND_COMMERCIAL_CANCELLATION_CERTIFICATE ProofOfPayeeMediaType = "INDUSTRIAL_AND_COMMERCIAL_CANCELLATION_CERTIFICATE" 253 PROOFOFPAYEEMEDIATYPE_BASIC_TRANSACTION_INFORMATION ProofOfPayeeMediaType = "BASIC_TRANSACTION_INFORMATION" 254 PROOFOFPAYEEMEDIATYPE_LEGAL_ID_CARD ProofOfPayeeMediaType = "LEGAL_ID_CARD" 255 PROOFOFPAYEEMEDIATYPE_ID_CARD ProofOfPayeeMediaType = "ID_CARD" 256 PROOFOFPAYEEMEDIATYPE_BUSINESS_LICENSE_PHOTO ProofOfPayeeMediaType = "BUSINESS_LICENSE_PHOTO" 257 PROOFOFPAYEEMEDIATYPE_PAYEE_ID_CARD ProofOfPayeeMediaType = "PAYEE_ID_CARD" 258 PROOFOFPAYEEMEDIATYPE_WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_6 ProofOfPayeeMediaType = "WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_6" 259 PROOFOFPAYEEMEDIATYPE_WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_7 ProofOfPayeeMediaType = "WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_7" 260 PROOFOFPAYEEMEDIATYPE_WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_8 ProofOfPayeeMediaType = "WECHAT_PAY_WITHDRAWAL_APPLICATION_TYPE_8" 261) 262
应答参数
|
applyment_id 选填 string(32)
【微信支付提现申请单号】电商平台提交二级商户可用余额提现申请后,由微信支付返回的申请单号,作为查询申请状态的唯一标识。
out_request_no 选填 string(32)
【商户提现申请单号】商户预约提现单号,由商户自定义生成,需要全局唯一
应答示例
200 OK
1{ 2 "applyment_id" : "20220101332222", 3 "out_request_no" : "1234567" 4} 5
错误码
公共错误码
状态码 | 错误码 | 描述 | 解决方案 |
---|---|---|---|
400 | PARAM_ERROR | 参数错误 | 请根据错误提示正确传入参数 |
400 | INVALID_REQUEST | HTTP 请求不符合微信支付 APIv3 接口规则 | 请参阅 接口规则 |
401 | SIGN_ERROR | 验证不通过 | 请参阅 签名常见问题 |
500 | SYSTEM_ERROR | 系统异常,请稍后重试 | 请稍后重试 |
业务错误码
状态码 | 错误码 | 描述 | 解决方案 |
---|---|---|---|
400 | RESOURCE_ALREADY_EXISTS | 重复提交, 商户的提现申请单号已经存在, 请调用查询状态接口检查 | 重复提交, 商户的提现申请单号已经存在, 请调用查询状态接口检查 |
403 | NO_AUTH | 商户暂无权限使用此功能 | 仅允许电商平台允许使用。 |
403 | NOTENOUGH | 二级商户号账户可用余额不足 | 二级商户号账户可用余额不足 |
429 | FREQUENCY_LIMITED | 频率限制 | 请降低频率后重试 |