根据OPENID导入用户会员卡
更新时间:2025.07.16对于经营会员生意的商家来说,存量会员的注册渠道广泛,包括但不限于线下渠道、微信渠道、App及其他线上渠道。因而,在商家名片经营会员时会遇到两类问题:
(1)存量会员的身份难统一识别;
(2)在应用入会活动能力时,容易对存量(但未同步身份至商家名片侧的)老会员重复补贴。
因而,针对存量会员,商家可通过用户在微信公众号/小程序内的OpenID,将存量会员通过接口导入至商家名片。
注意:用户OpenID对应的AppID,需要和会员卡所属的品牌号绑定。
接口限频:按品牌商户品牌 ID 维度 5 次/秒
接口说明
支持商户:【品牌商户】
请求方式:【POST】/brand/card-member/user-cards/import-by-openid
请求域名:【主域名】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】 请传入brand_id对应的微信支付公钥ID,接口将会校验两者的关联关系,参考微信支付公钥产品简介及使用说明获取微信支付公钥ID和相关的介绍。以下两种场景将使用到微信支付公钥: 1、接收到接口的返回内容,需要使用微信支付公钥进行验签; 2、调用含有敏感信息参数(如姓名、身份证号码)的接口时,需要使用微信支付公钥加密敏感信息后再传输参数,加密指引请参考微信支付公钥加密敏感信息指引。
body 包体参数
card_id 必填 string(32)
【会员卡模板ID】 商家创建会员卡模板成功后系统返回的会员卡模板ID
openid 必填 string(128)
【用户标识】 用户在品牌商家会员卡模板AppID下的唯一标识,获取方式详见参数说明。
user_card_code 必填 string(32)
【会员卡code】 会员在一个会员卡模板下的唯一标识,用户领取会员卡后获得的code。只能填写数字/英文/半角标点。
phone_number 选填 string(512)
【加密的手机号】 注册会员的手机号码。该字段需要使用微信支付公钥加密,请参考获取微信支付公钥ID说明以及微信支付公钥加密敏感信息指引。
card_color 选填 string(7)
【卡背景颜色】 用于卡片正面设计的RGB颜色编码,仅支持十六进制
card_picture_url 选填 string(256)
【卡图片】 商家自定义会员卡背景图。仅支持通过图片上传API接口获取的图片URL地址。支持JPG/JPEG/PNG格式,建议尺寸716px*320px,且图片小于1M。请查看以下链接后传入:图片要求示例,图片上传API指引
level 选填 string(10)
【等级】 用户会员等级,展示字段,商家可以自定义填写内容。
user_information 选填 object
【用户开卡时填写的个人信息】 用户开卡时填写的个人信息
| 属性 | |||||||||
common_field_list 选填 array[object] 【平台提供的通用开卡信息字段】 包含性别、姓名等基本信息字段
custom_field_list 选填 array[object] 【商家自定义的开卡信息字段】 商家自定义的开卡信息字段,当前最多只允许传入1项
|
valid_date_information 选填 object
【会员卡有效期】 会员卡有效期。传入的有效期类型,必须和会员卡模板保持一致。
| 属性 | |
type 选填 string 【有效期类型】 1.该有效期为会员卡激活后的有效期 2.支持绝对有效期&相对有效期设置 3.绝对有效期:固定过期时间,需遵循 RFC3339 标准格式:yyyy-MM-DDTHH:mm:ss+TIMEZONE。yyyy-MM-DD 表示年月日;T 字符用于分隔日期和时间部分;HH:mm:ss 表示具体的时分秒;TIMEZONE 表示时区(例如,+08:00 对应东八区时间,即北京时间)。示例:2015-05-20T13:29:35+08:00 表示北京时间2015年5月20日13点29分35秒。 4.相对有效期:用户激活后x天后有效,x为天数。最多支持10,957天(30年) 5.永久有效 6.过期后卡状态变为“已过期” 7.过期后不再出现服务项,且无法给用户发送会员服务消息通知 可选取值
available_begin_time 选填 string(32) 【有效期开始时间】 type为FIX_TIME_RANGE时专用, 表示有效期开始时间。需需遵循 RFC3339 标准格式:yyyy-MM-DDTHH:mm:ss+TIMEZONE。yyyy-MM-DD 表示年月日;T 字符用于分隔日期和时间部分;HH:mm:ss 表示具体的时分秒;TIMEZONE 表示时区(例如,+08:00 对应东八区时间,即北京时间)。示例:2015-05-20T13:29:35+08:00 表示北京时间2015年5月20日13点29分35秒。 available_end_time 选填 string(32) 【有效期结束时间】 type为FIX_TERM_RANGE时专用,表示有效期结束时间。需需遵循 RFC3339 标准格式:yyyy-MM-DDTHH:mm:ss+TIMEZONE。yyyy-MM-DD 表示年月日;T 字符用于分隔日期和时间部分;HH:mm:ss 表示具体的时分秒;TIMEZONE 表示时区(例如,+08:00 对应东八区时间,即北京时间)。示例:2015-05-20T13:29:35+08:00 表示北京时间2015年5月20日13点29分35秒。 available_day_after_receive 选填 integer 【领取后N天内有效】 type为FIX_TERM时专用,表示领取后N个自然天内有效。最长不超过30年(10958 天) |
pickup_time 选填 string(32)
【领取时间】 用户领取会员卡的时间。仅在会员卡有效期类型是FIX_TERM时需要填写,领取时间必须早于当前时间,且不允许导入已过期的会员卡。需遵循 RFC3339 标准格式:yyyy-MM-DDTHH:mm:ss+TIMEZONE。yyyy-MM-DD 表示年月日;T 字符用于分隔日期和时间部分;HH:mm:ss 表示具体的时分秒;TIMEZONE 表示时区(例如,+08:00 对应东八区时间,即北京时间)。示例:2015-05-20T13:29:35+08:00 表示北京时间2015年5月20日13点29分35秒。
请求示例
POST
1curl -X POST \ 2 https://api.mch.weixin.qq.com/brand/card-member/user-cards/import-by-openid \ 3 -H "Authorization: WECHATPAY-BRAND-SHA256-RSA2048 brand_id=\"XXXX\",..." \ 4 -H "Accept: application/json" \ 5 -H "Wechatpay-Serial: PUB_KEY_ID_XXXX" \ 6 -H "Content-Type: application/json" \ 7 -d '{ 8 "card_id" : "pbLatjvWOibDc5-TBnbUk1pD12o0", 9 "openid" : "obLatjnx9gnqzS4myYGmLZ7LgLBA", 10 "user_card_code" : "478515832665", 11 "phone_number" : "vvysDQeEaH3I+wRh14St0abIkvQyFgh/fbWYSs2bLtG9tj+bdJn4WSCPzLhShNHgujZzseiL6sYmT7E65mv/eFeTa7yslYfrX0hrhHazSM/+tfvN/C3OZwiBbcrF9LTIIdBVhGOqhCx0gK5YAVZc8dbW/yJqC5i79PDfVYJtpQe3A4v/GiDa2Q+Mv03taxgnEkzqlSPjkXiCYBj9UaFJ4bqCTXiO2Kt6TpczvAaZW+9/blxiJwqEFXe78LbrIQvkDUmVdZbqBdPQ+QGQgc/2Ea4IbP/EEt1qSyXnFbzaaKSE2j4mAFON3kzNexb/SYkHZNJAuCittaW4wpGj7U+h9A==", 12 "card_color" : "#FFFF00", 13 "card_picture_url" : "https://wxpaylogo.qpic.cn/wxpaylogo/PiajxSqBRaEIPAeia7Imvtsn7sYGNcEj33YzVvJF88ECQ19LXId8ZL2Q/0", 14 "level" : "钻石会员", 15 "user_information" : { 16 "common_field_list" : [ 17 { 18 "name" : "USER_FORM_FLAG_BIRTHDAY", 19 "value" : "vvysDQeEaH3I+wRh14St0abIkvQyFgh/fbWYSs2bLtG9tj+bdJn4WSCPzLhShNHgujZzseiL6sYmT7E65mv/eFeTa7yslYfrX0hrhHazSM/+tfvN/C3OZwiBbcrF9LTIIdBVhGOqhCx0gK5YAVZc8dbW/yJqC5i79PDfVYJtpQe3A4v/GiDa2Q+Mv03taxgnEkzqlSPjkXiCYBj9UaFJ4bqCTXiO2Kt6TpczvAaZW+9/blxiJwqEFXe78LbrIQvkDUmVdZbqBdPQ+QGQgc/2Ea4IbP/EEt1qSyXnFbzaaKSE2j4mAFON3kzNexb/SYkHZNJAuCittaW4wpGj7U+h9A==" 20 } 21 ], 22 "custom_field_list" : [ 23 { 24 "name" : "喜欢的运动", 25 "user_chosen_values" : [ 26 "vvysDQeEaH3I+wRh14St0abIkvQyFgh/fbWYSs2bLtG9tj+bdJn4WSCPzLhShNHgujZzseiL6sYmT7E65mv/eFeTa7yslYfrX0hrhHazSM/+tfvN/C3OZwiBbcrF9LTIIdBVhGOqhCx0gK5YAVZc8dbW/yJqC5i79PDfVYJtpQe3A4v/GiDa2Q+Mv03taxgnEkzqlSPjkXiCYBj9UaFJ4bqCTXiO2Kt6TpczvAaZW+9/blxiJwqEFXe78LbrIQvkDUmVdZbqBdPQ+QGQgc/2Ea4IbP/EEt1qSyXnFbzaaKSE2j4mAFON3kzNexb/SYkHZNJAuCittaW4wpGj7U+h9A==" 27 ] 28 } 29 ] 30 }, 31 "valid_date_information" : { 32 "type" : "PERMANENT", 33 "available_begin_time" : "2020-05-20T13:29:35.120+08:00", 34 "available_end_time" : "2020-05-20T13:29:35.120+08:00", 35 "available_day_after_receive" : 30 36 }, 37 "pickup_time" : "2020-05-20T13:29:35.120+08:00" 38 }' 39
需配合微信支付工具库 WXPayUtility 使用,请参考Java
1package com.java.demo; 2 3import com.java.utils.WXPayBrandUtility; // 引用微信支付工具库,参考:https://pay.weixin.qq.com/doc/brand/4015826861 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 * 根据OpenID导入用户会员卡 24 */ 25public class ImportUserCardByOpenId { 26 private static String HOST = "https://api.mch.weixin.qq.com"; 27 private static String METHOD = "POST"; 28 private static String PATH = "/brand/card-member/user-cards/import-by-openid"; 29 30 public static void main(String[] args) { 31 // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/brand/4015415289 32 ImportUserCardByOpenId client = new ImportUserCardByOpenId( 33 "xxxxxxxx", // 品牌ID,是由微信支付系统生成并分配给每个品牌方的唯一标识符,品牌ID获取方式参考 https://pay.weixin.qq.com/doc/brand/4015415289 34 "1DDE55AD98Exxxxxxxxxx", // 品牌API证书序列号,如何获取请参考 https://pay.weixin.qq.com/doc/brand/4015407570 35 "/path/to/apiclient_key.pem", // 品牌API证书私钥文件路径,本地文件路径 36 "PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID,如何获取请参考 https://pay.weixin.qq.com/doc/brand/4015453439 37 "/path/to/wxp_pub.pem" // 微信支付公钥文件路径,本地文件路径 38 ); 39 40 ImportUserCardByOpenIdRequest request = new ImportUserCardByOpenIdRequest(); 41 request.cardId = "pbLatjvWOibDc5-TBnbUk1pD12o0"; 42 request.openid = "obLatjnx9gnqzS4myYGmLZ7LgLBA"; 43 request.userCardCode = "478515832665"; 44 request.phoneNumber = client.encrypt("phone_number"); 45 request.cardColor = "#FFFF00"; 46 request.cardPictureUrl = "https://wxpaylogo.qpic.cn/wxpaylogo/PiajxSqBRaEIPAeia7Imvtsn7sYGNcEj33YzVvJF88ECQ19LXId8ZL2Q/0"; 47 request.level = "钻石会员"; 48 request.userInformation = new UserInfo(); 49 request.userInformation.commonFieldList = new ArrayList<>(); 50 { 51 UserInfoCommonField commonFieldListItem = new UserInfoCommonField(); 52 commonFieldListItem.name = CommonFieldFlag.USER_FORM_FLAG_BIRTHDAY; 53 commonFieldListItem.value = client.encrypt("value"); 54 request.userInformation.commonFieldList.add(commonFieldListItem); 55 }; 56 request.userInformation.customFieldList = new ArrayList<>(); 57 { 58 UserInfoCustomField customFieldListItem = new UserInfoCustomField(); 59 customFieldListItem.name = "喜欢的运动"; 60 customFieldListItem.userChosenValues = new ArrayList<>(); 61 { 62 customFieldListItem.userChosenValues.add("vvysDQeEaH3I+wRh14St0abIkvQyFgh/fbWYSs2bLtG9tj+bdJn4WSCPzLhShNHgujZzseiL6sYmT7E65mv/eFeTa7yslYfrX0hrhHazSM/+tfvN/C3OZwiBbcrF9LTIIdBVhGOqhCx0gK5YAVZc8dbW/yJqC5i79PDfVYJtpQe3A4v/GiDa2Q+Mv03taxgnEkzqlSPjkXiCYBj9UaFJ4bqCTXiO2Kt6TpczvAaZW+9/blxiJwqEFXe78LbrIQvkDUmVdZbqBdPQ+QGQgc/2Ea4IbP/EEt1qSyXnFbzaaKSE2j4mAFON3kzNexb/SYkHZNJAuCittaW4wpGj7U+h9A=="); 63 }; 64 request.userInformation.customFieldList.add(customFieldListItem); 65 }; 66 request.validDateInformation = new DateInfo(); 67 request.validDateInformation.type = DateType.PERMANENT; 68 request.validDateInformation.availableBeginTime = "2020-05-20T13:29:35.120+08:00"; 69 request.validDateInformation.availableEndTime = "2020-05-20T13:29:35.120+08:00"; 70 request.validDateInformation.availableDayAfterReceive = 30L; 71 request.pickupTime = "2020-05-20T13:29:35.120+08:00"; 72 try { 73 UserCard response = client.run(request); 74 // TODO: 请求成功,继续业务逻辑 75 System.out.println(response); 76 } catch (WXPayBrandUtility.ApiException e) { 77 // TODO: 请求失败,根据状态码执行不同的逻辑 78 e.printStackTrace(); 79 } 80 } 81 82 public UserCard run(ImportUserCardByOpenIdRequest request) { 83 String uri = PATH; 84 String reqBody = WXPayBrandUtility.toJson(request); 85 86 Request.Builder reqBuilder = new Request.Builder().url(HOST + uri); 87 reqBuilder.addHeader("Accept", "application/json"); 88 reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId); 89 reqBuilder.addHeader("Authorization", WXPayBrandUtility.buildAuthorization(brand_id, certificateSerialNo,privateKey, METHOD, uri, reqBody)); 90 reqBuilder.addHeader("Content-Type", "application/json"); 91 RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody); 92 reqBuilder.method(METHOD, requestBody); 93 Request httpRequest = reqBuilder.build(); 94 95 // 发送HTTP请求 96 OkHttpClient client = new OkHttpClient.Builder().build(); 97 try (Response httpResponse = client.newCall(httpRequest).execute()) { 98 String respBody = WXPayBrandUtility.extractBody(httpResponse); 99 if (httpResponse.code() >= 200 && httpResponse.code() < 300) { 100 // 2XX 成功,验证应答签名 101 WXPayBrandUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey, 102 httpResponse.headers(), respBody); 103 104 // 从HTTP应答报文构建返回数据 105 return WXPayBrandUtility.fromJson(respBody, UserCard.class); 106 } else { 107 throw new WXPayBrandUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers()); 108 } 109 } catch (IOException e) { 110 throw new UncheckedIOException("Sending request to " + uri + " failed.", e); 111 } 112 } 113 114 private final String brand_id; 115 private final String certificateSerialNo; 116 private final PrivateKey privateKey; 117 private final String wechatPayPublicKeyId; 118 private final PublicKey wechatPayPublicKey; 119 120 public ImportUserCardByOpenId(String brand_id, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) { 121 this.brand_id = brand_id; 122 this.certificateSerialNo = certificateSerialNo; 123 this.privateKey = WXPayBrandUtility.loadPrivateKeyFromPath(privateKeyFilePath); 124 this.wechatPayPublicKeyId = wechatPayPublicKeyId; 125 this.wechatPayPublicKey = WXPayBrandUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath); 126 } 127 128 public String encrypt(String plainText) { 129 return WXPayBrandUtility.encrypt(this.wechatPayPublicKey, plainText); 130 } 131 132 public static class ImportUserCardByOpenIdRequest { 133 @SerializedName("card_id") 134 public String cardId; 135 136 @SerializedName("openid") 137 public String openid; 138 139 @SerializedName("user_card_code") 140 public String userCardCode; 141 142 @SerializedName("phone_number") 143 public String phoneNumber; 144 145 @SerializedName("card_color") 146 public String cardColor; 147 148 @SerializedName("card_picture_url") 149 public String cardPictureUrl; 150 151 @SerializedName("level") 152 public String level; 153 154 @SerializedName("user_information") 155 public UserInfo userInformation; 156 157 @SerializedName("valid_date_information") 158 public DateInfo validDateInformation; 159 160 @SerializedName("pickup_time") 161 public String pickupTime; 162 } 163 164 public static class UserCard { 165 @SerializedName("user_card_code") 166 public String userCardCode; 167 168 @SerializedName("card_id") 169 public String cardId; 170 171 @SerializedName("openid") 172 public String openid; 173 174 @SerializedName("card_color") 175 public String cardColor; 176 177 @SerializedName("card_picture_url") 178 public String cardPictureUrl; 179 180 @SerializedName("brand_id") 181 public String brandId; 182 183 @SerializedName("card_type") 184 public CardType cardType; 185 186 @SerializedName("phone_number") 187 public String phoneNumber; 188 189 @SerializedName("level") 190 public String level; 191 192 @SerializedName("valid_date_information") 193 public DateInfo validDateInformation; 194 195 @SerializedName("pickup_time") 196 public String pickupTime; 197 198 @SerializedName("user_information") 199 public UserInfo userInformation; 200 201 @SerializedName("attach") 202 public String attach; 203 204 @SerializedName("user_card_state") 205 public UserCardState userCardState; 206 207 @SerializedName("invalid_reason") 208 public String invalidReason; 209 210 @SerializedName("invalid_time") 211 public String invalidTime; 212 213 @SerializedName("create_time") 214 public String createTime; 215 216 @SerializedName("modify_time") 217 public String modifyTime; 218 } 219 220 public static class UserInfo { 221 @SerializedName("common_field_list") 222 public List<UserInfoCommonField> commonFieldList; 223 224 @SerializedName("custom_field_list") 225 public List<UserInfoCustomField> customFieldList; 226 } 227 228 public static class DateInfo { 229 @SerializedName("type") 230 public DateType type; 231 232 @SerializedName("available_begin_time") 233 public String availableBeginTime; 234 235 @SerializedName("available_end_time") 236 public String availableEndTime; 237 238 @SerializedName("available_day_after_receive") 239 public Long availableDayAfterReceive; 240 } 241 242 public enum CardType { 243 @SerializedName("PURCHASE") 244 PURCHASE, 245 @SerializedName("NORMAL") 246 NORMAL, 247 @SerializedName("BALANCE") 248 BALANCE 249 } 250 251 public enum UserCardState { 252 @SerializedName("UNACTIVATED") 253 UNACTIVATED, 254 @SerializedName("EFFECTIVE") 255 EFFECTIVE, 256 @SerializedName("EXPIRED") 257 EXPIRED, 258 @SerializedName("INVALID") 259 INVALID 260 } 261 262 public static class UserInfoCommonField { 263 @SerializedName("name") 264 public CommonFieldFlag name; 265 266 @SerializedName("value") 267 public String value; 268 } 269 270 public static class UserInfoCustomField { 271 @SerializedName("name") 272 public String name; 273 274 @SerializedName("user_chosen_values") 275 public List<String> userChosenValues; 276 } 277 278 public enum DateType { 279 @SerializedName("FIX_TIME_RANGE") 280 FIX_TIME_RANGE, 281 @SerializedName("FIX_TERM") 282 FIX_TERM, 283 @SerializedName("PERMANENT") 284 PERMANENT 285 } 286 287 public enum CommonFieldFlag { 288 @SerializedName("USER_FORM_FLAG_SEX") 289 USER_FORM_FLAG_SEX, 290 @SerializedName("USER_FORM_FLAG_NAME") 291 USER_FORM_FLAG_NAME, 292 @SerializedName("USER_FORM_FLAG_BIRTHDAY") 293 USER_FORM_FLAG_BIRTHDAY, 294 @SerializedName("USER_FORM_FLAG_ADDRESS") 295 USER_FORM_FLAG_ADDRESS, 296 @SerializedName("USER_FORM_FLAG_EMAIL") 297 USER_FORM_FLAG_EMAIL, 298 @SerializedName("USER_FORM_FLAG_CITY") 299 USER_FORM_FLAG_CITY 300 } 301 302} 303
需配合微信支付工具库 wxpay_utility 使用,请参考Go
1package main 2 3import ( 4 "bytes" 5 "demo/wxpay_brand_utility" // 引用微信支付工具库,参考 https://pay.weixin.qq.com/doc/brand/4015826866 6 "encoding/json" 7 "fmt" 8 "net/http" 9 "net/url" 10) 11 12func main() { 13 // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/brand/4015415289 14 config, err := wxpay_brand_utility.CreateBrandConfig( 15 "xxxxxxxx", // 品牌ID,是由微信支付系统生成并分配给每个品牌方的唯一标识符,品牌ID获取方式参考 https://pay.weixin.qq.com/doc/brand/4015415289 16 "1DDE55AD98Exxxxxxxxxx", // 品牌API证书序列号,如何获取请参考 https://pay.weixin.qq.com/doc/brand/4015407570 17 "/path/to/apiclient_key.pem", // 品牌API证书私钥文件路径,本地文件路径 18 "PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID,如何获取请参考 https://pay.weixin.qq.com/doc/brand/4015453439 19 "/path/to/wxp_pub.pem", // 微信支付公钥文件路径,本地文件路径 20 ) 21 if err != nil { 22 fmt.Println(err) 23 return 24 } 25 26 request := &ImportUserCardByOpenIdRequest{ 27 CardId: wxpay_brand_utility.String("pbLatjvWOibDc5-TBnbUk1pD12o0"), 28 Openid: wxpay_brand_utility.String("obLatjnx9gnqzS4myYGmLZ7LgLBA"), 29 UserCardCode: wxpay_brand_utility.String("478515832665"), 30 PhoneNumber: wxpay_brand_utility.String("vvysDQeEaH3I+wRh14St0abIkvQyFgh/fbWYSs2bLtG9tj+bdJn4WSCPzLhShNHgujZzseiL6sYmT7E65mv/eFeTa7yslYfrX0hrhHazSM/+tfvN/C3OZwiBbcrF9LTIIdBVhGOqhCx0gK5YAVZc8dbW/yJqC5i79PDfVYJtpQe3A4v/GiDa2Q+Mv03taxgnEkzqlSPjkXiCYBj9UaFJ4bqCTXiO2Kt6TpczvAaZW+9/blxiJwqEFXe78LbrIQvkDUmVdZbqBdPQ+QGQgc/2Ea4IbP/EEt1qSyXnFbzaaKSE2j4mAFON3kzNexb/SYkHZNJAuCittaW4wpGj7U+h9A=="), /*请传入wxpay_brand_utility.EncryptOAEPWithPublicKey 加密结果*/ 31 CardColor: wxpay_brand_utility.String("#FFFF00"), 32 CardPictureUrl: wxpay_brand_utility.String("https://wxpaylogo.qpic.cn/wxpaylogo/PiajxSqBRaEIPAeia7Imvtsn7sYGNcEj33YzVvJF88ECQ19LXId8ZL2Q/0"), 33 Level: wxpay_brand_utility.String("钻石会员"), 34 UserInformation: &UserInfo{ 35 CommonFieldList: []UserInfoCommonField{UserInfoCommonField{ 36 Name: COMMONFIELDFLAG_USER_FORM_FLAG_BIRTHDAY.Ptr(), 37 Value: wxpay_brand_utility.String("vvysDQeEaH3I+wRh14St0abIkvQyFgh/fbWYSs2bLtG9tj+bdJn4WSCPzLhShNHgujZzseiL6sYmT7E65mv/eFeTa7yslYfrX0hrhHazSM/+tfvN/C3OZwiBbcrF9LTIIdBVhGOqhCx0gK5YAVZc8dbW/yJqC5i79PDfVYJtpQe3A4v/GiDa2Q+Mv03taxgnEkzqlSPjkXiCYBj9UaFJ4bqCTXiO2Kt6TpczvAaZW+9/blxiJwqEFXe78LbrIQvkDUmVdZbqBdPQ+QGQgc/2Ea4IbP/EEt1qSyXnFbzaaKSE2j4mAFON3kzNexb/SYkHZNJAuCittaW4wpGj7U+h9A=="), /*请传入wxpay_brand_utility.EncryptOAEPWithPublicKey 加密结果*/ 38 }}, 39 CustomFieldList: []UserInfoCustomField{UserInfoCustomField{ 40 Name: wxpay_brand_utility.String("喜欢的运动"), 41 UserChosenValues: []string{"vvysDQeEaH3I+wRh14St0abIkvQyFgh/fbWYSs2bLtG9tj+bdJn4WSCPzLhShNHgujZzseiL6sYmT7E65mv/eFeTa7yslYfrX0hrhHazSM/+tfvN/C3OZwiBbcrF9LTIIdBVhGOqhCx0gK5YAVZc8dbW/yJqC5i79PDfVYJtpQe3A4v/GiDa2Q+Mv03taxgnEkzqlSPjkXiCYBj9UaFJ4bqCTXiO2Kt6TpczvAaZW+9/blxiJwqEFXe78LbrIQvkDUmVdZbqBdPQ+QGQgc/2Ea4IbP/EEt1qSyXnFbzaaKSE2j4mAFON3kzNexb/SYkHZNJAuCittaW4wpGj7U+h9A=="}, 42 }}, 43 }, 44 ValidDateInformation: &DateInfo{ 45 Type: DATETYPE_PERMANENT.Ptr(), 46 AvailableBeginTime: wxpay_brand_utility.String("2020-05-20T13:29:35.120+08:00"), 47 AvailableEndTime: wxpay_brand_utility.String("2020-05-20T13:29:35.120+08:00"), 48 AvailableDayAfterReceive: wxpay_brand_utility.Int64(30), 49 }, 50 PickupTime: wxpay_brand_utility.String("2020-05-20T13:29:35.120+08:00"), 51 } 52 53 response, err := ImportUserCardByOpenId(config, request) 54 if err != nil { 55 fmt.Printf("请求失败: %+v\n", err) 56 // TODO: 请求失败,根据状态码执行不同的处理 57 return 58 } 59 60 // TODO: 请求成功,继续业务逻辑 61 fmt.Printf("请求成功: %+v\n", response) 62} 63 64func ImportUserCardByOpenId(config *wxpay_brand_utility.BrandConfig, request *ImportUserCardByOpenIdRequest) (response *UserCard, err error) { 65 const ( 66 host = "https://api.mch.weixin.qq.com" 67 method = "POST" 68 path = "/brand/card-member/user-cards/import-by-openid" 69 ) 70 71 reqUrl, err := url.Parse(fmt.Sprintf("%s%s", host, path)) 72 if err != nil { 73 return nil, err 74 } 75 reqBody, err := json.Marshal(request) 76 if err != nil { 77 return nil, err 78 } 79 httpRequest, err := http.NewRequest(method, reqUrl.String(), bytes.NewReader(reqBody)) 80 if err != nil { 81 return nil, err 82 } 83 httpRequest.Header.Set("Accept", "application/json") 84 httpRequest.Header.Set("Wechatpay-Serial", config.WechatPayPublicKeyId()) 85 httpRequest.Header.Set("Content-Type", "application/json") 86 authorization, err := wxpay_brand_utility.BuildAuthorization(config.BrandId(), config.CertificateSerialNo(), config.PrivateKey(), method, reqUrl.RequestURI(), reqBody) 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_brand_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_brand_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 := &UserCard{} 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_brand_utility.NewApiException( 120 httpResponse.StatusCode, 121 httpResponse.Header, 122 respBody, 123 ) 124 } 125} 126 127type ImportUserCardByOpenIdRequest struct { 128 CardId *string `json:"card_id,omitempty"` 129 Openid *string `json:"openid,omitempty"` 130 UserCardCode *string `json:"user_card_code,omitempty"` 131 PhoneNumber *string `json:"phone_number,omitempty"` 132 CardColor *string `json:"card_color,omitempty"` 133 CardPictureUrl *string `json:"card_picture_url,omitempty"` 134 Level *string `json:"level,omitempty"` 135 UserInformation *UserInfo `json:"user_information,omitempty"` 136 ValidDateInformation *DateInfo `json:"valid_date_information,omitempty"` 137 PickupTime *string `json:"pickup_time,omitempty"` 138} 139 140type UserCard struct { 141 UserCardCode *string `json:"user_card_code,omitempty"` 142 CardId *string `json:"card_id,omitempty"` 143 Openid *string `json:"openid,omitempty"` 144 CardColor *string `json:"card_color,omitempty"` 145 CardPictureUrl *string `json:"card_picture_url,omitempty"` 146 BrandId *string `json:"brand_id,omitempty"` 147 CardType *CardType `json:"card_type,omitempty"` 148 PhoneNumber *string `json:"phone_number,omitempty"` 149 Level *string `json:"level,omitempty"` 150 ValidDateInformation *DateInfo `json:"valid_date_information,omitempty"` 151 PickupTime *string `json:"pickup_time,omitempty"` 152 UserInformation *UserInfo `json:"user_information,omitempty"` 153 Attach *string `json:"attach,omitempty"` 154 UserCardState *UserCardState `json:"user_card_state,omitempty"` 155 InvalidReason *string `json:"invalid_reason,omitempty"` 156 InvalidTime *string `json:"invalid_time,omitempty"` 157 CreateTime *string `json:"create_time,omitempty"` 158 ModifyTime *string `json:"modify_time,omitempty"` 159} 160 161type UserInfo struct { 162 CommonFieldList []UserInfoCommonField `json:"common_field_list,omitempty"` 163 CustomFieldList []UserInfoCustomField `json:"custom_field_list,omitempty"` 164} 165 166type DateInfo struct { 167 Type *DateType `json:"type,omitempty"` 168 AvailableBeginTime *string `json:"available_begin_time,omitempty"` 169 AvailableEndTime *string `json:"available_end_time,omitempty"` 170 AvailableDayAfterReceive *int64 `json:"available_day_after_receive,omitempty"` 171} 172 173type CardType string 174 175func (e CardType) Ptr() *CardType { 176 return &e 177} 178 179const ( 180 CARDTYPE_PURCHASE CardType = "PURCHASE" 181 CARDTYPE_NORMAL CardType = "NORMAL" 182 CARDTYPE_BALANCE CardType = "BALANCE" 183) 184 185type UserCardState string 186 187func (e UserCardState) Ptr() *UserCardState { 188 return &e 189} 190 191const ( 192 USERCARDSTATE_UNACTIVATED UserCardState = "UNACTIVATED" 193 USERCARDSTATE_EFFECTIVE UserCardState = "EFFECTIVE" 194 USERCARDSTATE_EXPIRED UserCardState = "EXPIRED" 195 USERCARDSTATE_INVALID UserCardState = "INVALID" 196) 197 198type UserInfoCommonField struct { 199 Name *CommonFieldFlag `json:"name,omitempty"` 200 Value *string `json:"value,omitempty"` 201} 202 203type UserInfoCustomField struct { 204 Name *string `json:"name,omitempty"` 205 UserChosenValues []string `json:"user_chosen_values,omitempty"` 206} 207 208type DateType string 209 210func (e DateType) Ptr() *DateType { 211 return &e 212} 213 214const ( 215 DATETYPE_FIX_TIME_RANGE DateType = "FIX_TIME_RANGE" 216 DATETYPE_FIX_TERM DateType = "FIX_TERM" 217 DATETYPE_PERMANENT DateType = "PERMANENT" 218) 219 220type CommonFieldFlag string 221 222func (e CommonFieldFlag) Ptr() *CommonFieldFlag { 223 return &e 224} 225 226const ( 227 COMMONFIELDFLAG_USER_FORM_FLAG_SEX CommonFieldFlag = "USER_FORM_FLAG_SEX" 228 COMMONFIELDFLAG_USER_FORM_FLAG_NAME CommonFieldFlag = "USER_FORM_FLAG_NAME" 229 COMMONFIELDFLAG_USER_FORM_FLAG_BIRTHDAY CommonFieldFlag = "USER_FORM_FLAG_BIRTHDAY" 230 COMMONFIELDFLAG_USER_FORM_FLAG_ADDRESS CommonFieldFlag = "USER_FORM_FLAG_ADDRESS" 231 COMMONFIELDFLAG_USER_FORM_FLAG_EMAIL CommonFieldFlag = "USER_FORM_FLAG_EMAIL" 232 COMMONFIELDFLAG_USER_FORM_FLAG_CITY CommonFieldFlag = "USER_FORM_FLAG_CITY" 233) 234
应答参数
200 OK
user_card_code 必填 string(32)
【会员卡code】 会员在一个会员卡模板下的唯一标识,用户领取会员卡后获得的code。只能填写数字/英文/半角标点。
card_id 必填 string(32)
【会员卡模板 ID】 商家创建会员卡模板成功后系统返回的会员卡模板ID
openid 必填 string(128)
【用户标识】 用户在品牌商家会员卡模板AppID下的唯一标识,获取方式详见参数说明。
card_color 选填 string(7)
【卡背景颜色】 用于卡片正面设计的RGB颜色编码,仅支持十六进制
card_picture_url 选填 string(256)
【卡图片】 商家自定义会员卡背景图。仅支持通过图片上传API接口获取的图片URL地址。支持JPG/JPEG/PNG格式,建议尺寸716px*320px,且图片小于1M。请查看以下链接后传入:图片要求示例,图片上传API指引
brand_id 必填 string(32)
【品牌ID】 商家进驻微信支付品牌商家后获得的品牌ID(灰度期间联系微信支付运营获取),用于标记该会员卡的归属方
card_type 必填 string
【会员卡类型】 支持付费、普通、储值 3 种类型。目前仅支持普通会员卡,填写付费和储值类型时会返回错误。
可选取值
PURCHASE: 付费NORMAL: 普通BALANCE: 储值
phone_number 选填 string(512)
【加密的手机号】 注册会员的手机号码,仅在用户授权手机号、商家通过 API 传入的情况下有值。解密请参考如何使用品牌API证书解密敏感字段。
level 选填 string(10)
【等级】 用户会员等级,展示字段,商家可以自定义填写内容。
valid_date_information 必填 object
【会员卡有效期】 会员卡有效期
| 属性 | |
type 选填 string 【有效期类型】 1.该有效期为会员卡激活后的有效期 2.支持绝对有效期&相对有效期设置 3.绝对有效期:固定过期时间,需遵循 RFC3339 标准格式:yyyy-MM-DDTHH:mm:ss+TIMEZONE。yyyy-MM-DD 表示年月日;T 字符用于分隔日期和时间部分;HH:mm:ss 表示具体的时分秒;TIMEZONE 表示时区(例如,+08:00 对应东八区时间,即北京时间)。示例:2015-05-20T13:29:35+08:00 表示北京时间2015年5月20日13点29分35秒。 4.相对有效期:用户激活后x天后有效,x为天数。最多支持10,957天(30年) 5.永久有效 6.过期后卡状态变为“已过期” 7.过期后不再出现服务项,且无法给用户发送会员服务消息通知 可选取值
available_begin_time 选填 string(32) 【有效期开始时间】 type为FIX_TIME_RANGE时专用, 表示有效期开始时间。需需遵循 RFC3339 标准格式:yyyy-MM-DDTHH:mm:ss+TIMEZONE。yyyy-MM-DD 表示年月日;T 字符用于分隔日期和时间部分;HH:mm:ss 表示具体的时分秒;TIMEZONE 表示时区(例如,+08:00 对应东八区时间,即北京时间)。示例:2015-05-20T13:29:35+08:00 表示北京时间2015年5月20日13点29分35秒。 available_end_time 选填 string(32) 【有效期结束时间】 type为FIX_TERM_RANGE时专用,表示有效期结束时间。需需遵循 RFC3339 标准格式:yyyy-MM-DDTHH:mm:ss+TIMEZONE。yyyy-MM-DD 表示年月日;T 字符用于分隔日期和时间部分;HH:mm:ss 表示具体的时分秒;TIMEZONE 表示时区(例如,+08:00 对应东八区时间,即北京时间)。示例:2015-05-20T13:29:35+08:00 表示北京时间2015年5月20日13点29分35秒。 available_day_after_receive 选填 integer 【领取后N天内有效】 type为FIX_TERM时专用,表示领取后N个自然天内有效。最长不超过30年(10958 天) |
pickup_time 必填 string(32)
【领取时间】 用户领取会员卡的时间,需遵循 RFC3339 标准格式:yyyy-MM-DDTHH:mm:ss+TIMEZONE。yyyy-MM-DD 表示年月日;T 字符用于分隔日期和时间部分;HH:mm:ss 表示具体的时分秒;TIMEZONE 表示时区(例如,+08:00 对应东八区时间,即北京时间)。示例:2015-05-20T13:29:35+08:00 表示北京时间2015年5月20日13点29分35秒。
user_information 选填 object
【用户开卡时填写的个人信息】 用户开卡时填写的个人信息
| 属性 | |||||||||
common_field_list 选填 array[object] 【平台提供的通用开卡信息字段】 包含性别、姓名等基本信息字段
custom_field_list 选填 array[object] 【商家自定义的开卡信息字段】 商家自定义的开卡信息字段,当前最多只允许传入1项
|
attach 选填 string(256)
【商家数据包】 商家在创建用户会员卡时可传入自定义数据包,该数据对用户不可见,用于存储商家自定义信息,其总长度限制在256字符以内。查询用户会员卡详情时会将此字段返回给商家。
user_card_state 必填 string
【用户会员卡状态】 用户当前的卡状态
可选取值
UNACTIVATED: 用户已领卡,但还未激活EFFECTIVE: 用户的会员卡可正常使用EXPIRED: 用户的会员卡已过期INVALID: 用户的会员卡已失效
invalid_reason 选填 string(32)
【作废原因】 会员卡作废时传入的原因
invalid_time 选填 string(32)
【作废时间】 会员卡作废操作的时间,需遵循 RFC3339 标准格式:yyyy-MM-DDTHH:mm:ss+TIMEZONE。yyyy-MM-DD 表示年月日;T 字符用于分隔日期和时间部分;HH:mm:ss 表示具体的时分秒;TIMEZONE 表示时区(例如,+08:00 对应东八区时间,即北京时间)。示例:2015-05-20T13:29:35+08:00 表示北京时间2015年5月20日13点29分35秒。
create_time 必填 string(32)
【创建时间】 创建会员卡的时间,需遵循 RFC3339 标准格式:yyyy-MM-DDTHH:mm:ss+TIMEZONE。yyyy-MM-DD 表示年月日;T 字符用于分隔日期和时间部分;HH:mm:ss 表示具体的时分秒;TIMEZONE 表示时区(例如,+08:00 对应东八区时间,即北京时间)。示例:2015-05-20T13:29:35+08:00 表示北京时间2015年5月20日13点29分35秒。
modify_time 必填 string(32)
【更新时间】 更新会员卡的时间,需遵循 RFC3339 标准格式:yyyy-MM-DDTHH:mm:ss+TIMEZONE。yyyy-MM-DD 表示年月日;T 字符用于分隔日期和时间部分;HH:mm:ss 表示具体的时分秒;TIMEZONE 表示时区(例如,+08:00 对应东八区时间,即北京时间)。示例:2015-05-20T13:29:35+08:00 表示北京时间2015年5月20日13点29分35秒。
应答示例
200 OK
1{ 2 "user_card_code" : "478515832665", 3 "card_id" : "pbLatjvWOibDc5-TBnbUk1pD12o0", 4 "openid" : "obLatjnx9gnqzS4myYGmLZ7LgLBA", 5 "card_color" : "#FFFF00", 6 "card_picture_url" : "https://wxpaylogo.qpic.cn/wxpaylogo/PiajxSqBRaEIPAeia7Imvtsn7sYGNcEj33YzVvJF88ECQ19LXId8ZL2Q/0", 7 "brand_id" : "1001622624", 8 "card_type" : "NORMAL", 9 "phone_number" : "vvysDQeEaH3I+wRh14St0abIkvQyFgh/fbWYSs2bLtG9tj+bdJn4WSCPzLhShNHgujZzseiL6sYmT7E65mv/eFeTa7yslYfrX0hrhHazSM/+tfvN/C3OZwiBbcrF9LTIIdBVhGOqhCx0gK5YAVZc8dbW/yJqC5i79PDfVYJtpQe3A4v/GiDa2Q+Mv03taxgnEkzqlSPjkXiCYBj9UaFJ4bqCTXiO2Kt6TpczvAaZW+9/blxiJwqEFXe78LbrIQvkDUmVdZbqBdPQ+QGQgc/2Ea4IbP/EEt1qSyXnFbzaaKSE2j4mAFON3kzNexb/SYkHZNJAuCittaW4wpGj7U+h9A==", 10 "level" : "钻石会员", 11 "valid_date_information" : { 12 "type" : "PERMANENT", 13 "available_begin_time" : "2020-05-20T13:29:35.120+08:00", 14 "available_end_time" : "2020-05-20T13:29:35.120+08:00", 15 "available_day_after_receive" : 30 16 }, 17 "pickup_time" : "2020-05-20T13:29:35.120+08:00", 18 "user_information" : { 19 "common_field_list" : [ 20 { 21 "name" : "USER_FORM_FLAG_BIRTHDAY", 22 "value" : "vvysDQeEaH3I+wRh14St0abIkvQyFgh/fbWYSs2bLtG9tj+bdJn4WSCPzLhShNHgujZzseiL6sYmT7E65mv/eFeTa7yslYfrX0hrhHazSM/+tfvN/C3OZwiBbcrF9LTIIdBVhGOqhCx0gK5YAVZc8dbW/yJqC5i79PDfVYJtpQe3A4v/GiDa2Q+Mv03taxgnEkzqlSPjkXiCYBj9UaFJ4bqCTXiO2Kt6TpczvAaZW+9/blxiJwqEFXe78LbrIQvkDUmVdZbqBdPQ+QGQgc/2Ea4IbP/EEt1qSyXnFbzaaKSE2j4mAFON3kzNexb/SYkHZNJAuCittaW4wpGj7U+h9A==" 23 } 24 ], 25 "custom_field_list" : [ 26 { 27 "name" : "喜欢的运动", 28 "user_chosen_values" : [ 29 "vvysDQeEaH3I+wRh14St0abIkvQyFgh/fbWYSs2bLtG9tj+bdJn4WSCPzLhShNHgujZzseiL6sYmT7E65mv/eFeTa7yslYfrX0hrhHazSM/+tfvN/C3OZwiBbcrF9LTIIdBVhGOqhCx0gK5YAVZc8dbW/yJqC5i79PDfVYJtpQe3A4v/GiDa2Q+Mv03taxgnEkzqlSPjkXiCYBj9UaFJ4bqCTXiO2Kt6TpczvAaZW+9/blxiJwqEFXe78LbrIQvkDUmVdZbqBdPQ+QGQgc/2Ea4IbP/EEt1qSyXnFbzaaKSE2j4mAFON3kzNexb/SYkHZNJAuCittaW4wpGj7U+h9A==" 30 ] 31 } 32 ] 33 }, 34 "attach" : "自定义数据说明", 35 "user_card_state" : "EFFECTIVE", 36 "invalid_reason" : "传入的自定义作废原因", 37 "invalid_time" : "2020-05-20T13:29:35.120+08:00", 38 "create_time" : "2020-05-20T13:29:35.120+08:00", 39 "modify_time" : "2020-05-20T13:29:35.120+08:00" 40} 41
错误码
以下是本接口返回的错误码列表。详细错误码规则,请参考微信支付接口规则-错误码和错误提示

