获取邀请商户开通服务商电子发票能力
更新时间:2025.09.03服务商通过填写发票模式,发票开通能力等信息,获取邀请商户开通服务商电子发票能力的链接,展示给商户,进行授权开通服务商电子发票能力。
接口说明
支持商户:【普通服务商】
请求方式:【GET】/v3/new-tax-control-fapiao/fapiaomerchant/getspinviteurl
请求域名:【主域名】https://api.mch.weixin.qq.com 使用该域名将访问就近的接入点
【备域名】https://api2.mch.weixin.qq.com 使用该域名将访问异地的接入点 ,指引点击查看
请求参数
Header HTTP头参数
Authorization 必填 string
请参考签名认证生成认证信息
Accept 必填 string
请设置为application/json
Wechatpay-Serial 必填 string
【微信支付公钥ID】或【微信支付平台证书序列号】 请求参数中的敏感字段,需要使用微信支付公钥加密(推荐),请参考获取微信支付公钥ID说明以及微信支付公钥加密敏感信息指引;也可以使用微信支付平台证书公钥加密,参考获取平台证书序列号、平台证书加密敏感信息指引
query 查询参数
operation_type 必填 string
【操作类型】 商户接受请求后的操作类型
可选取值
AUTH_BINDING
: 授权绑定
fapiao_mode 必填 array[string]
【开票模式】 邀请商户开通服务商电子发票的可选开票模式
可选取值
THIRD_OR_SELF_FAPIAO
: 第三方/自建发票,即使用自有或其他第三方发票系统生成发票TENCENT_DIGITAL_TAX
: 腾讯数电发票,即使用腾讯数电发票系统生成发票
fapiao_ability_type_list 选填 array[string]
【发票能力类型】 邀请商户开通的腾讯数电发票能力类型,可以选择多个。当开票模式为TENCENT_DIGITAL_TAX时必填
可选取值
BASE_ABILITY
: 基础开票能力(适合餐饮、酒店等)REAL_ESTATE_ABILITY
: 不动产租赁能力(适合停车场等)
invite_channel 选填 string
【服务商邀请渠道】 服务商自定义的渠道信息,用于标识该邀请从哪个渠道发起
operate_user 选填 string
【操作人员】 服务商邀请操作人员信息,用于标识该邀请是哪个人员发起。
注意:该字段为密文字段,需要使用微信支付公钥加密(推荐),参考获取微信支付公钥ID说明以及微信支付公钥加密敏感信息指引;也可以使用微信支付平台证书公钥加密,参考获取平台证书序列号、平台证书加密敏感信息指引
invite_code 必填 string(128)
【服务商邀请code】 服务商邀请的唯一标识,由服务商生成,可根据邀请code查询邀请开通情况
sub_mchid 选填 string
【受邀请商户号】 受服务商邀请开通电子发票能力的商户号
请求示例
GET
1curl -X GET \ 2 https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/fapiaomerchant/getspinviteurl?operation_type=AUTH_BINDING&fapiao_mode=TENCENT_DIGITAL_TAX&fapiao_ability_type_list=BASE_ABILITY&invite_channel=miniprogram&operate_user=mI7HGEJ4Q2B91IGjHZu/Gthm87Szv0MK2AoC0/3ZMDgltMtdoY6O0qZ4F1iXiwCuqkkBe+9M4ggvdzRVVVB9s+zLEQ8nv74vsgl77MZx14nd5obtCcfAvPfDJob3oG7FqlThmYKJqjiOwBvvQse7p9R8onj/POzSrbM8re8ZYGp4LcehXopTLdk2ZVWRv8bnJgKZeY4vpMmq4xuRTYk6xNXvowBBKLu4oaNFNdBO3fip1a1rFW0vRw==&invite_code=code_20200101_123&sub_mchid=19998278783 \ 3 -H "Authorization: WECHATPAY2-SHA256-RSA2048 mchid=\"1900000001\",..." \ 4 -H "Accept: application/json" \ 5 -H "Wechatpay-Serial: 5157F09EFDC096DE15EBE81A47057A7232F1B8E1" 6
需配合微信支付工具库 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 GetSpInviteUrl { 26 private static String HOST = "https://api.mch.weixin.qq.com"; 27 private static String METHOD = "GET"; 28 private static String PATH = "/v3/new-tax-control-fapiao/fapiaomerchant/getspinviteurl"; 29 30 public static void main(String[] args) { 31 // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/v3/partner/4013080340 32 GetSpInviteUrl client = new GetSpInviteUrl( 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 GetSpInviteUrlRequest request = new GetSpInviteUrlRequest(); 41 request.operationType = InviteOperationType.AUTH_BINDING; 42 request.fapiaoMode = new ArrayList<>(); 43{ 44 request.fapiaoMode.add(InvoiceMode.THIRD_OR_SELF_FAPIAO); 45}; 46 request.fapiaoAbilityTypeList = new ArrayList<>(); 47{ 48 request.fapiaoAbilityTypeList.add(FapiaoAbilityType.BASE_ABILITY); 49}; 50 request.inviteChannel = "miniprogram"; 51 request.operateUser = "mI7HGEJ4Q2B91IGjHZu/Gthm87Szv0MK2AoC0/3ZMDgltMtdoY6O0qZ4F1iXiwCuqkkBe+9M4ggvdzRVVVB9s+zLEQ8nv74vsgl77MZx14nd5obtCcfAvPfDJob3oG7FqlThmYKJqjiOwBvvQse7p9R8onj/POzSrbM8re8ZYGp4LcehXopTLdk2ZVWRv8bnJgKZeY4vpMmq4xuRTYk6xNXvowBBKLu4oaNFNdBO3fip1a1rFW0vRw=="; 52 request.inviteCode = "code_20200101_123"; 53 request.subMchid = "19998278783"; 54 try { 55 GetSpInviteUrlResp response = client.run(request); 56 // TODO: 请求成功,继续业务逻辑 57 System.out.println(response); 58 } catch (WXPayUtility.ApiException e) { 59 // TODO: 请求失败,根据状态码执行不同的逻辑 60 e.printStackTrace(); 61 } 62 } 63 64 public GetSpInviteUrlResp run(GetSpInviteUrlRequest request) { 65 String uri = PATH; 66 Map<String, Object> args = new HashMap<>(); 67 args.put("operation_type", request.operationType); 68 args.put("fapiao_mode", request.fapiaoMode); 69 args.put("fapiao_ability_type_list", request.fapiaoAbilityTypeList); 70 args.put("invite_channel", request.inviteChannel); 71 args.put("operate_user", request.operateUser); 72 args.put("invite_code", request.inviteCode); 73 args.put("sub_mchid", request.subMchid); 74 String queryString = WXPayUtility.urlEncode(args); 75 if (!queryString.isEmpty()) { 76 uri = uri + "?" + queryString; 77 } 78 79 Request.Builder reqBuilder = new Request.Builder().url(HOST + uri); 80 reqBuilder.addHeader("Accept", "application/json"); 81 reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId); 82 reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, null)); 83 reqBuilder.method(METHOD, null); 84 Request httpRequest = reqBuilder.build(); 85 86 // 发送HTTP请求 87 OkHttpClient client = new OkHttpClient.Builder().build(); 88 try (Response httpResponse = client.newCall(httpRequest).execute()) { 89 String respBody = WXPayUtility.extractBody(httpResponse); 90 if (httpResponse.code() >= 200 && httpResponse.code() < 300) { 91 // 2XX 成功,验证应答签名 92 WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey, 93 httpResponse.headers(), respBody); 94 95 // 从HTTP应答报文构建返回数据 96 return WXPayUtility.fromJson(respBody, GetSpInviteUrlResp.class); 97 } else { 98 throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers()); 99 } 100 } catch (IOException e) { 101 throw new UncheckedIOException("Sending request to " + uri + " failed.", e); 102 } 103 } 104 105 private final String mchid; 106 private final String certificateSerialNo; 107 private final PrivateKey privateKey; 108 private final String wechatPayPublicKeyId; 109 private final PublicKey wechatPayPublicKey; 110 111 public GetSpInviteUrl(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) { 112 this.mchid = mchid; 113 this.certificateSerialNo = certificateSerialNo; 114 this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath); 115 this.wechatPayPublicKeyId = wechatPayPublicKeyId; 116 this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath); 117 } 118 119 public String encrypt(String plainText) { 120 return WXPayUtility.encrypt(this.wechatPayPublicKey, plainText); 121 } 122 123 public static class GetSpInviteUrlRequest { 124 @SerializedName("fapiao_mode") 125 @Expose(serialize = false) 126 public List<InvoiceMode> fapiaoMode = new ArrayList<InvoiceMode>(); 127 128 @SerializedName("fapiao_ability_type_list") 129 @Expose(serialize = false) 130 public List<FapiaoAbilityType> fapiaoAbilityTypeList; 131 132 @SerializedName("invite_channel") 133 @Expose(serialize = false) 134 public String inviteChannel; 135 136 @SerializedName("operate_user") 137 @Expose(serialize = false) 138 public String operateUser; 139 140 @SerializedName("invite_code") 141 @Expose(serialize = false) 142 public String inviteCode; 143 144 @SerializedName("sub_mchid") 145 @Expose(serialize = false) 146 public String subMchid; 147 148 @SerializedName("operation_type") 149 @Expose(serialize = false) 150 public InviteOperationType operationType; 151 } 152 153 public static class GetSpInviteUrlResp { 154 @SerializedName("invite_url") 155 public String inviteUrl; 156 157 @SerializedName("miniprogram_appid") 158 public String miniprogramAppid; 159 160 @SerializedName("miniprogram_path") 161 public String miniprogramPath; 162 } 163 164 public enum InvoiceMode { 165 @SerializedName("THIRD_OR_SELF_FAPIAO") 166 THIRD_OR_SELF_FAPIAO, 167 @SerializedName("TENCENT_DIGITAL_TAX") 168 TENCENT_DIGITAL_TAX 169 } 170 171 public enum FapiaoAbilityType { 172 @SerializedName("BASE_ABILITY") 173 BASE_ABILITY, 174 @SerializedName("REAL_ESTATE_ABILITY") 175 REAL_ESTATE_ABILITY 176 } 177 178 public enum InviteOperationType { 179 @SerializedName("AUTH_BINDING") 180 AUTH_BINDING 181 } 182 183} 184
需配合微信支付工具库 wxpay_utility 使用,请参考 Go
1package main 2 3import ( 4 "demo/wxpay_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/v3/partner/4015119446 5 "encoding/json" 6 "fmt" 7 "net/http" 8 "net/url" 9) 10 11func main() { 12 // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/v3/partner/4013080340 13 config, err := wxpay_utility.CreateMchConfig( 14 "19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/partner/4013080340 15 "1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号,如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924 16 "/path/to/apiclient_key.pem", // 商户API证书私钥文件路径,本地文件路径 17 "PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID,如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589 18 "/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径 19 ) 20 if err != nil { 21 fmt.Println(err) 22 return 23 } 24 25 request := &GetSpInviteUrlRequest{ 26 OperationType: INVITEOPERATIONTYPE_AUTH_BINDING.Ptr(), 27 FapiaoMode: []InvoiceMode{INVOICEMODE_THIRD_OR_SELF_FAPIAO}, 28 FapiaoAbilityTypeList: []FapiaoAbilityType{FAPIAOABILITYTYPE_BASE_ABILITY}, 29 InviteChannel: wxpay_utility.String("miniprogram"), 30 OperateUser: wxpay_utility.String("mI7HGEJ4Q2B91IGjHZu/Gthm87Szv0MK2AoC0/3ZMDgltMtdoY6O0qZ4F1iXiwCuqkkBe+9M4ggvdzRVVVB9s+zLEQ8nv74vsgl77MZx14nd5obtCcfAvPfDJob3oG7FqlThmYKJqjiOwBvvQse7p9R8onj/POzSrbM8re8ZYGp4LcehXopTLdk2ZVWRv8bnJgKZeY4vpMmq4xuRTYk6xNXvowBBKLu4oaNFNdBO3fip1a1rFW0vRw=="), 31 InviteCode: wxpay_utility.String("code_20200101_123"), 32 SubMchid: wxpay_utility.String("19998278783"), 33 } 34 35 response, err := GetSpInviteUrl(config, request) 36 if err != nil { 37 fmt.Printf("请求失败: %+v\n", err) 38 // TODO: 请求失败,根据状态码执行不同的处理 39 return 40 } 41 42 // TODO: 请求成功,继续业务逻辑 43 fmt.Printf("请求成功: %+v\n", response) 44} 45 46func GetSpInviteUrl(config *wxpay_utility.MchConfig, request *GetSpInviteUrlRequest) (response *GetSpInviteUrlResp, err error) { 47 const ( 48 host = "https://api.mch.weixin.qq.com" 49 method = "GET" 50 path = "/v3/new-tax-control-fapiao/fapiaomerchant/getspinviteurl" 51 ) 52 53 reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path)) 54 if err != nil { 55 return nil, err 56 } 57 query := reqUrl.Query() 58 if request.OperationType != nil { 59 query.Add("operation_type", fmt.Sprintf("%v", *request.OperationType)) 60 } 61 if request.FapiaoMode != nil { 62 query.Add("fapiao_mode", fmt.Sprintf("%v", *request.FapiaoMode)) 63 } 64 if request.FapiaoAbilityTypeList != nil { 65 query.Add("fapiao_ability_type_list", fmt.Sprintf("%v", *request.FapiaoAbilityTypeList)) 66 } 67 if request.InviteChannel != nil { 68 query.Add("invite_channel", *request.InviteChannel) 69 } 70 if request.OperateUser != nil { 71 query.Add("operate_user", *request.OperateUser) 72 } 73 if request.InviteCode != nil { 74 query.Add("invite_code", *request.InviteCode) 75 } 76 if request.SubMchid != nil { 77 query.Add("sub_mchid", *request.SubMchid) 78 } 79 reqUrl.RawQuery = query.Encode() 80 httpRequest, err := http.NewRequest(method, reqUrl.String(), nil) 81 if err != nil { 82 return nil, err 83 } 84 httpRequest.Header.Set("Accept", "application/json") 85 httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId()) 86 authorization, err := wxpay_utility.BuildAuthorization(config.MchId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), nil) 87 if err != nil { 88 return nil, err 89 } 90 httpRequest.Header.Set("Authorization", authorization) 91 92 client := &http.Client{} 93 httpResponse, err := client.Do(httpRequest) 94 if err != nil { 95 return nil, err 96 } 97 respBody, err := wxpay_utility.ExtractResponseBody(httpResponse) 98 if err != nil { 99 return nil, err 100 } 101 if httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300 { 102 // 2XX 成功,验证应答签名 103 err = wxpay_utility.ValidateResponse( 104 config.WechatPayPublicKeyId(), 105 config.WechatPayPublicKey(), 106 &httpResponse.Header, 107 respBody, 108 ) 109 if err != nil { 110 return nil, err 111 } 112 response := &GetSpInviteUrlResp{} 113 if err := json.Unmarshal(respBody, response); err != nil { 114 return nil, err 115 } 116 117 return response, nil 118 } else { 119 return nil, wxpay_utility.NewApiException( 120 httpResponse.StatusCode, 121 httpResponse.Header, 122 respBody, 123 ) 124 } 125} 126 127type GetSpInviteUrlRequest struct { 128 FapiaoMode []InvoiceMode `json:"fapiao_mode,omitempty"` 129 FapiaoAbilityTypeList []FapiaoAbilityType `json:"fapiao_ability_type_list,omitempty"` 130 InviteChannel *string `json:"invite_channel,omitempty"` 131 OperateUser *string `json:"operate_user,omitempty"` 132 InviteCode *string `json:"invite_code,omitempty"` 133 SubMchid *string `json:"sub_mchid,omitempty"` 134 OperationType *InviteOperationType `json:"operation_type,omitempty"` 135} 136 137func (o *GetSpInviteUrlRequest) MarshalJSON() ([]byte, error) { 138 type Alias GetSpInviteUrlRequest 139 a := &struct { 140 FapiaoMode []InvoiceMode `json:"fapiao_mode,omitempty"` 141 FapiaoAbilityTypeList []FapiaoAbilityType `json:"fapiao_ability_type_list,omitempty"` 142 InviteChannel *string `json:"invite_channel,omitempty"` 143 OperateUser *string `json:"operate_user,omitempty"` 144 InviteCode *string `json:"invite_code,omitempty"` 145 SubMchid *string `json:"sub_mchid,omitempty"` 146 OperationType *InviteOperationType `json:"operation_type,omitempty"` 147 *Alias 148 }{ 149 // 序列化时移除非 Body 字段 150 FapiaoMode: nil, 151 FapiaoAbilityTypeList: nil, 152 InviteChannel: nil, 153 OperateUser: nil, 154 InviteCode: nil, 155 SubMchid: nil, 156 OperationType: nil, 157 Alias: (*Alias)(o), 158 } 159 return json.Marshal(a) 160} 161 162type GetSpInviteUrlResp struct { 163 InviteUrl *string `json:"invite_url,omitempty"` 164 MiniprogramAppid *string `json:"miniprogram_appid,omitempty"` 165 MiniprogramPath *string `json:"miniprogram_path,omitempty"` 166} 167 168type InvoiceMode string 169 170func (e InvoiceMode) Ptr() *InvoiceMode { 171 return &e 172} 173 174const ( 175 INVOICEMODE_THIRD_OR_SELF_FAPIAO InvoiceMode = "THIRD_OR_SELF_FAPIAO" 176 INVOICEMODE_TENCENT_DIGITAL_TAX InvoiceMode = "TENCENT_DIGITAL_TAX" 177) 178 179type FapiaoAbilityType string 180 181func (e FapiaoAbilityType) Ptr() *FapiaoAbilityType { 182 return &e 183} 184 185const ( 186 FAPIAOABILITYTYPE_BASE_ABILITY FapiaoAbilityType = "BASE_ABILITY" 187 FAPIAOABILITYTYPE_REAL_ESTATE_ABILITY FapiaoAbilityType = "REAL_ESTATE_ABILITY" 188) 189 190type InviteOperationType string 191 192func (e InviteOperationType) Ptr() *InviteOperationType { 193 return &e 194} 195 196const ( 197 INVITEOPERATIONTYPE_AUTH_BINDING InviteOperationType = "AUTH_BINDING" 198) 199
应答参数
200 OK
invite_url 必填 string(1024)
【邀请开通二维码链接】 用于生成邀请二维码,邀请商户在微信内扫码跳转至指定开通小程序,开通服务商电子发票能力
miniprogram_appid 必填 string(32)
【开通小程序AppID】 商户授权的小程序 AppID。与miniprogram_path 共同作为小程序跳转插件的参数,用于任意小程序跳转至指定开通小程序,开通服务商电子发票能力。参考:
wx.navigateToMiniProgram
miniprogram_path 必填 string(1024)
【开通小程序跳转路径】 商户开通服务商电子发票小程序的页面路径,与 miniprogram_appid 共同作为小程序跳转插件的参数,用于任意小程序跳转至指定开通小程序,开通服务商电子发票能力。参考:
wx.navigateToMiniProgram
应答示例
200 OK
1{ 2 "invite_url" : "https://wxacurl.cn?xxx=", 3 "miniprogram_appid" : "wxb1170446a4c0a5a2", 4 "miniprogram_path" : "pages/xxxPage" 5} 6
错误码
公共错误码
状态码 | 错误码 | 描述 | 解决方案 |
---|---|---|---|
400 | PARAM_ERROR | 参数错误 | 请根据错误提示正确传入参数 |
400 | INVALID_REQUEST | HTTP 请求不符合微信支付 APIv3 接口规则 | 请参阅 接口规则 |
401 | SIGN_ERROR | 验证不通过 | 请参阅 签名常见问题 |
500 | SYSTEM_ERROR | 系统异常,请稍后重试 | 请稍后重试 |
业务错误码
状态码 | 错误码 | 描述 | 解决方案 |
---|---|---|---|
400 | INVALID_REQUEST | 请求参数符合参数格式,但不符合业务规则 | 请使用正确的参数重新调用 |
403 | NO_AUTH | 商户无权限 | 请检查是否已经开通电子发票产品相关功能权限,并检查子商户是否接受了服务商的邀请 |
429 | FREQUENCY_LIMITED | 频率超限 | 请降低请求接口频率 |