将电子发票插入微信用户卡包
更新时间: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 "drawer" : "*五 0010" 46 }, 47 "items" : [ 48 { 49 "tax_code" : "3010101020203000000", 50 "goods_name" : "出租汽车客运服务", 51 "specification" : "A4", 52 "unit" : "次", 53 "quantity" : 100000000, 54 "unit_price" : 380442000000, 55 "amount" : 380442, 56 "tax_amount" : 49458, 57 "total_amount" : 429900, 58 "tax_rate" : 1300, 59 "tax_prefer_mark" : "NO_FAVORABLE", 60 "discount" : false 61 } 62 ], 63 "remark" : "备注" 64 } 65 ] 66 }' 67
需配合微信支付工具库 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.drawer = "*五 0010"; 79 fapiaoCardInformationItem.items = new ArrayList<>(); 80 { 81 FapiaoItem itemsItem = new FapiaoItem(); 82 itemsItem.taxCode = "3010101020203000000"; 83 itemsItem.goodsName = "出租汽车客运服务"; 84 itemsItem.specification = "A4"; 85 itemsItem.unit = "次"; 86 itemsItem.quantity = 100000000L; 87 itemsItem.unitPrice = 380442000000L; 88 itemsItem.amount = 380442L; 89 itemsItem.taxAmount = 49458L; 90 itemsItem.totalAmount = 429900L; 91 itemsItem.taxRate = 1300L; 92 itemsItem.taxPreferMark = TaxPreferMark.NO_FAVORABLE; 93 itemsItem.discount = false; 94 fapiaoCardInformationItem.items.add(itemsItem); 95 }; 96 fapiaoCardInformationItem.remark = "备注"; 97 request.fapiaoCardInformation.add(fapiaoCardInformationItem); 98 }; 99 try { 100 client.run(request); 101 } catch (WXPayUtility.ApiException e) { 102 // TODO: 请求失败,根据状态码执行不同的逻辑 103 e.printStackTrace(); 104 } 105 } 106 107 public void run(InsertCardsRequest request) { 108 String uri = PATH; 109 uri = uri.replace("{fapiao_apply_id}", WXPayUtility.urlEncode(request.fapiaoApplyId)); 110 String reqBody = WXPayUtility.toJson(request); 111 112 Request.Builder reqBuilder = new Request.Builder().url(HOST + uri); 113 reqBuilder.addHeader("Accept", "application/json"); 114 reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId); 115 reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody)); 116 reqBuilder.addHeader("Content-Type", "application/json"); 117 RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody); 118 reqBuilder.method(METHOD, requestBody); 119 Request httpRequest = reqBuilder.build(); 120 121 // 发送HTTP请求 122 OkHttpClient client = new OkHttpClient.Builder().build(); 123 try (Response httpResponse = client.newCall(httpRequest).execute()) { 124 String respBody = WXPayUtility.extractBody(httpResponse); 125 if (httpResponse.code() >= 200 && httpResponse.code() < 300) { 126 // 2XX 成功,验证应答签名 127 WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey, 128 httpResponse.headers(), respBody); 129 130 return; 131 } else { 132 throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers()); 133 } 134 } catch (IOException e) { 135 throw new UncheckedIOException("Sending request to " + uri + " failed.", e); 136 } 137 } 138 139 private final String mchid; 140 private final String certificateSerialNo; 141 private final PrivateKey privateKey; 142 private final String wechatPayPublicKeyId; 143 private final PublicKey wechatPayPublicKey; 144 145 public InsertCards(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) { 146 this.mchid = mchid; 147 this.certificateSerialNo = certificateSerialNo; 148 this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath); 149 this.wechatPayPublicKeyId = wechatPayPublicKeyId; 150 this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath); 151 } 152 153 public String encrypt(String plainText) { 154 return WXPayUtility.encrypt(this.wechatPayPublicKey, plainText); 155 } 156 157 public static class InsertCardsRequest { 158 @SerializedName("sub_mchid") 159 public String subMchid; 160 161 @SerializedName("scene") 162 public Scene scene; 163 164 @SerializedName("fapiao_apply_id") 165 @Expose(serialize = false) 166 public String fapiaoApplyId; 167 168 @SerializedName("buyer_information") 169 public UserTitleEntity buyerInformation; 170 171 @SerializedName("fapiao_card_information") 172 public List<FapiaoCardInfo> fapiaoCardInformation = new ArrayList<FapiaoCardInfo>(); 173 } 174 175 public enum Scene { 176 @SerializedName("WITH_WECHATPAY") 177 WITH_WECHATPAY, 178 @SerializedName("WITHOUT_WECHATPAY") 179 WITHOUT_WECHATPAY 180 } 181 182 public static class UserTitleEntity { 183 @SerializedName("type") 184 public BuyerType type; 185 186 @SerializedName("name") 187 public String name; 188 189 @SerializedName("taxpayer_id") 190 public String taxpayerId; 191 192 @SerializedName("address") 193 public String address; 194 195 @SerializedName("telephone") 196 public String telephone; 197 198 @SerializedName("bank_name") 199 public String bankName; 200 201 @SerializedName("bank_account") 202 public String bankAccount; 203 204 @SerializedName("phone") 205 public String phone; 206 207 @SerializedName("email") 208 public String email; 209 210 @SerializedName("amount") 211 public Long amount; 212 213 @SerializedName("out_trade_no") 214 public String outTradeNo; 215 216 @SerializedName("fapiao_bill_type") 217 public FapiaoBillType fapiaoBillType; 218 219 @SerializedName("user_apply_message") 220 public String userApplyMessage; 221 } 222 223 public static class FapiaoCardInfo { 224 @SerializedName("fapiao_media_id") 225 public String fapiaoMediaId; 226 227 @SerializedName("fapiao_number") 228 public String fapiaoNumber; 229 230 @SerializedName("fapiao_code") 231 public String fapiaoCode; 232 233 @SerializedName("fapiao_time") 234 public String fapiaoTime; 235 236 @SerializedName("check_code") 237 public String checkCode; 238 239 @SerializedName("password") 240 public String password; 241 242 @SerializedName("total_amount") 243 public Long totalAmount; 244 245 @SerializedName("tax_amount") 246 public Long taxAmount; 247 248 @SerializedName("amount") 249 public Long amount; 250 251 @SerializedName("seller_information") 252 public SellerInfo sellerInformation; 253 254 @SerializedName("extra_information") 255 public ExtraInfo extraInformation; 256 257 @SerializedName("items") 258 public List<FapiaoItem> items; 259 260 @SerializedName("remark") 261 public String remark; 262 } 263 264 public enum BuyerType { 265 @SerializedName("INDIVIDUAL") 266 INDIVIDUAL, 267 @SerializedName("ORGANIZATION") 268 ORGANIZATION 269 } 270 271 public enum FapiaoBillType { 272 @SerializedName("COMM_FAPIAO") 273 COMM_FAPIAO, 274 @SerializedName("VAT_FAPIAO") 275 VAT_FAPIAO 276 } 277 278 public static class SellerInfo { 279 @SerializedName("name") 280 public String name; 281 282 @SerializedName("taxpayer_id") 283 public String taxpayerId; 284 285 @SerializedName("address") 286 public String address; 287 288 @SerializedName("telephone") 289 public String telephone; 290 291 @SerializedName("bank_name") 292 public String bankName; 293 294 @SerializedName("bank_account") 295 public String bankAccount; 296 } 297 298 public static class ExtraInfo { 299 @SerializedName("drawer") 300 public String drawer; 301 } 302 303 public static class FapiaoItem { 304 @SerializedName("tax_code") 305 public String taxCode; 306 307 @SerializedName("goods_name") 308 public String goodsName; 309 310 @SerializedName("specification") 311 public String specification; 312 313 @SerializedName("unit") 314 public String unit; 315 316 @SerializedName("quantity") 317 public Long quantity; 318 319 @SerializedName("unit_price") 320 public Long unitPrice; 321 322 @SerializedName("amount") 323 public Long amount; 324 325 @SerializedName("tax_amount") 326 public Long taxAmount; 327 328 @SerializedName("total_amount") 329 public Long totalAmount; 330 331 @SerializedName("tax_rate") 332 public Long taxRate; 333 334 @SerializedName("tax_prefer_mark") 335 public TaxPreferMark taxPreferMark; 336 337 @SerializedName("discount") 338 public Boolean discount; 339 } 340 341 public enum TaxPreferMark { 342 @SerializedName("NO_FAVORABLE") 343 NO_FAVORABLE, 344 @SerializedName("OUTSIDE_VAT") 345 OUTSIDE_VAT, 346 @SerializedName("VAT_EXEMPT") 347 VAT_EXEMPT, 348 @SerializedName("NORMAL_ZERO_RATED") 349 NORMAL_ZERO_RATED, 350 @SerializedName("EXPORT_ZERO_RATED") 351 EXPORT_ZERO_RATED 352 } 353 354} 355
需配合微信支付工具库 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 Drawer: wxpay_utility.String("*五 0010"), 66 }, 67 Items: []FapiaoItem{FapiaoItem{ 68 TaxCode: wxpay_utility.String("3010101020203000000"), 69 GoodsName: wxpay_utility.String("出租汽车客运服务"), 70 Specification: wxpay_utility.String("A4"), 71 Unit: wxpay_utility.String("次"), 72 Quantity: wxpay_utility.Int64(100000000), 73 UnitPrice: wxpay_utility.Int64(380442000000), 74 Amount: wxpay_utility.Int64(380442), 75 TaxAmount: wxpay_utility.Int64(49458), 76 TotalAmount: wxpay_utility.Int64(429900), 77 TaxRate: wxpay_utility.Int64(1300), 78 TaxPreferMark: TAXPREFERMARK_NO_FAVORABLE.Ptr(), 79 Discount: wxpay_utility.Bool(false), 80 }}, 81 Remark: wxpay_utility.String("备注"), 82 }}, 83 } 84 85 err = InsertCards(config, request) 86 if err != nil { 87 fmt.Printf("请求失败: %+v\n", err) 88 // TODO: 请求失败,根据状态码执行不同的处理 89 return 90 } 91 92 // TODO: 请求成功,继续业务逻辑 93 fmt.Println("请求成功") 94} 95 96func InsertCards(config *wxpay_utility.MchConfig, request *InsertCardsRequest) (err error) { 97 const ( 98 host = "https://api.mch.weixin.qq.com" 99 method = "POST" 100 path = "/v3/new-tax-control-fapiao/fapiao-applications/{fapiao_apply_id}/insert-cards" 101 ) 102 103 reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path)) 104 if err != nil { 105 return err 106 } 107 reqUrl.Path = strings.Replace(reqUrl.Path, "{fapiao_apply_id}", url.PathEscape(*request.FapiaoApplyId), -1) 108 reqBody, err := json.Marshal(request) 109 if err != nil { 110 return err 111 } 112 httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody)) 113 if err != nil { 114 return err 115 } 116 httpRequest.Header.Set("Accept", "application/json") 117 httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId()) 118 httpRequest.Header.Set("Content-Type", "application/json") 119 authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody) 120 if err != nil { 121 return err 122 } 123 httpRequest.Header.Set("Authorization", authorization) 124 125 client := &http.Client{} 126 httpResponse, err := client.Do(httpRequest) 127 if err != nil { 128 return err 129 } 130 respBody, err := wxpay_utility.ExtractResponseBody(httpResponse) 131 if err != nil { 132 return err 133 } 134 if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 { 135 // 2XX 成功,验证应答签名 136 err = wxpay_utility.ValidateResponse( 137 config.WechatPayPublicKeyId(), 138 config.WechatPayPublicKey(), 139 &httpResponse.Header, 140 respBody, 141 ) 142 if err != nil { 143 return err 144 } 145 return nil 146 } else { 147 return wxpay_utility.NewApiException( 148 httpResponse.StatusCode, 149 httpResponse.Header, 150 respBody, 151 ) 152 } 153} 154 155type InsertCardsRequest struct { 156 SubMchid *string `json:"sub_mchid,omitempty"` 157 Scene *Scene `json:"scene,omitempty"` 158 FapiaoApplyId *string `json:"fapiao_apply_id,omitempty"` 159 BuyerInformation *UserTitleEntity `json:"buyer_information,omitempty"` 160 FapiaoCardInformation []FapiaoCardInfo `json:"fapiao_card_information,omitempty"` 161} 162 163func (o *InsertCardsRequest) MarshalJSON() ([]byte, error) { 164 type Alias InsertCardsRequest 165 a := &struct { 166 FapiaoApplyId *string `json:"fapiao_apply_id,omitempty"` 167 *Alias 168 }{ 169 // 序列化时移除非 Body 字段 170 FapiaoApplyId: nil, 171 Alias: (*Alias)(o), 172 } 173 return json.Marshal(a) 174} 175 176type Scene string 177 178func (e Scene) Ptr() *Scene { 179 return &e 180} 181 182const ( 183 SCENE_WITH_WECHATPAY Scene = "WITH_WECHATPAY" 184 SCENE_WITHOUT_WECHATPAY Scene = "WITHOUT_WECHATPAY" 185) 186 187type UserTitleEntity struct { 188 Type *BuyerType `json:"type,omitempty"` 189 Name *string `json:"name,omitempty"` 190 TaxpayerId *string `json:"taxpayer_id,omitempty"` 191 Address *string `json:"address,omitempty"` 192 Telephone *string `json:"telephone,omitempty"` 193 BankName *string `json:"bank_name,omitempty"` 194 BankAccount *string `json:"bank_account,omitempty"` 195 Phone *string `json:"phone,omitempty"` 196 Email *string `json:"email,omitempty"` 197 Amount *int64 `json:"amount,omitempty"` 198 OutTradeNo *string `json:"out_trade_no,omitempty"` 199 FapiaoBillType *FapiaoBillType `json:"fapiao_bill_type,omitempty"` 200 UserApplyMessage *string `json:"user_apply_message,omitempty"` 201} 202 203type FapiaoCardInfo struct { 204 FapiaoMediaId *string `json:"fapiao_media_id,omitempty"` 205 FapiaoNumber *string `json:"fapiao_number,omitempty"` 206 FapiaoCode *string `json:"fapiao_code,omitempty"` 207 FapiaoTime *string `json:"fapiao_time,omitempty"` 208 CheckCode *string `json:"check_code,omitempty"` 209 Password *string `json:"password,omitempty"` 210 TotalAmount *int64 `json:"total_amount,omitempty"` 211 TaxAmount *int64 `json:"tax_amount,omitempty"` 212 Amount *int64 `json:"amount,omitempty"` 213 SellerInformation *SellerInfo `json:"seller_information,omitempty"` 214 ExtraInformation *ExtraInfo `json:"extra_information,omitempty"` 215 Items []FapiaoItem `json:"items,omitempty"` 216 Remark *string `json:"remark,omitempty"` 217} 218 219type BuyerType string 220 221func (e BuyerType) Ptr() *BuyerType { 222 return &e 223} 224 225const ( 226 BUYERTYPE_INDIVIDUAL BuyerType = "INDIVIDUAL" 227 BUYERTYPE_ORGANIZATION BuyerType = "ORGANIZATION" 228) 229 230type FapiaoBillType string 231 232func (e FapiaoBillType) Ptr() *FapiaoBillType { 233 return &e 234} 235 236const ( 237 FAPIAOBILLTYPE_COMM_FAPIAO FapiaoBillType = "COMM_FAPIAO" 238 FAPIAOBILLTYPE_VAT_FAPIAO FapiaoBillType = "VAT_FAPIAO" 239) 240 241type SellerInfo struct { 242 Name *string `json:"name,omitempty"` 243 TaxpayerId *string `json:"taxpayer_id,omitempty"` 244 Address *string `json:"address,omitempty"` 245 Telephone *string `json:"telephone,omitempty"` 246 BankName *string `json:"bank_name,omitempty"` 247 BankAccount *string `json:"bank_account,omitempty"` 248} 249 250type ExtraInfo struct { 251 Drawer *string `json:"drawer,omitempty"` 252} 253 254type FapiaoItem struct { 255 TaxCode *string `json:"tax_code,omitempty"` 256 GoodsName *string `json:"goods_name,omitempty"` 257 Specification *string `json:"specification,omitempty"` 258 Unit *string `json:"unit,omitempty"` 259 Quantity *int64 `json:"quantity,omitempty"` 260 UnitPrice *int64 `json:"unit_price,omitempty"` 261 Amount *int64 `json:"amount,omitempty"` 262 TaxAmount *int64 `json:"tax_amount,omitempty"` 263 TotalAmount *int64 `json:"total_amount,omitempty"` 264 TaxRate *int64 `json:"tax_rate,omitempty"` 265 TaxPreferMark *TaxPreferMark `json:"tax_prefer_mark,omitempty"` 266 Discount *bool `json:"discount,omitempty"` 267} 268 269type TaxPreferMark string 270 271func (e TaxPreferMark) Ptr() *TaxPreferMark { 272 return &e 273} 274 275const ( 276 TAXPREFERMARK_NO_FAVORABLE TaxPreferMark = "NO_FAVORABLE" 277 TAXPREFERMARK_OUTSIDE_VAT TaxPreferMark = "OUTSIDE_VAT" 278 TAXPREFERMARK_VAT_EXEMPT TaxPreferMark = "VAT_EXEMPT" 279 TAXPREFERMARK_NORMAL_ZERO_RATED TaxPreferMark = "NORMAL_ZERO_RATED" 280 TAXPREFERMARK_EXPORT_ZERO_RATED TaxPreferMark = "EXPORT_ZERO_RATED" 281) 282
应答参数
无应答包体
应答示例
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 | 频率超限 | 请降低请求接口频率 |
