将电子发票插入微信用户卡包
更新时间:2025.09.03商户自行开具电子发票后,可调用本接口将电子发票插入微信用户的卡包。
请求本接口前需要调用【上传电子发票文件】接口上传电子发票文件并获取文件ID。
注:该文件ID三天内有效。
若是非微信支付场景,需要先通过【获取用户抬头填写链接】接口获取用户授权链接,并等待用户完成授权才能调用本接口;若是微信支付场景,则无需额外获取用户授权。
注意,本接口返回成功仅代表请求被受理。当插卡完成时,微信支付会根据商户配置的回调地址进行回调通知,商户也可以通过【查询电子发票】接口获取插卡结果及卡券信息。
注:一个微信支付订单只能插卡一次,最多对应五张电子发票,多次调用会做幂等性检查。
接口说明
支持商户:【普通服务商】
请求方式:【POST】/v3/new-tax-control-fapiao/fapiao-applications/{fapiao_apply_id}/insert-cards
请求域名:【主域名】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说明以及微信支付公钥加密敏感信息指引;也可以使用微信支付平台证书公钥加密,参考获取平台证书序列号、平台证书加密敏感信息指引
path 路径参数
fapiao_apply_id 必填 string(32)
【发票申请单号】 发票申请单号,唯一标识一次开票行为。当开票场景为WITHOUT_WECHATPAY时,为调用【获取用户抬头填写链接】接口时指定的发票申请单号;当开票场景为WITH_WECHATPAY时,为与本次开票关联的微信支付订单号,且必须是属于相应商户的订单(服务商模式下该订单必须属于子商户;直连模式下该订单必须属于直连商户)
body 包体参数
sub_mchid 必填 string(32)
【子商户号】 微信支付分配的子商户号,具体请参考服务商模式开发必要参数说明
scene 必填 string
【插卡场景】 插卡场景
可选取值
WITH_WECHATPAY
: 微信支付场景WITHOUT_WECHATPAY
: 非微信支付场景
buyer_information 必填 object
【购买方信息】 购买方信息,即发票抬头。商户可以从【获取用户填写抬头信息】接口获取用户填写的抬头;微信支付场景下,若该笔订单在下单时指定在支付凭证上不展示开票入口,则商户需要自行获取用户抬头。
属性 | |
type 必填 string 【购买方类型】 购买方类型 可选取值
name 必填 string(256) 【名称】 购买方名称 taxpayer_id 选填 string(32) 【纳税人识别号】 购买方纳税人识别号,购买方类型为ORGANIZATION时必填 address 选填 string(128) 【地址】 购买方地址 telephone 选填 string(32) 【电话】 购买方电话 bank_name 选填 string(128) 【开户银行名称】 购买方开户银行名称 bank_account 选填 string(32) 【银行账号】 购买方银行账号 phone 选填 string 【手机号】 用户手机号。注意:该字段为密文字段,作为请求字段需加密,使用微信支付公钥加密(推荐),参考获取微信支付公钥ID说明以及微信支付公钥加密敏感信息指引;也可以使用微信支付平台证书公钥加密,参考获取平台证书序列号、平台证书加密敏感信息指引;作为响应字段需解密,参考如何使用API证书解密敏感字段 email 选填 string 【邮箱地址】 用户邮箱地址。注意:该字段为密文字段,作为请求字段需加密,使用微信支付公钥加密(推荐),参考获取微信支付公钥ID说明以及微信支付公钥加密敏感信息指引;也可以使用微信支付平台证书公钥加密,参考获取平台证书序列号、平台证书加密敏感信息指引;作为响应字段需解密,参考如何使用API证书解密敏感字段 amount 选填 integer 【订单金额】 微信支付订单金额,仅在微信支付场景下有效,单位:分 out_trade_no 选填 string(32) 【商户订单号】 商户订单号,仅在微信支付场景下有效 fapiao_bill_type 选填 string 【开具的发票类型】 用户选择提交开具发票的类型 可选取值
user_apply_message 选填 string(100) 【留言信息】 用户申请开票时提交的留言信息 |
fapiao_card_information 必填 array[object]
【电子发票卡券信息列表】 电子发票卡券信息列表,最多五条
属性 | |||||||||||||
fapiao_media_id 必填 string(128) 【电子发票文件ID】 上传的电子发票文件对应的ID,用于CreateFapiaoCard接口 fapiao_number 必填 string(20) 【发票号码】 发票号码 fapiao_code 选填 string(12) 【发票代码】 发票代码,非数电发票必填 fapiao_time 必填 string(32) 【开票时间】 开票时间,遵循RFC3339标准格式:yyyy-MM-DDTHH:mm:ss+TIMEZONE check_code 选填 string(20) 【校验码】 校验码,非数电发票必填 password 选填 string(1024) 【密码】 发票票面密码区内容,非数电发票必填 total_amount 必填 integer 【总价税合计】 总价税合计,所有发票行单行金额合计的累加,单位:分 tax_amount 必填 integer 【总税额】 总税额,所有发票行单行税额的累加,单位:分 amount 必填 integer 【总金额】 总金额,所有发票行单行金额的累加,单位:分 seller_information 必填 object 【销售方信息】 销售方信息
extra_information 必填 object 【附加信息】 附加信息
items 选填 array[object] 【发票行信息】 发票行信息
remark 选填 string(200) 【备注信息】 备注信息 |
请求示例
POST
1curl -X POST \ 2 https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/fapiao-applications/4200000444201910177461284488/insert-cards \ 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 "scene" : "WITH_WECHATPAY", 10 "buyer_information" : { 11 "type" : "INDIVIDUAL", 12 "name" : "深圳市南山区测试企业", 13 "taxpayer_id" : "202003261233701778", 14 "address" : "深圳市南山区深南大道10000号", 15 "telephone" : "075512345678", 16 "bank_name" : "测试银行", 17 "bank_account" : "62001234567890", 18 "phone" : "mI7HGEJ4Q2B91IGjHrl7FNN9QuFPDfzeXoaJM4B8ZghZPzXK+vNotEZu/Gthm87Szv0MK2AoC0/3ZMDgltMtdoY6O0qZ4F1iXiwCuqkkBe+9M4ggvdzpPGM+fyed2QU1seUGbii5RVVVB9s+zLEQ8nv74vsgl77MZx14nd5obtCcfAvPfDJob3oG7FqlThmYKJqjiOwBvvQse7p9R8onj/POzSrbM8re8ZYGp4LcehXopTLdk2ZVWRv8bnJgKZWArAcqMdahq4jY2UVYeY4vpMmq4xuRTYk6xNXvowBBKK2SX8SqM+jm1USyoBIazLu4oaNFNdBO3fip1a1rFW0vRw==", 19 "email" : "NzJy3r0Z2u2Vs5l+WSH0A3CZ1oGlCZ66aa2wUlMXNmACbd4wU8LqqYCuTG4cYWxrVUSmviV59/Uy9vLdIwuHZVrMalYAZGtb8inWGhDj3wUqQnPkmBKBVGIWG5Y6XJmMvpXW6rIKsdzxs8NwWj30cRNfjanLxiWc0aIgl8Knwo0JcxlcYLo38T9ntsrRkQZMQEWHaMYnzjp7ysLbp6yW83OZb/NwEufERBdPnIbDbVE7DUd5MGhvO+tlr2YC1b4VCsrDmjryuTD5nvYYCGHyfXW2CM23hZdBm9tPc+mU18Z9d4XkasnfsecGWd2ISkpPmnk3DtapnD64Nw8JyLtkgw==", 20 "amount" : 1000, 21 "out_trade_no" : "order_20200701_123456", 22 "fapiao_bill_type" : "COMM_FAPIAO", 23 "user_apply_message" : "用户留言" 24 }, 25 "fapiao_card_information" : [ 26 { 27 "fapiao_media_id" : "ASNFZ4mrze/+3LqYdlQyEA==", 28 "fapiao_number" : "12897794", 29 "fapiao_code" : "044001911211", 30 "fapiao_time" : "2020-07-01T12:00:00+08:00", 31 "check_code" : "69001808340631374774", 32 "password" : "006>299-375/326>2+7/*0-+<351059<80<4*/5>+<11631+*3030/5*37+/-243159658+013>3409*044>4-/1+/9->*>69501*6++1997--21", 33 "total_amount" : 382895, 34 "tax_amount" : 44050, 35 "amount" : 338845, 36 "seller_information" : { 37 "name" : "深圳市南山区测试公司", 38 "taxpayer_id" : "202003261233701778", 39 "address" : "深圳市南山区深南大道10000号", 40 "telephone" : "075512345678", 41 "bank_name" : "测试银行", 42 "bank_account" : "62001234567890" 43 }, 44 "extra_information" : { 45 "payee" : "张三", 46 "reviewer" : "李四", 47 "drawer" : "王五" 48 }, 49 "items" : [ 50 { 51 "tax_code" : "3010101020203000000", 52 "goods_name" : "出租汽车客运服务", 53 "specification" : "A4", 54 "unit" : "次", 55 "quantity" : 100000000, 56 "unit_price" : 380442000000, 57 "amount" : 380442, 58 "tax_amount" : 49458, 59 "total_amount" : 429900, 60 "tax_rate" : 1300, 61 "tax_prefer_mark" : "NO_FAVORABLE", 62 "discount" : false 63 } 64 ], 65 "remark" : "备注" 66 } 67 ] 68 }' 69
需配合微信支付工具库 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 InsertCards { 26 private static String HOST = "https://api.mch.weixin.qq.com"; 27 private static String METHOD = "POST"; 28 private static String PATH = "/v3/new-tax-control-fapiao/fapiao-applications/{fapiao_apply_id}/insert-cards"; 29 30 public static void main(String[] args) { 31 // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/v3/partner/4013080340 32 InsertCards client = new InsertCards( 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 InsertCardsRequest request = new InsertCardsRequest(); 41 request.fapiaoApplyId = "4200000444201910177461284488"; 42 request.subMchid = "1900000109"; 43 request.scene = Scene.WITH_WECHATPAY; 44 request.buyerInformation = new UserTitleEntity(); 45 request.buyerInformation.type = BuyerType.INDIVIDUAL; 46 request.buyerInformation.name = "深圳市南山区测试企业"; 47 request.buyerInformation.taxpayerId = "202003261233701778"; 48 request.buyerInformation.address = "深圳市南山区深南大道10000号"; 49 request.buyerInformation.telephone = "075512345678"; 50 request.buyerInformation.bankName = "测试银行"; 51 request.buyerInformation.bankAccount = "62001234567890"; 52 request.buyerInformation.phone = client.encrypt("phone"); 53 request.buyerInformation.email = client.encrypt("email"); 54 request.buyerInformation.amount = 1000L; 55 request.buyerInformation.outTradeNo = "order_20200701_123456"; 56 request.buyerInformation.fapiaoBillType = FapiaoBillType.COMM_FAPIAO; 57 request.buyerInformation.userApplyMessage = "用户留言"; 58 request.fapiaoCardInformation = new ArrayList<>(); 59 { 60 FapiaoCardInfo fapiaoCardInformationItem = new FapiaoCardInfo(); 61 fapiaoCardInformationItem.fapiaoMediaId = "ASNFZ4mrze/+3LqYdlQyEA=="; 62 fapiaoCardInformationItem.fapiaoNumber = "12897794"; 63 fapiaoCardInformationItem.fapiaoCode = "044001911211"; 64 fapiaoCardInformationItem.fapiaoTime = "2020-07-01T12:00:00+08:00"; 65 fapiaoCardInformationItem.checkCode = "69001808340631374774"; 66 fapiaoCardInformationItem.password = "006>299-375/326>2+7/_*0-+<351059<80<4*_/5>+<11631+*3030/5*37+/-243159658+013>3409*044>4-/1+/9->*>69501*6++1997--21"; 67 fapiaoCardInformationItem.totalAmount = 382895L; 68 fapiaoCardInformationItem.taxAmount = 44050L; 69 fapiaoCardInformationItem.amount = 338845L; 70 fapiaoCardInformationItem.sellerInformation = new SellerInfo(); 71 fapiaoCardInformationItem.sellerInformation.name = "深圳市南山区测试公司"; 72 fapiaoCardInformationItem.sellerInformation.taxpayerId = "202003261233701778"; 73 fapiaoCardInformationItem.sellerInformation.address = "深圳市南山区深南大道10000号"; 74 fapiaoCardInformationItem.sellerInformation.telephone = "075512345678"; 75 fapiaoCardInformationItem.sellerInformation.bankName = "测试银行"; 76 fapiaoCardInformationItem.sellerInformation.bankAccount = "62001234567890"; 77 fapiaoCardInformationItem.extraInformation = new ExtraInfo(); 78 fapiaoCardInformationItem.extraInformation.payee = "张三"; 79 fapiaoCardInformationItem.extraInformation.reviewer = "李四"; 80 fapiaoCardInformationItem.extraInformation.drawer = "王五"; 81 fapiaoCardInformationItem.items = new ArrayList<>(); 82 { 83 FapiaoItem itemsItem = new FapiaoItem(); 84 itemsItem.taxCode = "3010101020203000000"; 85 itemsItem.goodsName = "出租汽车客运服务"; 86 itemsItem.specification = "A4"; 87 itemsItem.unit = "次"; 88 itemsItem.quantity = 100000000L; 89 itemsItem.unitPrice = 380442000000L; 90 itemsItem.amount = 380442L; 91 itemsItem.taxAmount = 49458L; 92 itemsItem.totalAmount = 429900L; 93 itemsItem.taxRate = 1300L; 94 itemsItem.taxPreferMark = TaxPreferMark.NO_FAVORABLE; 95 itemsItem.discount = false; 96 fapiaoCardInformationItem.items.add(itemsItem); 97 }; 98 fapiaoCardInformationItem.remark = "备注"; 99 request.fapiaoCardInformation.add(fapiaoCardInformationItem); 100 }; 101 try { 102 client.run(request); 103 } catch (WXPayUtility.ApiException e) { 104 // TODO: 请求失败,根据状态码执行不同的逻辑 105 e.printStackTrace(); 106 } 107 } 108 109 public void run(InsertCardsRequest request) { 110 String uri = PATH; 111 uri = uri.replace("{fapiao_apply_id}", WXPayUtility.urlEncode(request.fapiaoApplyId)); 112 String reqBody = WXPayUtility.toJson(request); 113 114 Request.Builder reqBuilder = new Request.Builder().url(HOST + uri); 115 reqBuilder.addHeader("Accept", "application/json"); 116 reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId); 117 reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody)); 118 reqBuilder.addHeader("Content-Type", "application/json"); 119 RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody); 120 reqBuilder.method(METHOD, requestBody); 121 Request httpRequest = reqBuilder.build(); 122 123 // 发送HTTP请求 124 OkHttpClient client = new OkHttpClient.Builder().build(); 125 try (Response httpResponse = client.newCall(httpRequest).execute()) { 126 String respBody = WXPayUtility.extractBody(httpResponse); 127 if (httpResponse.code() >= 200 && httpResponse.code() < 300) { 128 // 2XX 成功,验证应答签名 129 WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey, 130 httpResponse.headers(), respBody); 131 132 return; 133 } else { 134 throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers()); 135 } 136 } catch (IOException e) { 137 throw new UncheckedIOException("Sending request to " + uri + " failed.", e); 138 } 139 } 140 141 private final String mchid; 142 private final String certificateSerialNo; 143 private final PrivateKey privateKey; 144 private final String wechatPayPublicKeyId; 145 private final PublicKey wechatPayPublicKey; 146 147 public InsertCards(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) { 148 this.mchid = mchid; 149 this.certificateSerialNo = certificateSerialNo; 150 this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath); 151 this.wechatPayPublicKeyId = wechatPayPublicKeyId; 152 this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath); 153 } 154 155 public String encrypt(String plainText) { 156 return WXPayUtility.encrypt(this.wechatPayPublicKey, plainText); 157 } 158 159 public static class InsertCardsRequest { 160 @SerializedName("sub_mchid") 161 public String subMchid; 162 163 @SerializedName("scene") 164 public Scene scene; 165 166 @SerializedName("fapiao_apply_id") 167 @Expose(serialize = false) 168 public String fapiaoApplyId; 169 170 @SerializedName("buyer_information") 171 public UserTitleEntity buyerInformation; 172 173 @SerializedName("fapiao_card_information") 174 public List<FapiaoCardInfo> fapiaoCardInformation = new ArrayList<FapiaoCardInfo>(); 175 } 176 177 public enum Scene { 178 @SerializedName("WITH_WECHATPAY") 179 WITH_WECHATPAY, 180 @SerializedName("WITHOUT_WECHATPAY") 181 WITHOUT_WECHATPAY 182 } 183 184 public static class UserTitleEntity { 185 @SerializedName("type") 186 public BuyerType type; 187 188 @SerializedName("name") 189 public String name; 190 191 @SerializedName("taxpayer_id") 192 public String taxpayerId; 193 194 @SerializedName("address") 195 public String address; 196 197 @SerializedName("telephone") 198 public String telephone; 199 200 @SerializedName("bank_name") 201 public String bankName; 202 203 @SerializedName("bank_account") 204 public String bankAccount; 205 206 @SerializedName("phone") 207 public String phone; 208 209 @SerializedName("email") 210 public String email; 211 212 @SerializedName("amount") 213 public Long amount; 214 215 @SerializedName("out_trade_no") 216 public String outTradeNo; 217 218 @SerializedName("fapiao_bill_type") 219 public FapiaoBillType fapiaoBillType; 220 221 @SerializedName("user_apply_message") 222 public String userApplyMessage; 223 } 224 225 public static class FapiaoCardInfo { 226 @SerializedName("fapiao_media_id") 227 public String fapiaoMediaId; 228 229 @SerializedName("fapiao_number") 230 public String fapiaoNumber; 231 232 @SerializedName("fapiao_code") 233 public String fapiaoCode; 234 235 @SerializedName("fapiao_time") 236 public String fapiaoTime; 237 238 @SerializedName("check_code") 239 public String checkCode; 240 241 @SerializedName("password") 242 public String password; 243 244 @SerializedName("total_amount") 245 public Long totalAmount; 246 247 @SerializedName("tax_amount") 248 public Long taxAmount; 249 250 @SerializedName("amount") 251 public Long amount; 252 253 @SerializedName("seller_information") 254 public SellerInfo sellerInformation; 255 256 @SerializedName("extra_information") 257 public ExtraInfo extraInformation; 258 259 @SerializedName("items") 260 public List<FapiaoItem> items; 261 262 @SerializedName("remark") 263 public String remark; 264 } 265 266 public enum BuyerType { 267 @SerializedName("INDIVIDUAL") 268 INDIVIDUAL, 269 @SerializedName("ORGANIZATION") 270 ORGANIZATION 271 } 272 273 public enum FapiaoBillType { 274 @SerializedName("COMM_FAPIAO") 275 COMM_FAPIAO, 276 @SerializedName("VAT_FAPIAO") 277 VAT_FAPIAO 278 } 279 280 public static class SellerInfo { 281 @SerializedName("name") 282 public String name; 283 284 @SerializedName("taxpayer_id") 285 public String taxpayerId; 286 287 @SerializedName("address") 288 public String address; 289 290 @SerializedName("telephone") 291 public String telephone; 292 293 @SerializedName("bank_name") 294 public String bankName; 295 296 @SerializedName("bank_account") 297 public String bankAccount; 298 } 299 300 public static class ExtraInfo { 301 @SerializedName("payee") 302 public String payee; 303 304 @SerializedName("reviewer") 305 public String reviewer; 306 307 @SerializedName("drawer") 308 public String drawer; 309 } 310 311 public static class FapiaoItem { 312 @SerializedName("tax_code") 313 public String taxCode; 314 315 @SerializedName("goods_name") 316 public String goodsName; 317 318 @SerializedName("specification") 319 public String specification; 320 321 @SerializedName("unit") 322 public String unit; 323 324 @SerializedName("quantity") 325 public Long quantity; 326 327 @SerializedName("unit_price") 328 public Long unitPrice; 329 330 @SerializedName("amount") 331 public Long amount; 332 333 @SerializedName("tax_amount") 334 public Long taxAmount; 335 336 @SerializedName("total_amount") 337 public Long totalAmount; 338 339 @SerializedName("tax_rate") 340 public Long taxRate; 341 342 @SerializedName("tax_prefer_mark") 343 public TaxPreferMark taxPreferMark; 344 345 @SerializedName("discount") 346 public Boolean discount; 347 } 348 349 public enum TaxPreferMark { 350 @SerializedName("NO_FAVORABLE") 351 NO_FAVORABLE, 352 @SerializedName("OUTSIDE_VAT") 353 OUTSIDE_VAT, 354 @SerializedName("VAT_EXEMPT") 355 VAT_EXEMPT, 356 @SerializedName("NORMAL_ZERO_RATED") 357 NORMAL_ZERO_RATED, 358 @SerializedName("EXPORT_ZERO_RATED") 359 EXPORT_ZERO_RATED 360 } 361 362} 363
需配合微信支付工具库 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 := &InsertCardsRequest{ 28 FapiaoApplyId: wxpay_utility.String("4200000444201910177461284488"), 29 SubMchid: wxpay_utility.String("1900000109"), 30 Scene: SCENE_WITH_WECHATPAY.Ptr(), 31 BuyerInformation: &UserTitleEntity{ 32 Type: BUYERTYPE_INDIVIDUAL.Ptr(), 33 Name: wxpay_utility.String("深圳市南山区测试企业"), 34 TaxpayerId: wxpay_utility.String("202003261233701778"), 35 Address: wxpay_utility.String("深圳市南山区深南大道10000号"), 36 Telephone: wxpay_utility.String("075512345678"), 37 BankName: wxpay_utility.String("测试银行"), 38 BankAccount: wxpay_utility.String("62001234567890"), 39 Phone: wxpay_utility.String("mI7HGEJ4Q2B91IGjHrl7FNN9QuFPDfzeXoaJM4B8ZghZPzXK+vNotEZu/Gthm87Szv0MK2AoC0/3ZMDgltMtdoY6O0qZ4F1iXiwCuqkkBe+9M4ggvdzpPGM+fyed2QU1seUGbii5RVVVB9s+zLEQ8nv74vsgl77MZx14nd5obtCcfAvPfDJob3oG7FqlThmYKJqjiOwBvvQse7p9R8onj/POzSrbM8re8ZYGp4LcehXopTLdk2ZVWRv8bnJgKZWArAcqMdahq4jY2UVYeY4vpMmq4xuRTYk6xNXvowBBKK2SX8SqM+jm1USyoBIazLu4oaNFNdBO3fip1a1rFW0vRw=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/ 40 Email: wxpay_utility.String("NzJy3r0Z2u2Vs5l+WSH0A3CZ1oGlCZ66aa2wUlMXNmACbd4wU8LqqYCuTG4cYWxrVUSmviV59/Uy9vLdIwuHZVrMalYAZGtb8inWGhDj3wUqQnPkmBKBVGIWG5Y6XJmMvpXW6rIKsdzxs8NwWj30cRNfjanLxiWc0aIgl8Knwo0JcxlcYLo38T9ntsrRkQZMQEWHaMYnzjp7ysLbp6yW83OZb/NwEufERBdPnIbDbVE7DUd5MGhvO+tlr2YC1b4VCsrDmjryuTD5nvYYCGHyfXW2CM23hZdBm9tPc+mU18Z9d4XkasnfsecGWd2ISkpPmnk3DtapnD64Nw8JyLtkgw=="), /*请传入 wxpay_utility.EncryptOAEPWithPublicKey 加密结果*/ 41 Amount: wxpay_utility.Int64(1000), 42 OutTradeNo: wxpay_utility.String("order_20200701_123456"), 43 FapiaoBillType: FAPIAOBILLTYPE_COMM_FAPIAO.Ptr(), 44 UserApplyMessage: wxpay_utility.String("用户留言"), 45 }, 46 FapiaoCardInformation: []FapiaoCardInfo{FapiaoCardInfo{ 47 FapiaoMediaId: wxpay_utility.String("ASNFZ4mrze/+3LqYdlQyEA=="), 48 FapiaoNumber: wxpay_utility.String("12897794"), 49 FapiaoCode: wxpay_utility.String("044001911211"), 50 FapiaoTime: wxpay_utility.String("2020-07-01T12:00:00+08:00"), 51 CheckCode: wxpay_utility.String("69001808340631374774"), 52 Password: wxpay_utility.String("006>299-375/326>2+7/*0-+<351059<80<4*/5>+<11631+*3030/5*37+/-243159658+013>3409*044>4-/1+/9->*>69501*6++1997--21"), 53 TotalAmount: wxpay_utility.Int64(382895), 54 TaxAmount: wxpay_utility.Int64(44050), 55 Amount: wxpay_utility.Int64(338845), 56 SellerInformation: &SellerInfo{ 57 Name: wxpay_utility.String("深圳市南山区测试公司"), 58 TaxpayerId: wxpay_utility.String("202003261233701778"), 59 Address: wxpay_utility.String("深圳市南山区深南大道10000号"), 60 Telephone: wxpay_utility.String("075512345678"), 61 BankName: wxpay_utility.String("测试银行"), 62 BankAccount: wxpay_utility.String("62001234567890"), 63 }, 64 ExtraInformation: &ExtraInfo{ 65 Payee: wxpay_utility.String("张三"), 66 Reviewer: wxpay_utility.String("李四"), 67 Drawer: wxpay_utility.String("王五"), 68 }, 69 Items: []FapiaoItem{FapiaoItem{ 70 TaxCode: wxpay_utility.String("3010101020203000000"), 71 GoodsName: wxpay_utility.String("出租汽车客运服务"), 72 Specification: wxpay_utility.String("A4"), 73 Unit: wxpay_utility.String("次"), 74 Quantity: wxpay_utility.Int64(100000000), 75 UnitPrice: wxpay_utility.Int64(380442000000), 76 Amount: wxpay_utility.Int64(380442), 77 TaxAmount: wxpay_utility.Int64(49458), 78 TotalAmount: wxpay_utility.Int64(429900), 79 TaxRate: wxpay_utility.Int64(1300), 80 TaxPreferMark: TAXPREFERMARK_NO_FAVORABLE.Ptr(), 81 Discount: wxpay_utility.Bool(false), 82 }}, 83 Remark: wxpay_utility.String("备注"), 84 }}, 85 } 86 87 err = InsertCards(config, request) 88 if err != nil { 89 fmt.Printf("请求失败: %+v\n", err) 90 // TODO: 请求失败,根据状态码执行不同的处理 91 return 92 } 93 94 // TODO: 请求成功,继续业务逻辑 95 fmt.Println("请求成功") 96} 97 98func InsertCards(config *wxpay_utility.MchConfig, request *InsertCardsRequest) (err error) { 99 const ( 100 host = "https://api.mch.weixin.qq.com" 101 method = "POST" 102 path = "/v3/new-tax-control-fapiao/fapiao-applications/{fapiao_apply_id}/insert-cards" 103 ) 104 105 reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path)) 106 if err != nil { 107 return err 108 } 109 reqUrl.Path = strings.Replace(reqUrl.Path, "{fapiao_apply_id}", url.PathEscape(*request.FapiaoApplyId), -1) 110 reqBody, err := json.Marshal(request) 111 if err != nil { 112 return err 113 } 114 httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody)) 115 if err != nil { 116 return err 117 } 118 httpRequest.Header.Set("Accept", "application/json") 119 httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId()) 120 httpRequest.Header.Set("Content-Type", "application/json") 121 authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody) 122 if err != nil { 123 return err 124 } 125 httpRequest.Header.Set("Authorization", authorization) 126 127 client := &http.Client{} 128 httpResponse, err := client.Do(httpRequest) 129 if err != nil { 130 return err 131 } 132 respBody, err := wxpay_utility.ExtractResponseBody(httpResponse) 133 if err != nil { 134 return err 135 } 136 if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 { 137 // 2XX 成功,验证应答签名 138 err = wxpay_utility.ValidateResponse( 139 config.WechatPayPublicKeyId(), 140 config.WechatPayPublicKey(), 141 &httpResponse.Header, 142 respBody, 143 ) 144 if err != nil { 145 return err 146 } 147 return nil 148 } else { 149 return wxpay_utility.NewApiException( 150 httpResponse.StatusCode, 151 httpResponse.Header, 152 respBody, 153 ) 154 } 155} 156 157type InsertCardsRequest struct { 158 SubMchid *string `json:"sub_mchid,omitempty"` 159 Scene *Scene `json:"scene,omitempty"` 160 FapiaoApplyId *string `json:"fapiao_apply_id,omitempty"` 161 BuyerInformation *UserTitleEntity `json:"buyer_information,omitempty"` 162 FapiaoCardInformation []FapiaoCardInfo `json:"fapiao_card_information,omitempty"` 163} 164 165func (o *InsertCardsRequest) MarshalJSON() ([]byte, error) { 166 type Alias InsertCardsRequest 167 a := &struct { 168 FapiaoApplyId *string `json:"fapiao_apply_id,omitempty"` 169 *Alias 170 }{ 171 // 序列化时移除非 Body 字段 172 FapiaoApplyId: nil, 173 Alias: (*Alias)(o), 174 } 175 return json.Marshal(a) 176} 177 178type Scene string 179 180func (e Scene) Ptr() *Scene { 181 return &e 182} 183 184const ( 185 SCENE_WITH_WECHATPAY Scene = "WITH_WECHATPAY" 186 SCENE_WITHOUT_WECHATPAY Scene = "WITHOUT_WECHATPAY" 187) 188 189type UserTitleEntity struct { 190 Type *BuyerType `json:"type,omitempty"` 191 Name *string `json:"name,omitempty"` 192 TaxpayerId *string `json:"taxpayer_id,omitempty"` 193 Address *string `json:"address,omitempty"` 194 Telephone *string `json:"telephone,omitempty"` 195 BankName *string `json:"bank_name,omitempty"` 196 BankAccount *string `json:"bank_account,omitempty"` 197 Phone *string `json:"phone,omitempty"` 198 Email *string `json:"email,omitempty"` 199 Amount *int64 `json:"amount,omitempty"` 200 OutTradeNo *string `json:"out_trade_no,omitempty"` 201 FapiaoBillType *FapiaoBillType `json:"fapiao_bill_type,omitempty"` 202 UserApplyMessage *string `json:"user_apply_message,omitempty"` 203} 204 205type FapiaoCardInfo struct { 206 FapiaoMediaId *string `json:"fapiao_media_id,omitempty"` 207 FapiaoNumber *string `json:"fapiao_number,omitempty"` 208 FapiaoCode *string `json:"fapiao_code,omitempty"` 209 FapiaoTime *string `json:"fapiao_time,omitempty"` 210 CheckCode *string `json:"check_code,omitempty"` 211 Password *string `json:"password,omitempty"` 212 TotalAmount *int64 `json:"total_amount,omitempty"` 213 TaxAmount *int64 `json:"tax_amount,omitempty"` 214 Amount *int64 `json:"amount,omitempty"` 215 SellerInformation *SellerInfo `json:"seller_information,omitempty"` 216 ExtraInformation *ExtraInfo `json:"extra_information,omitempty"` 217 Items []FapiaoItem `json:"items,omitempty"` 218 Remark *string `json:"remark,omitempty"` 219} 220 221type BuyerType string 222 223func (e BuyerType) Ptr() *BuyerType { 224 return &e 225} 226 227const ( 228 BUYERTYPE_INDIVIDUAL BuyerType = "INDIVIDUAL" 229 BUYERTYPE_ORGANIZATION BuyerType = "ORGANIZATION" 230) 231 232type FapiaoBillType string 233 234func (e FapiaoBillType) Ptr() *FapiaoBillType { 235 return &e 236} 237 238const ( 239 FAPIAOBILLTYPE_COMM_FAPIAO FapiaoBillType = "COMM_FAPIAO" 240 FAPIAOBILLTYPE_VAT_FAPIAO FapiaoBillType = "VAT_FAPIAO" 241) 242 243type SellerInfo struct { 244 Name *string `json:"name,omitempty"` 245 TaxpayerId *string `json:"taxpayer_id,omitempty"` 246 Address *string `json:"address,omitempty"` 247 Telephone *string `json:"telephone,omitempty"` 248 BankName *string `json:"bank_name,omitempty"` 249 BankAccount *string `json:"bank_account,omitempty"` 250} 251 252type ExtraInfo struct { 253 Payee *string `json:"payee,omitempty"` 254 Reviewer *string `json:"reviewer,omitempty"` 255 Drawer *string `json:"drawer,omitempty"` 256} 257 258type FapiaoItem struct { 259 TaxCode *string `json:"tax_code,omitempty"` 260 GoodsName *string `json:"goods_name,omitempty"` 261 Specification *string `json:"specification,omitempty"` 262 Unit *string `json:"unit,omitempty"` 263 Quantity *int64 `json:"quantity,omitempty"` 264 UnitPrice *int64 `json:"unit_price,omitempty"` 265 Amount *int64 `json:"amount,omitempty"` 266 TaxAmount *int64 `json:"tax_amount,omitempty"` 267 TotalAmount *int64 `json:"total_amount,omitempty"` 268 TaxRate *int64 `json:"tax_rate,omitempty"` 269 TaxPreferMark *TaxPreferMark `json:"tax_prefer_mark,omitempty"` 270 Discount *bool `json:"discount,omitempty"` 271} 272 273type TaxPreferMark string 274 275func (e TaxPreferMark) Ptr() *TaxPreferMark { 276 return &e 277} 278 279const ( 280 TAXPREFERMARK_NO_FAVORABLE TaxPreferMark = "NO_FAVORABLE" 281 TAXPREFERMARK_OUTSIDE_VAT TaxPreferMark = "OUTSIDE_VAT" 282 TAXPREFERMARK_VAT_EXEMPT TaxPreferMark = "VAT_EXEMPT" 283 TAXPREFERMARK_NORMAL_ZERO_RATED TaxPreferMark = "NORMAL_ZERO_RATED" 284 TAXPREFERMARK_EXPORT_ZERO_RATED TaxPreferMark = "EXPORT_ZERO_RATED" 285) 286
应答参数
无应答包体
应答示例
202 Accepted
1'无应答包体' 2
错误码
公共错误码
状态码 | 错误码 | 描述 | 解决方案 |
---|---|---|---|
400 | PARAM_ERROR | 参数错误 | 请根据错误提示正确传入参数 |
400 | INVALID_REQUEST | HTTP 请求不符合微信支付 APIv3 接口规则 | 请参阅 接口规则 |
401 | SIGN_ERROR | 验证不通过 | 请参阅 签名常见问题 |
500 | SYSTEM_ERROR | 系统异常,请稍后重试 | 请稍后重试 |
业务错误码
状态码 | 错误码 | 描述 | 解决方案 |
---|---|---|---|
400 | INVALID_REQUEST | 请求参数符合参数格式,但不符合业务规则 | 请使用正确的参数重新调用 |
400 | RESOURCE_ALREADY_EXISTS | 发票申请单已存在 | 请稍后调用【查询电子发票】接口获取开票结果 |
403 | NO_AUTH | 商户无权限 | 请检查是否已经开通电子发票产品相关功能权限,并检查子商户是否接受了服务商的邀请 |
403 | RULE_LIMIT | 商户尚未配置电子发票卡券模板信息 | 请先调用【创建电子发票卡券模板】接口成功后再重新调用 |
403 | RULE_LIMIT | 商户提交的购买方信息与用户填写的发票抬头不一致 | 请检查参数中的购买方信息与【获取用户填写抬头信息】接口返回的发票抬头信息是否一致 |
403 | RULE_LIMIT | 微信支付订单所属商户与当前商户不一致(仅微信支付场景) | 请检查微信支付订单号是否属于商户 |
404 | RESOURCE_NOT_EXISTS | 用户尚未完成发票抬头填写 | 请在调用【获取用户填写抬头信息】接口成功后再以相同发票申请单号重新调用 |
429 | FREQUENCY_LIMITED | 频率超限 | 请降低请求接口频率 |