# K12开发文档
更新记录
版本 | 简要说明 | 修改日期 |
---|---|---|
1.0 | 新增K12开发文档 | 2022/4/8 |
# 1. 接口规范
问题:基于平台提供的通用接口能力,服务商自由度高但缺少经验,方案落地后出现接口调用不合理、无法正常使用,代扣时序和模版不清晰,家长质疑扣错款导致客诉。
目标:指导服务商合理地使用接口能力封装方案,学校上线后避免用户链路中断或体验感极差而导致客诉。
接入规范:
详情请点击进入《离线刷脸SDK商户接入规范(终端)》查阅。
详情请点击进入《离线刷脸后端接口商户接入规范(后台)》查阅。
签约/解约接入规范请查阅下述内容。
# 1.1 签约
# 1.1.1 签约后信息同步
问题1:小程序传入参数错误,用户无法进入k12官方小程序进行签约?
方案:
【接口文档】必须遵守如下规则:
类型 | 跳转类型与跳转链接必须一一对应 |
学校名称 | 必须与机构ID的学校名称一致、不能简写, 例如"深圳市高级中学" |
学生信息 | 必须是完整班级信息(*注意传入真实班级,例如“高中一年三班”,“19届2班”等) |
手机号 | 必须满足11位,例如"15988866666" |
token | 有效期5分钟,注意不要过期(* 建议在跳转官方小程序前的最后一个页面,才获取token) |
【界面提示】常见参数异常提示优化,让服务商可以自行快速地调整。
目前弹窗提示与优化后的弹窗提示分别如下图所示:
传参异常提示列表:
错误类型 | 文案 |
手机号有误 | 无法创建用户 传入手机号不足11位,需确保传入正确的手机号,请反馈给技术方处理。 |
班级信息有误 | 无法创建用户 班级信息不正确,需传入完整的班级信息,请反馈给技术方处理。 |
学校名称与机构ID不符 | 无法创建用户 学校名称有误,需要与机构ID对应的名称一致,请反馈给技术方处理。 |
token过期 | 无法创建用户 Token超过有效期,需确保Token获取后在5分钟内使用,请反馈给技术方处理。 |
类型和跳转链接不匹配 | 无法创建用户 传入的调用类型与跳转链接类型不一致,请反馈给技术方处理。 |
问题2:用户签约后,学生信息(姓名/班级/手机号)等在签约后因为换班、家长换手机等情况修改,如果没有及时同步给微信平台,会导致学生无法正常使用刷脸。
方案:当学生信息有变更时,调用用户信息修改接口、传入最新信息。
# 1.1.2 签约后重新采集人脸
问题:用户签约后,因为采错照片等原因无法刷脸识别?
方案:服务商可调用重新采集接口、在学校给学生重采人脸;然后让家长打开小程序,确认重采的学生人脸照片后,系统即替换掉签约时的照片。
# 1.2 代扣
# 1.2.1 订单补扣
问题:代扣发起时间在深夜或节假日,家长收到后质疑乱扣费,导致客诉?
接口规范建议:
【补扣时间】不干扰家长休息
● 建议时段,对于三餐都有的学校,建议工作日早上6:00-8:00、中午11:00-14:00、晚上16:00-20:00,对于仅中午有食堂的学校,建议中午11:00-14:00;周末节假日如果学生不在校,建议不发起补扣;
● 建议频率,每笔订单每天尝试扣款最多5次,超过5次会被拦截。
【公众号通知】说明清晰,避免误解
● 每笔订单单独进行补扣,不建议多笔欠款合并一起扣款;
● 强调“订单延迟扣款”,与正常支付消息区分明显,避免误以为重复扣款;
● 设备断网、银行系统维护等原因也会导致扣款延误,所以避免用“欠款”字样等可能引起用户抵触的文字。
延时扣款消息与普通支付消息分别如下图所示:
延迟原因与文案建议:
延迟原因 | 文案建议 |
零钱或银行卡余额不足 | 消费时“零钱或银行卡余额不足”导致扣款延误,请保持账户资金充足。 |
指定卡不可用 | 消费时“签约的银行卡被解绑”导致扣款延误,请保持银行卡可用。 |
无可用支付方式 | 消费时“无可用的银行卡导致”扣款延误,请保持银行卡可用。 |
垫资超过上限 | 消费时“微信零钱或银行卡余额不足”导致扣款延误,请保持账户资金充足。 |
支付凭证异常 | 系统异常导致扣款延迟,现已恢复。 |
微信账号异常 | 微信账号异常导致无法扣费,现已恢复。 |
银行卡状态异常 | 银行卡无法扣费导致,现已恢复。 |
签约异常 | 签约微信号解约导致无法扣款,现已恢复。 |
# 1.2.2 订单跨节假日支付
问题:学校放假时关闭设备,部分订单未及时上传,节后发现订单过期无法扣费?
接入规则建议:
设备使用后预留1小时,等订单上传完成后,再关机或断网。
订单有效期为7天,节假日会适当延长,如果遇到订单失效,则需向平台方申请延长有效期。
# 1.2.3 大额代扣调用
问题:学校包餐制,单笔金额大于100元?
可以调用大额代扣接口:
消费额度:单笔最大额度为500元。
频率限制:教职工微信号限频为40次/月、userid为20次/月;学生的签约微信号为5次/月。
# 1.2.4 支付凭证内容展示
问题:支付凭证内容不清晰,家长不确定是否学生本人刷脸消费,导致客诉核实?
接口规范建议:扣费内容信息要具体、清晰,避免家长疑惑。
内容要求 | 举例 | |
必备内容 | 展示消费者姓名、消费场所 | 王小明-中午食堂就餐 王小明-面包房消费 |
进阶内容 | 展示具体档口,菜品/商品信息 | 王小明-中午食堂6号档口消费,两荤一素套餐 王小明-便利店消费,酸奶 |
样式示例:
# 1.3 解约
# 1.3.1 解约后重新签约
问题:微信号冻结/丢失等原因,无法还款、导致无法再使用刷脸代扣?
指导服务商获取还款链接,让用户通过其他微信号还款,然后通过后台接口进行解约,让用户使用其他微信号重新签约。
● 还款链接:服务商后台获取垫资的还款链接、线下向用户核实后,人工转发给还款的微信号;
● 后台解约:服务商调用后台解约接口进行解约。
# 1.3.2 毕业批量解约
问题:毕业季学生家长未解约,服务商如何清理数据?
● 后台解约:调用后台解约接口,服务商获知毕业学生名单后,可以对毕业学生进行批量解约,注意控制调用解约接口的频率。
# 2. 签约小程序
跳转一共包含3种场景,签约,集采照片和确认重采照片。
跳转方式:详情请点击wx.navigateToMiniProgram查看。
场景1:集采照片
主要用于学校统一采集学生照片场景,目的是为了提高签约效率,实现录入照片的操作。
wx.navigateToMiniProgram({
appId:'wx5931af4836330935', //采集小程序appid
path:'/pages/face_take_photos/take_photos?is_first=1', //小程序路径
extraData: {
type:'take_photo',//采集跳转
user_name: '张三', //刷脸用户姓名
school_name:'深圳中学', //学校
user_type:'STAFF', //职业(STUDENT:学生,STAFF:职员)
student_info:{'class_name':'1班'}, //class_name:班级,user_type为STUDENT时必传
staff_info:{'occupation':'教师'}, //occupation:职业, user_type为STAFF时必传
school_list:["深圳中学", "宝安中学"],// 学校列表,至少包含本学校
organization_id: 'O1947FD2089aed8785', //organazition_id
out_user_id: 'test', // out_user_id,商户侧的用户ID,唯一不可重复
account:'15988866666', // 签约手机号
token:'XCXab19673d0d0b5c0ffd980fb60ce82f5e', //商户认证凭据
},
envVersion: 'trial', // 如果要跳转体验版,加上这个参数,否则请不要加这个参数
success(res) {
// 成功跳转到签约小程序
},
fail(res) {
// 未成功跳转到签约小程序
}
})
字段 | 描述 | 示例 | 必填 |
type | 跳转类型 | 固定值:take_photo | 是 |
user_name | 用户名 | 张三 | 是 |
school_name | 学校名称 | 深圳中学 | 是 |
user_type | 职业 STUDENT:学生 STAFF:职员 | STUDENT | 是 |
student_info | 学生信息 | {'class_name':'高一(1)班'} | user_type为STUDENT时必填 |
staff_info | 职工信息 | {'occupation':'教师'} | user_type为STAFF时必填 |
school_list | 学校列表 | ["深圳中学", "宝安中学", "南山中学", "罗湖中学"] | 是 |
organization_id | 机构id | O1947FD2089aed8785 | 是 |
out_user_id | out_user_id | test | 是 |
account | 手机号 | 15988866666 | 是 |
token | token | XCXab19673d0d0b5c0ffd980fb60ce82f5e | 是 |
referrerInfo字段说明
{
appId:'wx5931af4836330935', //采集小程序appid
extraData:{
'return_code':'SUCCESS', //状态码
'return_msg':'录入成功', //提示信息
}
}
已录入 | 有照片,且转码成功,照片质量合格 | SUCCESS | 录入成功 |
未录入 | 无照片 | FAIL | 未录入 |
场景2:签约
签约正常流程,如果已有集采的照片,在签约时会展示已经录入的照片,否则有录入照片的流程。
wx.navigateToMiniProgram({
appId:'wx5931af4836330935', //小程序id
path:'/pages/face_index/index?is_first=1', //小程序路径
extraData: {
type:'sign',//签约跳转
user_name: '张三', //刷脸用户姓名
school_name:'深圳中学', //学校
user_type:'STAFF', //职业(STUDENT:学生,STAFF:职员)
student_info:{'class_name':'1班'}, //class_name:班级,user_type为STUDENT时必传
staff_info:{'occupation':'教师'}, // occupation:职业, user_type为STAFF时必传
school_list:["深圳中学", "宝安中学"],// 学校列表,至少包含本学校
organization_id: 'oea567edbgADeG', // 机构ID
out_user_id: 'SEGdget123987789', // 商户侧用户ID
account:'15988866666', // 签约手机号
token:'PRESIGN_DGET1233543djgegeedde'
},
success(res) {
// 成功跳转到签约小程序
},
fail(res) {
// 未成功跳转到签约小程序
}
})
字段 | 描述 | 示例 | 必填 |
type | 跳转类型 | 固定值:sign | 是 |
user_name | 用户名 | 张三 | 是 |
school_name | 学校名称 | 深圳中学 | 是 |
user_type | 职业 STUDENT:学生 STAFF:职员 | STUDENT | 是 |
student_info | 学生信息 | {'class_name':'高一(1)班'} | user_type为STUDENT时必填 |
staff_info | 职工信息 | {'occupation':'教师'} | user_type为STAFF时必填 |
school_list | 学校列表 | ["深圳中学", "宝安中学", "南山中学", "罗湖中学"] | 是 |
organization_id | 机构id | O1947FD2089aed8785 | 是 |
out_user_id | out_user_id | test | 是 |
account | 手机号 | 15988866666 | 是 |
token | token | XCXab19673d0d0b5c0ffd980fb60ce82f5e | 是 |
referrerInfo字段说明
referrerInfo字段说明 {
appId:'wx5931af4836330935',
extraData:{
'return_code':'SUCCESS',
'return_msg':'签约成功',
}
}
签约成功 | SUCCESS | 签约成功 |
签约失败 | FAIL | 签约失败 |
场景3:家长确认学生重采照片(低频)
只要用户学生照片质量不合格,就需要重新录入照片,家长进行确认后即可使用新的照片刷脸消费。
跳转k12小程序参数字段
wx.navigateToMiniProgram({
appId:'wx5931af4836330935', // 确认小程序appid
path:'/pages/photo_confirm_user/photo_confirm_user',//小程序路径
extraData: {
type:'confirm_register_photo',// 家长确认学生重采照片场景
user_name: '张三', // 刷脸用户姓名,学生名字
school_name:'深圳中学', // 学校
user_type:'STAFF', //职业(STUDENT:学生,STAFF:职员)
organization_id: 'O1947FD2089aed8785', // 机构ID
out_user_id: '516064415', // 商户的用户ID
account:'15988866666', //签约手机号
token:'XCXab19673d0d0b5c0ffd980fb60ce82f5e'
},
envVersion: 'trial', // 如果要跳转体验版,加上这个参数,否则请不要加这个参数
success(res) {
// 成功跳转到小程序确认流程
},
fail(res) {
// 未成功跳转到小程序确认流程
}
})
字段 | 描述 | 示例 | 必填 |
type | 跳转类型 | 固定值:confirm_register_photo | 是 |
user_name | 用户名 | 张三 | 是 |
school_name | 学校名称 | 深圳中学 | 是 |
user_type | 职业 STUDENT:学生 STAFF:职员 | STUDENT | 是 |
school_list | 学校列表 | ["深圳中学", "宝安中学", "南山中学", "罗湖中学"] | 是 |
organization_id | 机构id | O1947FD2089aed8785 | 是 |
out_user_id | out_user_id | 516064415 | 是 |
user_id | user_id | FU29EAEFZ5722adadd | 是 |
account | 手机号 | 15988866666 | 是 |
token | token | XCXab19673d0d0b5c0ffd980fb60ce82f5e | 是 |
跳转回商户小程序携带参数
referrerInfo字段说明 {
appId:'wx5931af4836330935', // 商户小程序appID
extraData:{
'return_code':'SUCCESS',
'return_msg':'确认成功',
}
}
确认成功 | SUCCESS | 确认成功 |
确认失败 | FAIL | 确认失败 |
# 3. 终端接入
更新记录
版本 | 简要说明 |
---|---|
2.12.100 | initWxpayface 调⽤必有回调,如果失败,可以等待⼀段时间处理; 加⼊need_ext_verify 来判断是否需要辅助验证; 补充摄像头散热问题软件建议。 |
2.12.200 | 增加preloadSdkEnv接⼝来减少启动识别耗时; 旧有的K12UserInfo改名为UserInfo,新旧版本AAR都能兼容现有apk,商户不需要单独考虑兼容性问题; startVerify增加“用户信息更新中,请等待...”的271378645错误码; startVerify根据need_ext_verify来判断是否辅助验证,后续不再保证只根据个数来做处理。 |
2.12.704 | 辅助验证要求下调,刷脸环境恶劣可以降级后四位验证; 辅助验证策略必须改造2.0版本need_ext_verify 才能适配新版,否则finishFaceVerify会提示”请输入⼿机号后四位“的271378652错误; 增加getUserInfo接口,方便商户确认机器用户信息是否同步以及签约状态ge'tSdkInfo数量显示的是全部用户数量,历史版本仅显示采集照⽚成功的⽤户数量。 |
2.13.808 | getUserInfo会同步返回用户信息更新时间和同步到设备时间。 |
2.21.300 | 推荐预览大小是3:4的高宽比; 数据库初始化失败271378588错误; 通用系统错误271378694; 双胞胎问题处理与解决; 预览接口提供手动移除可能性。 |
# 3.1 常用参考
# 3.2 业务流程
# 3.3 注意点
A、流程1、流程2任选其一即可;
B、使用“流程1”耗时可以更优,适用于支付金额在开始识别之前就已知的情况;
C、使用“流程2”耗时可以更长,适用于支付金额在开始识别之前未明确的情况;
D、展示完用户信息后,获取支付凭证和用户点击确认可以并行处理,优化支付耗时。
# 3.4 使用说明
使用方式
A、安装人脸App;
B、商户接入人脸SDK。
注意点
A、商户使用SDK接口均封装在WxPayFace类中,该类以单例形式存在。调用结果统一由IWxPayfaceCallback回调;
B、参数或回调结果以Map形式传递,方便扩展,具体字段名称及返回值定义参考文档;
C、每次SDK退出(release或异常),如果重新调用任何其它api,都会重新调用init,并且回调之前的callback,这里建议init的callback固定为同⼀个,可以持续监听对应的回调事件。
//IWxPayfaceCallback//继承⾃AIDL接⼝,⽅便服务商使⽤。⽬前仅提⼀个统⼀的回调接⼝。
public abstract interface IWxPayfaceCallback {
public abstract void response(Map info) throws RemoteException;
}
# 3.5 通用请求参数(每个请求都需要带)
经过“初始化”,“获取rawData”、“销毁并释放资源” 步骤外的所有流程都需要带授权凭据和商户基础信息。
请求参数 | 必填 | 类型 | 说明 |
authinfo | 是 | string | 调用授权凭据 |
appid | 是 | string | 微信公众号 |
sub_appid | 否 | string | 子商户公众账号id(非服务商模式不填) |
mch_id | 是 | string | 填您的商户号 |
mch_name | 是 | string | 商户名 |
sub_mch_id | 否 | string | 子商户号(非服务商模式不填) |
organization_id | 是 | string | 机构id |
# 3.6 通用返回参数(每个请求都会回应)
当商户刷脸APP向微信离线刷脸SDK请求时,都会返回通用的参数。
变量名 | 必填 | 描述 | 解决方案 |
return_code | 是 | 错误码 | 无 |
return_msg | 是 | 错误描述 | 展示错误原因 |
err_code | 否 | 二级错误码类型Integer,注意判空 | 错误码,有特定的规则说明 |
return_code | 描述 | 解决方案 |
SUCCESS | 接口成功 | 无 |
ERROR | 接口错误 | 展示错误原因(该请求无法通过重试解决) |
PARAM_ERROR | 参数错误 | 参照错误提示 |
SYSTEMERROR | 接口返回错误 | 系统异常,建议提示让用户重试 |
FAIL | 接口失败 | SDK服务连接断开,SDK会自动重试请求 |
# 3.7 通用err_code
通用err_code(注意判空,不⼀定返回,只用于辅助查问题作归因,不存在的时候可以使用return_msg直接归因)。
通用err_code | 描述 | 解决方案 |
271378620 | 刷脸服务未初始化(所有接口都有可能返回) | 等待500ms左右调用init |
271378621 | 刷脸服务初始化中(所有接口都有可能返回) | 等待500ms左右调用init |
271378498 | 通用输入参数错误 | 无,检查api调用 |
271378562 | 机构ID不对 | 无,检查api调用 |
271378434 | sn不匹配 | 无,检查api调用 |
271378525/271378435/271377920 | authinfo异常 | 重新获取authinfo |
271378588 | 数据库初始化失败 | 建议检查调用release时机;release时间无异常则检查设备存储,重新初始化 |
271378694 | 系统异常 | 建议release后初始化重试 |
# 3.8 常规接口
(1)初始化(initWxpayface)
接口作用:对人脸SDK进行初始化
public void initWxpayface(Context ctx,Map info, IWxPayfaceCallback callback);
请求参数(无通用参数)
请求参数 | 必填 | 类型 | 说明 |
ip | 否 | string | HTTP代理IP |
port | 否 | string | HTTP代理端口,需为数字 |
user | 否 | string | HTTP代理的用户名 |
passwd | 否 | string | HTTP代理的密码 |
返回参数
无特殊参数,只有returncode和returnmsg
示例
private void initPayFace() {
Map<String, String> m1 = new HashMap<>();
m1.put("ip", "xxx.xxx.xxx.xxx");
//若没有代理,则不需要此行,代理ip请自行寻找
m1.put("port", "8888");
//若没有代理,则不需要此行,代理端口不一定是8888,根据代理设置来决定
WxPayFace.getInstance().initWxpayface(this, m1, new IWxPayfaceCallback() {
@Override
public void response(Map info) throws RemoteException {
if (info == null) {
new RuntimeException("调用返回为空").printStackTrace();
return ;
}
String code = (String) info.get("return_code");
String msg = (String) info.get("return_msg");
Log.d(TAG, "response info :: " + code + " | " + msg);
if (code == null || !code.equals("SUCCESS")) {
new RuntimeException("调用返回非成功信息: " + msg).printStackTrace();
return ;
}
Log.d(TAG, "调用返回成功");
/*
在这里处理您自己的业务逻辑
*/
}
});
}
建议:
A、您可以自定义一个Application,然后在自定义Application的onCreate()中调用initPayFace()完成人脸识别模块的初始化;
B、您可以只在被调用人脸识别模块的activity的onCreate()中完成initPayFace()的调用;
C、失败或者超时请release后重试。
(2)获取数据(getWxpayfaceRawdata)
public void getWxpayfaceRawdata(IWxPayfaceCallback callback);
请求参数
无参数
返回参数(包含returncode和returnmsg)
额外参数 | 必填 | 类型 | 说明 |
rawdata | 是 | string(2048) | 初始化数据,用于API(获取调用授权凭据authinfo) |
示例
private void getWxpayfaceRawdata() {
WxPayFace.getInstance().getWxpayfaceRawdata(new IWxPayfaceCallback() {
@Override
public void response(Map info) throws RemoteException {
if (info == null) {
new RuntimeException("调用返回为空").printStackTrace();
return;
}
String code = (String) info.get("returncode");
String msg = (String) info.get("returnmsg");
String rawdata = (String)info.get("rawdata");
if (code == null || rawdata == null || !code.equals("SUCCESS")) {
new RuntimeException("调用返回非成功信息,return_msg:" + msg + " ").printStackTrace();
return ;
}
/*
在这里处理您自己的业务逻辑
*/
}
});
}
建议:失败或者超时请重新release。
(3)获取调用授权凭据authinfo
接口定义
POST https://api.mch.weixin.qq.com/v3/offlineface/authinfo
请求参数
字段名 | 变量名 | 类型 | 必填 | 示例 | 说明 |
服务商appid | sp_appid | string | 是 | 示例值: wx369ab4160391b078 字符长度限制: [1, 32] | 商户appid |
子appid | sub_appid | string | 有则必传 | 示例值: wx369ab4160391b078 字符长度限制: [0, 32] | 子商户appid |
子商户号 | sub_mchid | string | 是 | 示例值: 1900000109 字符长度限制: [0, 32] | 子商户号 |
设备id | device_id | string | 是 | 示例值: TXAP12029003744ND002112 字符长度限制: [1, 32] | 终端设备唯一ID,必须为数字、字母、下划线的组合 |
原始数据 | raw_data | string | 是 | 示例值: kh5HJYlzqXosbqJCOYXASBxYozukRFjg5P9MY
字符长度限制: [1, 2048] | 初始化数据,由微信人脸SDK的接口返回。 |
机构id | organization_id | string | 是 | 示例值: OCAABBDDee 字符长度限制: [1, 64] | 机构ID,注意创建机构的商户号和mch_id应该保持一致。 |
返回结果
字段名 | 变量名 | 类型 | 必填 | 示例 | 说明 |
授权信息 | authinfo | string | 是 | 示例值: kh5HJYlzqXosbqJCOYXASBxYozukRFjg5P9MY 字符长度限制: [1, 4096] | SDK调用凭证,用于调用SDK的人脸识别接口 |
请求示例
<return_code>SUCCESS</return_code>
<return_msg>请求成功</return_msg>
<nonce_str>Tivppi4UXAbgLxk8e1Sij76YdowOFFii</nonce_str>
<sign>PL0EUID6A7ICWNKHCSMQC0UIXOYNSE5B</sign>
<appid>wx31fdaErqR31</appid>
<mch_id>12345689</mch_id>
<authinfo>q3OPhFtQBf6KZGqmZhejKCRy5K/ch0kwS11YSsEj9XmUGqcsT2QPHt0Oa7xaCMCoSZTWMmShCo4dOiO5tU+OJEsvSxXzn5m3Nkh747tinNlbpJmVq1zOPj+FJNndkzanxoiAddO8p1EfrmUhJs/aNf0pDfrPoVfkAapK+ZY6blwyaDQ9bB7+KkZq29kObsXOZ3thg+bxP4RAqC0oxNS4JiyP0uA1Euzxtkc9lCTebloFied8stILrMehUKukeMGkZ1SzTyc8/HFHApzHahNPX6yD8ttzYnhe+IRMFJgpuTlIvEOYZUxenPXE1A5clrPvOBeJDszX/OvZl4fpYWPpXAcVQlw+gfYhblt+rT6ALMsD73w/rT4NRriQEEraC4Pfb5yua4qAqv4TVo04</authinfo>
<expires_in>3600</expires_in>
建议:返回的接口凭证authinfo,可以在expires_in指定的有效期内,同一台机具上重复使用。
注意:authinfo有效期一般是36个小时,建议设备自动每小时更新一次。
(4)销毁并释放资源(releaseWxpayface)
public void releaseWxpayface((Context cxt);
请求参数
无参数
返回参数
无参数
示例
private void releasePayFace() {
WxPayFace.getInstance().releaseWxpayface(this);
}
注意:获取rawdata和authinfo失败或者超时时,调用此接口,即release后重试。
(5)手动更新人脸库(manualUpdateFaceDatas)
public void manualUpdateFaceDatas(Map info,IWxPayfaceCallback cb);
请求参数
包含通用请求参数
返回参数(包含通用返回参数和通用errCode)
如果returncode不为成功,可以使用返回的returnmsg,比如“正在更新中...” 可能返回errcode 271378620 和 271378621,具体处理方式参考errcode说明。
示例
private void manualUpdateFaceDatas() {
//params包含请求通用参数(authinfo,mch_id等)
WxPayFace.getInstance().manualUpdateFaceDatas(params,new IWxPayfaceCallback() {
@Override
public void response(Map info) throws RemoteException {
if (info == null) {
new RuntimeException("调用返回为空").printStackTrace();
return;
}
String code = (String) info.get("return_code");
String msg = (String) info.get("return_msg");
if (code == null || !code.equals("SUCCESS")) {
new RuntimeException("调用返回非成功信息,return_msg:" + msg + " ").printStackTrace();
return ;
}
}
});
}
}
注意:
A、商户app启动必须调用更新人脸库;
B、SDK有自身的自动更新逻辑,但是没有回调,适用于同步少量数据的时间,比如商户就餐期间等;
C、手动更新同步存在回调,适用于同步大量数据的时间,比如商户就餐前登录账号的时间,保证数据尽快同步到本地,使用时希望能设置loading页面,禁止用户操作,必须等待回调再开始操作;
D、自动更新同步在网络良好的情况下一般要前端修改用户信息3分钟左右,手动更新会更快一些,并且适用于机器重置数据后同步恢复数据状态。
同步的原因主要是是增加新用户信息;对删除用户出库;更新用户状态(比如调整欠费状态、是否禁用等)。
(6)预加载识别资源(preloadSdkEnv)
public void preloadSdkEnv(Map info,IWxPayfaceCallback cb);
说明:
一般情况下,应用启动后的第一次调用开启摄像头等api会耗时较长,因为涉及到SDK的初始化工作,涉及到很多io读写,如果人脸库规模越大,初始化时间越长,如果提前preloadsdkenv加载资源,可以保证第一次开启摄像头和识别启动很快。
请求参数
包含通用请求参数
返回参数(包含通用返回参数和通用errCode)
无特殊参数,只有returncode和returnmsg,可能返回errcode 271378620 和 271378621,具体处理方式参考errcode说明。
示例
private void preloadEnv() {
//params包含请求通用参数(authinfo,mch_id等)
WxPayFace.getInstance().preloadSdkEnv(params,new IWxPayfaceCallback() {
@Override
public void response(Map info) throws RemoteException {
if (info == null) {
new RuntimeException("调用返回为空").printStackTrace();
return;
}
String code = (String) info.get("return_code");
String msg = (String) info.get("return_msg");
if (code == null || sdkVersion == null || !code.equals("SUCCESS")) {
new RuntimeException("调用返回非成功信息,return_msg:" + msg + " ").printStackTrace();
return ;
}
/*
在这里处理您自己的业务逻辑
*/
}
});
}
(7)获取支付SDK相关信息(getSdkInfo)
public void getSdkInfo(Map info,IWxPayfaceCallback cb);
请求参数
包含通用请求参数
返回参数(包含通用返回参数和通用errCode)
返回参数 | 必填 | 类型 | 说明 |
sdk_version | 是 | string(2048) | 支付app版本 |
face_feature_version | 是 | string(2048) | 人脸特征版本 |
user_info_total_count | 是 | int | 数据库全部用户信息数量,包含小程序图片未确认的用户信息 |
user_info_dbcount | 是 | int | 小程序图片已确认的数据库用户信息数量 |
user_info_memcount | 是 | int | 小程序图片已确认能检索到的用户信息数量 |
非通用错误码
无特殊参数,只有returncode和returnmsg,可能返回errcode 271378620 和 271378621,具体处理方式参考errcode说明。
示例
private void getSdkInfo() {
//params包含请求通用参数(authinfo,mch_id等)
WxPayFace.getInstance().getSdkInfo(params,new IWxPayfaceCallback() {
@Override
public void response(Map info) throws RemoteException {
if (info == null) {
new RuntimeException("调用返回为空").printStackTrace();
return;
}
String code = (String) info.get("return_code");
String msg = (String) info.get("return_msg");
String sdkVersion = (String)info.get("sdk_version");
String faceFeatureVersion = (String)info.get("face_feature_version");
int faceFeatureVersion = (Integer)info.get("user_info_dbcount");
if (code == null || sdkVersion == null ||
!code.equals("SUCCESS")) {
new RuntimeException("调用返回非成功信息,return_msg:" + msg + " ").printStackTrace();
return ;
}
/*
在这里处理您自己的业务逻辑
*/
}
});
}
(8)获取用户信息状态(getUserInfo)
public void getUserInfo(Map info,IWxPayfaceCallback cb);
用途:
落地排查问题专用,商户需要获取用户信息在机器上的同步状态,避免因为同步而导致的无法交易问题。
请求参数
特殊参数 | 必填 | 类型 | 说明 |
out_user_id | 否 | string | 用户在商户处的唯一id,商户需保持唯一性,如果不唯一,终端返回检索到的第一个 |
返回参数(包含通用返回参数和通用errCode)
特殊参数 | 必填 | 类型 | 说明 |
status | 否 | string | 用户当前状态为空表示不存在; 用户当前状态FS_NORMAL代表正常可用; 用户当前状态为其他,表示用户无法支付 |
update_time | 否 | string | 用户信息更新时间,格式yyyy-MM-dd HH:mm:ss |
sync_time | 否 | string | 用户信息同步到本地时间,格式yyyy-MM-dd HH:mm:ss |
示例
private void getUserInfo() {
//params包含请求通用参数(authinfo,mch_id等)
WxPayFace.getInstance().getUserInfo(params,new IWxPayfaceCallback() {
@Override
public void response(Map info) throws RemoteException {
if (info == null) {
new RuntimeException("调用返回为空").printStackTrace();
return;
}
String code = (String) info.get("return_code");
String msg = (String) info.get("return_msg");
if (code == null || !code.equals("SUCCESS")) {
new RuntimeException("调用返回非成功信息,return_msg:" + msg + " ").printStackTrace();
return ;
}
final String status = (String) info.get(FacePayConstants.KEY_RET_FACE_FEATURE_STATUS);
final String syncTimeStr = (String) info.get(FacePayConstants.KEY_RET_USER_SYNCTIME);
final String updateTimeStr = (String) info.get(FacePayConstants.KEY_RET_USER_UPDATETIME);
String result = TextUtils.isEmpty(status) ? "用户不存在" : "用户当前状态:" + status;
}
});
}
}
(9)设置预览view(setCameaPreview)
public void setCameaPreview(SurfaceView surfaceView,Map info,IWxPayfaceCallback cb);
请求参数
包含通用请求参数
特殊参数 | 必填 | 类型 | 说明 |
surfaceView | 是 | surfaceView | 摄像头回调展示界面,默认渲染高度使用surfaceView高宽 |
返回参数(包含通用返回参数和通用errCode)
可能返回errcode 271378620 和 271378621,具体处理方式参考errcode说明。
示例
private void setCameaPreview(SurfaceView surfaceview) {
//params包含请求通用参数(authinfo,mch_id等)
WxPayFace.getInstance().setCameaPreview(surfaceview,params,new IWxPayfaceCallback() {
@Override
public void response(Map info) throws RemoteException {
if (info == null) {
new RuntimeException("调用返回为空").printStackTrace();
return;
}
String code = (String) info.get("return_code");
String msg = (String) info.get("return_msg");
if (code == null || !code.equals("SUCCESS")) {
new RuntimeException("调用返回非成功信息,return_msg:" + msg + " ").printStackTrace();
return ;
}
}
});
}
}
注意:
A、预览view主要是用于摄像头的图像画面回调,必须保证surface一定不能为空;
B、如果绑定的surfaceview调用surfaceDestroyed销毁后,记得需要重新绑定。
(10)移除预览view(removeCameaPreview)
public void removeCameaPreview(SurfaceView surfaceView,Map info,IWxPayfaceCallback cb);
注意:
预览界面默认可以自行进行绑定和移除,特殊的surfaceview可以考虑自行移除预览view。
请求参数
包含通用请求参数
返回参数(包含通用返回参数和通用errCode)
可能返回errcode 271378620 和 271378621,具体处理方式参考errcode说明。
示例
private void removeCameaPreview(SurfaceView surfaceview) { //params包含请求通用参数(authinfo,mch_id等)
WxPayFace.getInstance().removeCameaPreview(surfaceview,params,new IWxPayfaceCallback() {
@Override
public void response(Map info) throws RemoteException {
if (info == null) {
new RuntimeException("调用返回为空").printStackTrace();
return;
}
String code = (String) info.get("return_code");
String msg = (String) info.get("return_msg");
if (code == null || !code.equals("SUCCESS")) {
new RuntimeException("调用返回非成功信息,return_msg:" + msg + " ").printStackTrace();
return ;
}
}
});
}
}
(11)开始识别(startVerify)
public void startVerify( Map info, IWxPayFaceCallbackAIDL cb);
请求参数
包含通用请求参数
返回参数(包含通用返回参数和通用errCode)
可能返回errcode 271378620 和 271378621,具体处理方式参考errcode说明。
特殊返回参数 | 必填 | 类型 | 说明 |
user_info_list | 否 | UserInfo 类型 | 识别后返回的用户信息,返回多个则需要商户处理手机号辅助校验,注意用户信息此时不包含userId |
best_face_img | 否 | Bitmap类型 | 安全处理后的现场图片,避免用户信息泄漏 |
best_face_rect_left | 否 | float | 0-1之间,表明人脸的最左边 |
best_face_rect_right | 否 | float | 0-1之间,表明人脸的最右边 |
best_face_rect_top | 否 | float | 0-1之间,表明人脸的最上边 |
best_face_rect_bottom | 否 | float | 0-1之间,表明人脸的最下边 |
err_code | 是 | Integer | 人脸识别异常原因,比如人脸未录入、请摘掉口罩等,重点注意-6是“未检测到人脸” |
return_msg | 是 | String | err_code对应异常原因 |
need_restart_verify | 否 | boolean | false表示会自动重新识别,true需要手动恢复 |
need_ext_verify | 否 | boolean | 2.23版本开始支持; 是否需要额外的辅助验证,相比userinfolist是为了方便后续拓展,新版本都采用这个参数判断是否需要验证手机号 |
face_verify_id | 否 | string | 用于定位问题的唯一id |
特殊的return_code
特殊的return_code | 说明 | 描述 |
FIRST_FRAME_CALLBACK | 识别后第一帧回调了 | 商户可以配合去做cameraview的展示,如果不需要根据这个信息处理surfaceview的可以不做处理 |
二级错误码参考
错误码 | 描述 | 是否停止识别(默认否) |
-1 | 请往前移一点 | 否 |
-2 | 请保持脸部在正中央 | 否 |
-3 | 请往后移一点 | 否 |
-5 | 请保持脸部端正 | 否 |
-6 | 未检测到人脸 | 否,商户可以自己关掉 |
-10 | 请将人脸移至画面正中央 | 否 |
-11 | 请右移至画面中央 | 否 |
-12 | 请左移至画面中央 | 否 |
-13 | 请将人脸移至画面正中央 | 否 |
271377935 | 请摘掉眼镜或帽子 | 否 |
271377936 | 请不要遮挡面部 | 否 |
271378510 | 请与设备保持合适距离 | 否 |
271378511 | 请面向摄像头刷脸 | 否 |
271378526 | 未识别出你的身份 | 否 |
271377938 | 识别中... | 否 |
27137846、27137846、 27137846、27137858、 27137858、27137858、 27137859、27137859、 271378592 | 摄像头状态异常,请重启 | 是 |
271378645 | 设备无法使用,请等待用户信息更新完成 | 是 |
其它异常问题可以直接参考接口返回的异常信息来做展示,needrestart
public class UserInfo implements Parcelable {
private String userId;
private String outUserId;
private String status;
//用户状态,FS_NORMAL为正常,其余非法,不能扣款
...
}
示例
private void startVerify() {
//params包含请求通用参数(authinfo,mch_id等)
WxPayface.getInstance().startVerify(params,new IWxPayfaceCallback() {
@Override
public void response(Map info) throws RemoteException {
if (info == null) {
new RuntimeException("调用返回为空").printStackTrace();
return;
}
String code = (String) info.get("return_code");
String msg = (String) info.get("return_msg");
if (code == null || !code.equals("SUCCESS")) {
new RuntimeException("调用返回非成功信息,return_msg:" + msg + " ").printStackTrace();
return ;
}
List<UserInfo> userInfos =(List<UserInfo>)info.get("user_info_list");
//是否需要辅助验证
final Boolean needExtVerify = (Boolean) (info.get(FacePayConstants.KEY_RET_PARAMS_NEED_EXT_VERIFY));
final Bitmap bitmap =(Bitmap)info.get("best_face_img");
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
mImageView.setImageBitmap(bitmap);
mImageView.requestLayout();
}
});
}
});
}
注意:
A、识别接口分为开启和停止,识别成功后会自动停止;
B、识别失败会自动重新开启,并返回对应的错误信息,注意271378467/271378468/271378469的返回码;
C、识别成功返回的userInfo类型,记得在proguard里需要keep对应的class
-keep class com.tencent.wxpayface.data.UserInfo{ *; };
D、startVerify后成功流程应该是finishverify->getFacePayCredential;如果中途异常退出需要调用stopVerify,流程只支持串行,并行会提示271378531 ,上次识别未完成。
返回参数有提供人脸识别框的坐标范围,主要优化现场照有多个人脸存在的场景,请商户自己考虑勾选框对应的颜色问题。
(12)停止识别(stopVerify)
public void stopVerify(Map info,IWxPayfaceCallback cb);
请求参数
包含通用请求参数
返回参数(包含通用返回参数和通用errCode)
可能返回errcode 271378620 和 271378621,具体处理方式参考errcode说明。
示例
private void stopVerify() {
//params包含请求通用参数(authinfo,mch_id等)
WxPayFace.getInstance().stopVerify(params,new IWxPayfaceCallback() {
@Override
public void response(Map info) throws RemoteException {
if (info == null) {
new RuntimeException("调用返回为空").printStackTrace();
return;
}
String code = (String) info.get("return_code");
String msg = (String) info.get("return_msg");
if (code == null || !code.equals("SUCCESS")) {
new RuntimeException("调用返回非成功信息,return_msg:" + msg + " ").printStackTrace();
return ;
}
}
});
}
}
注意:
任意时刻都可以调用该接口,但是注意该接口调用后并不会清除上一次的识别数据,仍然可以走完支付流程。
(13)完成识别流程( finishFaceVerify)
public void finishFaceVerify(Map info,IWxPayfaceCallback cb);
请求参数
包含通用请求参数
特殊必填 | 类型 | 说明 |
user_phone | 否 | string |
返回参数(包含通用返回参数和通用errCode)
可能返回errcode 271378620 和 271378621,具体处理方式参考errcode说明。
返回参数 | 必填 | 类型 | 说明 |
user_info | 否 | UserInfo的parcelable类型 | 返回完成识别流程的用户信息,这里的userinfo会带有userId |
face_verify_id | 否 | string | 用于定位问题的唯一id |
二级错误码参考
error_code | return_msg | 说明 |
271378532 | 传入的手机号错误,请联络客服 | 无满足条件用户返回 |
271378652 | 传入验证信息确认,请联络客服 | 新版SDK需要根据need_ext_verify判断是否需要输入手机号 |
271378587 | 输入的手机号匹配到多个用户,请联系客服 | 存在同一个手机尾号人脸相似的多个用户 |
示例
private void finishFaceVerify() {
//params包含请求通用参数(authinfo,mchid等)
WxPayFace.getInstance().finishFaceVerify(params,new IWxPayfaceCallback() {
@Override
public void response(Map info) throws RemoteException {
if (info == null) {
new RuntimeException("调用返回为空").printStackTrace();
return;
}
String code = (String) info.get("returncode");
String msg = (String) info.get("returnmsg");
if (code == null || !code.equals("SUCCESS")) {
new RuntimeException("调用返回非成功信息,returnmsg:" + msg + " ").printStackTrace();
return ;
}
UserInfo userInfo =(UserInfo)info.get("userinfo");
if(userInfo == null || TextUtils.isEmpty(userInfo.getUserId()) {
new RuntimeException("调用返回非成功信息,returnmsg: 用户信息为空").printStackTrace();
return ;
}
//到此处才算成功,一定要注意userinfo和userid判空
});
}
}
}
}
注意:
开始识别返回用户信息后,不论是确认还是取消,都需要调用完成才能进行下一次识别。
如果识别成功返回了单个用户信息,则不需要传递手机号,直接可以拿到当前的识别用户信息。
如果返回多个用户信息,需要商户传递手机号来获得对应的识别用户信息。
(14)获取支付凭证(getFacePayCredential)
public void getFacePayCredential(Map info,IWxPayfaceCallback cb);
请求参数
包含通用请求参数
请求参数 | 必填 | 类型 | 说明 |
user_id | 否 | string | 识别后的用户id |
recog_mode | 是 | int32 | 0:直接识别;1:手机辅助识别。 |
total_fee | 是 | string | 订单金额(数字),单位:分 |
返回参数(包含通用返回参数和通用errCode)
可能返回errcode 271378620 和 271378621,具体处理方式参考errcode说明。
返回参数 | 必填 | 类型 | 说明 |
face_token | 否 | string | 终端支付凭证 |
face_verify_id | 否 | string | 用户定位问题的唯一id |
二级错误码参考
error_code | return_msg | 说明 |
271378533 | 请检查用户签约状态 | 用户状态异常 |
271378595 | 未找到用户信息,请联系客服 | 无对应用户信息 |
271378527 | 支付账号异常,请联系客服 | 被风控拦截 |
271378641 | 交易频繁,请等待重试 | 同人同金额5s内重复扣款 |
示例
private void getFacePayCredential() {
//params包含请求通用参数(authinfo,mch_id等)
WxPayFace.getInstance().getFacePayCredential(params,new IWxPayfaceCallback() {
@Override
public void response(Map info) throws RemoteException {
if (info == null) {
new RuntimeException("调用返回为空").printStackTrace();
return;
}
String code = (String) info.get("return_code");
String msg = (String) info.get("return_msg");
String faceToken= (String)info.get("face_token");
if (code == null || !code.equals("SUCCESS") || TextUtils.isEmpty(faceToken)) {
new RuntimeException("调用返回非成功信息,return_msg:" + msg + " ").printStackTrace();
return ;
}
//到此处才算成功,一定要注意faceToken判空
}
});
}
}
注意:
开始识别返回用户信息后,不论是确认还是取消,都需要调用完成才能进行下一次识别。确认了会生成支付凭证,支付凭证生成需要一定时间。
(15)启动扫码(startCodeScanner)
public void startCodeScanner(Map info,IWxPayfaceCallback cb);
作用:
微信人脸sdk启动摄像头进入扫码模式,扫描二维码。
注意:
A、该方法注册的回调接口在stopCodeScanner之前,扫码成功都会回调;
B、该方法可以多次调用,但是扫码结果只会回调最后一次注册的回调;
C、扫码模式和刷脸互斥,一旦开始刷脸则SDK会退出扫码模式,扫码回调失效,如果需要扫码功能,需要刷脸结束后再次调用该方法启动扫码。
返回参数(包含通用返回参数和通用errCode)
特殊返回参数 | 必填 | 类型 | 说明 |
code_msg | 是 | string | 当扫码成功时返回扫码内容 |
示例
WxPayFace.getInstance().startCodeScanner(params,new IWxPayfaceCallback() {
@Override
public void response(Map info) throws RemoteException {
if (info != null) {
String return_code = (String) info.get("return_code");
Integer errcode = (Integer) info.get("err_code");
String return_msg = (String) info.get("return_msg");
String code_msg = (String) info.get("code_msg");
final String resultString = "startCodeScanner, return_code : " + return_code + " return_msg : " + return_msg + " code_msg: " + code_msg;
/** 这里添加业务自定义的工作即可 注意该回调在异步线程 **/
}
}
});
(16)停止扫码(stopCodeScanner)
public void stopCodeScanner(Map info,IWxPayfaceCallback cb);
作用:
微信人脸sdk停止摄像头扫码,退出扫码模式。
返回参数(包含通用返回参数和通用errCode)
示例
WxPayFace.getInstance().stopCodeScanner(params,,new IWxPayfaceCallback() {
@Override
public void response(Map info) throws RemoteException {
if (info == null) {
new RuntimeException("调用返回为空").printStackTrace();
return;
}
String code = (String) info.get("return_code");
String msg = (String) info.get("return_msg");
if (code == null || !code.equals("SUCCESS")) {
new RuntimeException("调用返回非成功信息,return_msg:" + msg + " ").printStackTrace();
return ;
}
}
});
(17)跳转出厂检测(goToFactoryPage)
public void goToFactoryPage(Map info,IWxPayfaceCallback cb);
作用:
微信人脸sdk进入出厂检测页面
注意:
无
返回参数(包含通用返回参数和通用errCode)
无特殊参数,只有成功和系统错误两种
示例
WxPayFace.getInstance().goToFactoryPage(params,new IWxPayfaceCallback() {
@Override
public void response(Map info) throws RemoteException {
if (info == null) {
new RuntimeException("调用返回为空").printStackTrace();
return;
}
String code = (String) info.get("return_code");
String msg = (String) info.get("return_msg");
if (code == null || !code.equals("SUCCESS")) {
new RuntimeException("调用返回非成功信息,return_msg:" + msg + " ").printStackTrace();
return ;
}
}
});
# 3.9 非必调接口
(1)清除人脸数据(clearFaceDatas)兜底逻辑接口
public void clearFaceDatas(Map info,IWxPayfaceCallback cb);
注意:
A、只是用于逻辑兜底,保证特征同步异常情况下可以重新同步,不同机构会有不同的数据库,切换机构不建议调用此方法;
B、使用异常会导致机构不可用时间增长,建议紧急情况下使用;
C、清理本地人脸数据,清除不会立马拉取。
请求参数:
包含通用请求参数
返回参数:
如果returncode不为成功,则需要记录对应的errMsg,可以提示“清除人脸数据失败” 可能返回errcode 271378620 和 271378621,具体处理方式参考err_code说明。
示例
private void clearFaceDatas() {
//params包含请求通用参数(authinfo,mch_id等)
WxPayFace.getInstance().clearFaceDatas(params,new IWxPayfaceCallback() {
@Override
public void response(Map info) throws RemoteException {
if (info == null) {
new RuntimeException("调用返回为空").printStackTrace();
return;
}
String code = (String) info.get("return_code");
String msg = (String) info.get("return_msg");
if (code == null || !code.equals("SUCCESS")) {
new RuntimeException("调用返回非成功信息,return_msg:" + msg + " ").printStackTrace();
return ;
}
}
});
}
}
(2)关闭摄像头常开(stopCamera)非常规接口
public void stopCamera(Map info,IWxPayfaceCallback cb);
注意:
这里关闭摄像头建议在长时间无交易的时段来自行处理,关闭摄像头会有损识别效率,对于华捷的摄像头如果散热OK不建议做操作。
请求参数:
包含通用请求参数
返回参数(包含通用返回参数和通用errCode)
可能返回errcode 271378620 和 271378621,具体处理方式参考errcode说明。
示例
private void stopCamera() {
//params包含请求通用参数(authinfo,mch_id等) WxPayFace.getInstance().stopCamera(params,new IWxPayfaceCallback() {
@Override
public void response(Map info) throws RemoteException {
if (info == null) {
new RuntimeException("调用返回为空").printStackTrace();
return;
}
String code = (String) info.get("return_code");
String msg = (String) info.get("return_msg");
if (code == null || !code.equals("SUCCESS")) {
new RuntimeException("调用返回非成功信息,return_msg:" + msg + " ").printStackTrace();
return ;
}
}
});
}
}
(3)AAR日志自定义(setLog) 非常规接口
public void setLog(WxLog log);
请求参数:
传入WxLog的实现
返回参数:
无
示例
private void setLog() {
WxLog logImpl = new WxLog() {
@Override
public void d(String tag, String msg) {
//可使用服务商自己的日志输出
}
@Override
public void i(String tag, String msg) {
//可使用服务商自己的日志输出
}
@Override
public void e(String tag, String msg) {
//可使用服务商自己的日志输出
}
@Override
public void e(String tag, String msg, Throwable e) {
//可使用服务商自己的日志输出
}
};
WxPayFace.getInstance().setLog(logImpl);
}
# 3.10 终端标准流程
(1)设备运行机制
定期重启机制一定要有,避免因ROM或者商户APP或者支付SDK运行太长时间导致突发异常,建议凌晨非高峰期可以自行重启一次(推荐时间凌晨1:00-3:00,将凌晨1:00前作为升级时间)。
(2)获取支付凭证去后台扣款流程
A、建议UI上明确区分在线模式和断网模式,只有极端网络情况才运行断网模式,常规网络都要走在线模式;
B、在线模式是在用户点击确认后,必须后台扣款成功才能展示成功结果,坏账率低,无需和支付侧对接扣款失败和垫资问题;
C、断网模式是在用户点击确认后,后台可以延后扣款,终端拿到支付凭证并且商户确认可以扣款就能展示成功结果,因为未经过后端风控,可能导致坏账、扣款失败和垫资问题;
D、获取用户信息后,获取支付凭证和用户点击确认流程可以并行,从而优化支付耗时。
(3)预览绑定流程
A、绑定surfaceview推荐全局使用同一个示例;
B、绑定最佳时机为surfaceview不会再发生大小改变或者隐藏的时刻,避免需要动态适配;
C、可以手动removeSurfaceview,重新绑定也会自动进行remove。
(4)识别&支付流程
默认流程成功:
取消订单(用户希望取消/结束流程):
页面跳转可能的异化流程
开始识别->停止识别->完成识别->获取支付凭证->开始识别->完成识别->停止识别->获取支付凭证
关闭摄像头渲染和识别时机
A、停止识别;
B、完成识别;
C、获取支付凭证;
D、开始识别(会停掉前一次识别)。
清除上一次识别数据时机
A、完成识别(仅限失败);
B、获取支付凭证(不论成功失败)。
“停止识别”和“清除当前识别数据”
停止识别作用只是停止摄像头渲染和识别,并不会清除掉上次的数据,可以在任何阶段调用,标准的结束必须以获取支付凭证为结尾。
A、调用“开始识别”会自动清除当前识别数据,并停止识别再启动识别,如果成功会直接停止识别;
B、调用“停止识别”只停止当前识别,不清除当前识别数据;
C、调用“完成识别”失败会清理上次识别数据,成功不做处理;
D、调用“获取凭证”不论成功失败都会直接停止当前识别并清理识别数据。
# 3.11 常见问题
(1)刷脸SDK仅用于识别,支付环节默认走非微信支付渠道
需要保证获取支付凭证接口被调用,保证真实金额传入获取支付凭证,可以用金额0去后台对当前支付凭证的安全性进行验证,保证支付流程完善。
(2)初始化提示“初始化失败”
A、检查对应的release调用时机,不要太频繁的release,每次release后初始化耗时较长;
B、调用其它API都依赖初始化成功后再操作,如果初始化未完成就调用任意非初始化API,就会提示该问题,碰上这两类错误码,只需要重试初始化即可。
(3)K12UserInfo和UserInfo的keep问题
AAR对返回的json字符串做了类型封装,本质上新旧AAR对apk的调用都没有异常,这里商户app升级后使用新版aar需要简单调整下对应的userinfo类型,并且在proguard里 -keep class com.tencent.wxpayface.data.UserInfo{ *; };
(4)parcelable exception 空指针
注意对err_code判空,不能直接转换为int,而应该使用Integer,否则会导致支付SDK无响应。
(5)摄像头温度过热问题
优先保证摄像头常开,保证体验;如果散热问题特别严重,可以尝试连续一段时间比如10分钟内没有识别,调用stopCamera,下一次启动识别耗时会变长,但是可以缓解散热问题。
(6)认证失败问题
认证失败可能出现在任意请求之内,如果出现新获取的authinfo无法调用,请检查机器时间,原则上机器时间应与网络时间同步。
(7)第一次调用摄像头或者其它api耗时超长
获取authinfo启动app后,第一次识别需要加载识别相关资源,可以提前调用preloadSdkEnv来提前预启动,保证第一次识别速度很快。
(8)商户识别流程设计
尽可能保证时序串行,避免出现重复扣款情况。
注意:商户可以按需求设计,比如不允许同人同金额10s内支付等逻辑。
(9)现场用户需要弯腰踮脚
建议将预览画面按照长宽比3:4来实现,方便用户最大范围进行识别,避免出现用户脸不在预览画面中心,误以为不能识别,其实可以识别的情况。
(10)数据库初始化失败271378588错误
A、部分设备可能重启或者运行时间久后,设备读写速度变慢,建议开机重启后延迟一段时间,比如5s再进行init,避免时序紊乱;
B、不要频繁地调用release,release后需要重新环境初始化,导致耗时增加,可能出现该错误。
(11)双胞胎算法不能区分问题
A、双胞胎不需要区分
绑定相同⼿机号、微信号,系统会默认合并到和现场照更相似的用户身份进⾏扣款。
B、双胞胎需要区分
绑定不同⼿机号、微信号,系统会提示需要输入手机号验证,从⽽区分当前身份。
# 4. 后台接口
更新记录
版本 | 简要说明 | 修改日期 |
---|---|---|
1.0 | 1. 查询结构支持机构名查询 2. 调整扣款接口,改为同步模式 3. 调整获取SDK鉴权信息方式 | 2019/8/5 |
1.1 | 查询用户信息增加签约状态返回 | 2019/8/8 |
1.2 | 增加流程图 | 2019/8/11 |
1.3 | 1. 增加敏感字段列表 2. GetUser接口调整字段名称 3. class修改为class_name 4. 其它 | 2019/8/28 |
1.4 | 增加联调环境说明 | 2019/8/28 |
1.5 | 更正url | 2019/8/28 |
1.6 | 所有参数中的mch_code改成mchid | 2019/8/31 |
1.7 | 扣款接口增加business_info参数 | 2019/9/4 |
1.8 | 增加商户主动解约接口。解约后,刷脸用户将无法支付,除非重新签约 | 2020/1/19 |
1.9 | 增加测试环境配置方法 | 2020/4/2 |
2.0 | 增加企业食堂和K12调用说明 | 2020/4/10 |
2.1 | 增加支持分账的扣款接口 | 2020/8/14 |
2.2 | 用户查询接口、预签约接口修改,增加按照签约ID查询签约信息接口 | 2020/9/28 |
2.3 | 增加还款小程序跳转协议 | 2020/11/5 |
2.4 | 扣款接口新增是否为垫资,新增查单接口 | 2020/11/13 |
2.5 | 接口5扣款接口标记为删除 | 2020/11/25 |
2.6 | 将机构管理相关接口列为待下线状态,建议服务商通过商户平台管理机构 | 2021/3/22 |
2.7 | 扣款接口新增error_type | 2021/4/21 |
2.8 | 上线新版authinfo接口 | 2021/5/20 |
2.9 | 上线获取还款链接接口 | 2021/6/22 |
3.0 | 下掉旧扣款接口 | 2021/8/31 |
名词定义
● 商户后台系统:商户侧后台处理系统。
● 商户刷脸APP:商户侧的刷脸支付APP。
● 商户小程序:商户提供给用户的小程序。
● 微信刷脸后台系统:微信侧刷脸后台处理系统。
● 微信离线刷脸SDK:微信侧提供的刷脸识别SDK。
● 微信刷脸小程序:微信侧提供的小程序,用户刷脸用户开通、签约等操作。
● 刷脸用户:刷脸消费用户。如学生、教职工。
● 支付用户:实际支付的用户,如家长、教职工。
● 收银员:负责收款的人或机器。
● 机构:学校、公司等都是机构,当前以机构为单位维护人脸特征库。
● out_user_id:刷脸用户标识,需要商户保证同一个刷脸用户在一个机构下唯一,不要给同一个用户创建多个out_user_id,否则可能导致用户无法识别,目前限制同一个微信号不允许绑定同一个机构下多个同名用户。
● user_id:刷脸用户标识,微信侧生成。
● organization_id:机构唯一标识,一个机构下的所有用户的人脸特征组成了该机构对应的人脸特征库。
● face_feature_version:人脸特征版本。由于算法升级,不同版本的识别算法提取的人脸特征会有差异。
业务流程
微信离线人脸APP调用凭证获取
参考获取authinfo接口。
商户录入刷脸用户流程
目前录入刷脸用户有如下入口,分别为:
(1)商家统一采集学生信息,家长签约时则无需录入照片。
(2)家长签约时录入照片。
(3)重新采集时更换学生照片。
扣款流程
扣款流程为同步接口,获取扣款相关参数请参考微信离线人脸APP接入文档。
错误码和错误提示
当请求处理失败时,除了HTTP状态码表示错误之外,API将在消息体返回错误相应说明具体的错误原因。
错误字段列表为:
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
错误码 | code | string(32) | 是 | PARAM_ERROR | / |
错误描述 | message | string(512) | 是 | 参数错误 | / |
code列表:
状态码 | 描述 |
SIGN_ERROR | 签名错误 |
INVALID_REQUEST | 无效请求 |
签名
所有接口调用均需要签名,请点击签名方法进行查阅。
字段有效性规定
字段名 | 含义 | 约束 | 示例 |
out_user_id | 商户侧生成,刷脸用户唯一标识 | 1. 商户ID下全局唯一; 2. 只能包含字母、数字; 3. 长度不超过50字节。 | FEX868felix3 |
user_id | 微信侧生成,刷脸用户唯一标识 | 1. 商户ID下全局唯一; 2. 必须为字母数字的组合; 3. 长度不超过50字节。 | FEX868felix3 |
organization_name | 机构名称,商户定义 | 1. 合法的UTF8字符串; 2. 长度不超过60字节。 | 深圳市宝安区铁岭第一高级中学 |
organization_id | 微信侧生成,机构唯一标识 | 1. 必须为字母数字的组合; 2. 长度不超过50字节。 | LIJX868felix3 |
user_name | 用户姓名 | 1. 合法的UTF8字符串; 2. 长度不超过50字节。 | 张三四 李王五 |
class_name | 班级名 | 1. 合法的UTF8字符串; 2. 长度不超过50字节。 | 高三五班 |
occupation | 职业 | 1. 合法的UTF8字符串; 2. 长度不超过50字节。 | 工程师 教师 |
敏感字段列表
根据微信APIv3的要求,所有敏感信息经网络传输需要进行二次加密,加密方法请参考《敏感信息加解密》。
敏感字段列表如下:
字段名 | 含义 |
user_name | 用户姓名 |
下面将不再单独对每个字段进行说明。
测试环境联调方法
注意测试环境不保证服务可用性,因此仅在特殊情况下使用与微信侧进行联调,其他非必要场景请不要使用测试环境,使用前请与微信侧确认测试环境可用,配置方法如下,任选其一即可,不可同时配置:
方法一:HTTP代理模式,139.199.171.252:8089
方法二:HOST模式,183.3.224.148 api.mch.weixin.qq.com
接口列表
# 4.1 查询机构信息接口
机构申请请点击参考《学校机构ID申请说明》。
接口定义
根据organization_id查询机构信息:
GET https://api.mch.weixin.qq.com/v3/offlinefacemch/organizations?organization_id=xxx
根据organization_name查询机构信息:
GET https://api.mch.weixin.qq.com/v3/offlinefacemch/organizations?organization_name=url_encode(name)
请求参数
无
返回结果
状态码 | 描述 |
200 | 成功 |
其他 | 失败 |
状态为200时:
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
机构ID | organization_id | string(50) | 是 | DBES323aeb | 机构唯一ID,由数字、字母组成 |
机构名称 | organization_name | string(50) | 是 | 南山中兴小学部 | 机构名称 |
# 4.2 获取授权凭证接口
授权凭证用与拉起小程序、H5等。
token有效期为5分钟,在商户小程序跳转签约小程序时获取,不要提前获取。
集中采集时建议使用该接口。
用户签约时建议使用预签约接口。
接口定义
POST https://api.mch.weixin.qq.com/v3/offlinefacemch/tokens
请求参数
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
使用场景 | scene | string(32) | 是 | WEBSESSION | 颁发的授权凭证将要使用的场景; WEBSESSION:小程序调用凭证。 |
小程序/h5鉴权场景初始化数据 | web_init_data | object | 否 | / | 小程序/h5鉴权场景初始化数据; scene等于WEBSESSION时必填。 |
web_init_data:
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
商户刷脸用户ID | out_user_id | string(50) | 是 | 123456 | 商户侧刷脸用户ID,只能包含字母、数字。同一个商户下,该值必须唯一。 |
机构ID | organization_id | string(50) | 是 | DBES323aeb | 机构唯一ID,由数字、字母组成。 |
返回结果
状态码 | 描述 |
200 | 成功 |
其它 | 失败 |
状态码为200时,结果参数为:
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
授权凭证 | token | string(50) | 是 | TKeinf3345ABC | 由字母数字组成。 |
# 4.3 刷脸用户信息查询接口
接口定义
GET https://api.mch.weixin.qq.com/v3/offlinefacemch/organizations/{organization_id}/users/out-user-id/{out_user_id}
请求参数
无
返回结果
状态码 | 描述 |
200 | 成功 |
其它 | 失败 |
状态码为200时,返回如下字段:
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
刷脸用户ID | user_id | string(50) | 是 | 34fdeEFGFE | 微信侧刷脸用户唯一ID |
商户刷脸用户ID | out_user_id | string(50) | 是 | 123456 | 商户侧刷脸用户ID,只能包含字母、数字。同一个商户下,该值必须唯一 |
机构ID | organization_id | string(50) | 是 | DBES323aeb | 机构唯一ID,由数字、字母组成 |
姓名 | user_name | string(32) | 是 | 张三 | 姓名 |
用户类型 | user_type | string(16) | 是 | STUDENT | 学生:STUDENT 职工:STAFF |
学生信息 | student_info | object | 否 | 详细见下文 | user_type为STUDENT时必填,字段见下文 |
职工信息 | staff_info | object | 否 | 详细见下文 | user_type为STAFF时必填,字段见下文 |
用户状态 | status | string(16) | 是 | NORMAL | 1. NOMAL:正常状态 2. DISABLED:禁用状态,此时支付被限制 |
签约状态 | contract_state | string | 是 | CONTRACTED | NOT_CONTRACTED:未签约 TERMINATED:已解约 CONTRACTED:已签约 |
人脸图片上传状态 | face_image_ok | bool | 是 | true false | 用户采集的照片 |
签约ID | contract_id | string | 否 | / | 用户已签约/已解约时存在 |
student_info:
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
班级名 | class_name | string(64) | 是 | 三年级二班 | 班级名 |
staff_info:
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
职业 | occupation | string(64) | 是 | 教职工 | 用户职业信息 |
# 4.4 刷脸用户信息修改接口
接口定义
PATCH https://api.mch.weixin.qq.com/v3/offlinefacemch/organizations/{organization_id}/users/out-user-id/{out_user_id}
请求参数
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
姓名 | user_name | string(32) | 是 | 张三 | 姓名,加密上传 |
用户类型 | user_type | string(16) | 是 | STUDENT | 学生:STUDENT 职工:STAFF 注意:企业食堂该值固定为STAFF。 |
学生信息 | student_info | object | 否 | 详情见下文 | user_type为STUDENT时必填,字段见下文。 |
职工信息 | staff_info | object | 否 | 详情见下文 | user_type为STAFF时必填,字段见下文。 |
状态 | status | string | 否 | NORMAL | 1、"NORMAL":正常状态; 2、"DISABLED":禁用,后续刷脸用户将无法消费。 |
手机号 | phone | string | 否 | 136xxxxxxxx | 手机号,加密上传 |
返回结果
状态码 | 描述 |
204 | 成功 |
其它 | 失败 |
# 4.5 获取authinfo接口
注意:建议authinfo每1小时内获取一次。
接口定义
POST https://api.mch.weixin.qq.com/v3/offlineface/authinfo
请求参数
字段名 | 变量名 | 类型 | 必填 | 示例 | 说明 |
服务商appid | sp_appid | string | 是 | 示例值: wx369ab4160391b078; 字符长度限制: [1, 32] | 商户appid |
子appid | sub_appid | string | 有则必传 | 示例值: wx369ab4160391b078; 字符长度限制: [0, 32] | 子商户APPID |
子商户号 | sub_mchid | string | 是 | 示例值: 1900000109; 字符长度限制: [0, 32] | 子商户号 |
设备id | device_id | string | 是 | 示例值: TXAP12029003744ND002112; 字符长度限制: [1, 32] | 终端设备唯一ID,必须为数字、字母、下划线的组合 |
原始数据 | raw_data | string | 是 | 示例值: kh5HJYlzqXosbqJCOYXASBxYozukRFjg5P9MY; 字符长度限制: [1, 2048] | 初始化数据,由微信人脸SDK的接口返回 |
机构id | organization_id | string | 是 | 示例值: OCAABBDDee; 字符长度限制: [1, 64] | 机构ID,注意创建机构的商户号和mch_id应该保持一致 |
返回结果
状态码 | 错误码 | 错误说明 |
200 | 请求正确处理 | 获取authinfo成功 |
500 | SYSTEM_ERROR | 请稍后重试 |
400 | PARAM_ERROR | 参数错误,请检查参数 |
400 | INVALID_REQUEST | 表示请求参数符合格式,但不符合业务规则 |
429 | RATELIMIT_EXCEEDED | 请求达到速率限制 |
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
授权信息 | authinfo | string | 是 | 示例值: kh5HJYlzqXosbqJCOYXASBxYozukRFjg5P9MY; 字符长度限制: [1, 4096] | SDK调用凭证,用于调用SDK的人脸识别接口 |
# 4.6 解除刷脸用户签约关系接口
接口定义
POST https://api.mch.weixin.qq.com/v3/offlinefacemch/organizations/{organization_id}/users/user-id/{user_id}/terminate-contract
请求参数
无
返回结果
状态码 | 描述 |
204 | 成功 |
其它 | 失败 |
# 4.7 预签约接口
接口定义
POST https://api.mch.weixin.qq.com/v3/offlineface/contracts/presign
用户能够扣款的前提是已经完成签约操作,签约流程如下:
A、用户在商户小程序发起签约;
B、商户调用该接口进行预签约,该接口会返回presign_token;
C、商户小程序携带presign_token跳转到微信侧人脸小程序,用户在微信侧人脸小程序完成签约操作。
注意:
a、一键绑卡不是支持所有银行卡,上线前请先测试是否支持该银行卡;
b、建议上线前一周完成调试;
c、签约完成务必多次扣款,防止由于银行限制每日扣款次数、扣款金额等影响用户消费;
d、指定卡签约建议异步扣款,否则银行维护会导致不能扣费,影响学生吃饭;
e、presign_token有效期为5分钟,在商户小程序跳转签约小程序时获取,不要提前获取。
请求参数
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
业务类型 | business_name | string | 是 | K12 | K12、GROUP_DINING |
刷脸用户信息 | facepay_user | object | 是 | 张三 | 刷脸用户信息 |
签约指定银行卡 | limit_bank_card | object | 否 | xxxxx | 签约绑定指定卡 |
签约模式 | contract_mode | string | 否 | LIMIT_BANK_CARD | LIMIT_BANK_CARD:指定卡签约; PRIORITY_BANK_CARD:优先卡签约; LIMIT_NONE:任意卡签约 |
facepay_user:
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
商户用户ID | out_user_id | string | 是 | 123456 | 商户侧对用户唯一标识 |
刷脸用户名 | identification_name | string | 否 | 张三 | 按照APIV3规范加密 |
机构ID | organization_id | string | 是 | DBES323aeb | 机构id |
证件信息 | identification | object | 否 | IDCARD | identification_type支持IDCARD、EEP_HK_MACAU、PASSPORT_NO |
手机号码 | phone | string | 否 | xxxxxx | 按照APIV3规范加密 |
limit_bank_card:
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
银行卡号 | bank_card_number | string | 是 | xxxxx | 按照APIV3规范加密 |
开卡人姓名 | identification_name | string | 是 | 张三 | 按照APIV3规范加密 |
开卡人证件 | identification | object | 是 | xxxxx | identification_type固定值:IDCARD |
银行卡有效期 | valid_thru | string | 否 | 08/21 | 格式mm/yy,仅部分银行需要 |
银行类型 | bank_type | string | 否 | 工商银行 | 强烈建议填写,采用字符串类型的银行标识,值列表详见银行类型 |
开卡预留手机号 | phone | string | 否 | xxxxx | 建议填写,按照APIV3规范加密 |
identification:
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
证件类型 | identification_type | string | 是 | IDCARD | 固定值:IDCARD |
证件ID | identification_number | string | 是 | xxxxx | 数字字母组成,按照APIV3规范加密 |
返回结果
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
会话id | presign_token | string(64) | 是 | xxxxx | 跳转小程序携带 |
# 4.8 申请扣款接口
接口定义
POST https://api.mch.weixin.qq.com/v3/offlineface/transactions
请求参数
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
支付凭证 | auth_code | string | 是 | 示例值: fewjfwoe3323wwxxxxxxxxx | 由刷脸SDK返回,作为唯一扣款凭证 |
服务商公众号appid | sp_appid | string | 是 | 示例值: wx333333333333333 字符字节限制: [0, 32] | 服务商公众号appid |
服务商商户号 | sp_mchid | string | 是 | 示例值: 198798777 字符字节限制: [0, 32] | 服务商商户号 |
子商户公众号appid | sub_appid | string | 否 | 示例值: wx3333333333 字符字节限制: [0, 32] | 子商户公众号appid |
子商户商户号 | sub_mchid | string | 是 | 示例值: 3233122121 字符字节限制: [0, 32] | 子商户号 |
金额信息 | amount | object | 是 | 示例值: 3 | 金额,单位:分 |
支付场景信息 | scene_info | object | 是 | 详情见下表 | 详情见下表 |
优惠标记 | goods_tag | string | 否 | 示例值: xtedx | 优惠标记 |
商品信息 | description | string | 是 | 示例值: XX小学午餐, XX中学惠客隆超市 字符字节限制: [0, 128] | 商品信息,长度不大于128 |
商品附加信息 | attach | string | 是 | 示例值: id=xxx 字符字节限制: [0, 128] | 商品附加描述,长度不大于128 |
结算信息 | settle_info | object | 否 | 示例值: false | 详情见下表 |
商户订单号 | out_trade_no | string | 是 | 示例值: IDXfewfe3 字符字节限制: [0, 32] | 长度不大于32 |
业务信息 | business | object | 是 | 详情见下表 | 详情见下表 |
amount定义如下:
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
总金额 | total | int64 | 是 | 示例值: 100 值限制: 1 ≤ value ≤ 1000000000 字符字节限制: [1, 10] | 订单总金额,单位分,只能为整数 |
货币类型 | currency | string(16) | 是 | 示例值: CNY 字符字节限制: [0, 16] | 符合ISO 4217标准的三位字母代码,目前仅支持人民币:CNY |
scene_info定义如下:
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
设备IP | device_ip | string | 是 | 示例值: 8.8.8.8 字符字节限制: [0, 45] | 设备IP |
business定义如下:
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
平台产品ID | business_product_id | int | 是 | 示例值: 2 | 2:K12项目 11:企业团餐 |
平台场景ID | business_scene_id | int | 是 | 示例值: 3 | K12可选: ● 3 食堂 ● 4 超市 ● 5 校医院 ● 6 K12测试场景 企业团餐可选: ● 124 团餐测试 ● 125 企业食堂 ● 126 腾讯食堂 |
settle_info定义如下:
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
是否支持分账 | profit_sharing | bool | 否 | 示例值: false | 分账使用 |
返回结果
状态码 | 描述 |
200 | 处理成功 |
其它 | 失败 |
状态码为200时:
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
服务商公众号appid | sp_appid | string | 是 | 示例值: wx333333333333333 字符字节限制: [0, 32] | 服务商公众号appid |
服务商商户号 | sp_mchid | string | 是 | 示例值: 198798777 字符字节限制: [0, 32] | 服务商商户号 |
子商户公众号appid | sub_appid | string | 否 | 示例值: wx3333333333 字符字节限制: [0, 32] | 子商户公众号appid |
子商户商户号 | sub_mchid | string | 是 | 示例值: 3233122121 字符字节限制: [0, 32] | 子商户号 |
支付用户信息 | payer | object | 否 | 详情见下表 | 详情见下表 |
金额信息 | amount | object | 否 | 详情见下表 | 详情见下表 |
优惠信息 | promotion_detail | array | 否 | 暂无 | 暂不支持,可不关注 |
支付场景信息 | scene_info | object | 否 | 暂无 | 与请求信息定义相同 |
付款银行 | bank_type | string | 否 | 示例值: 招商银行 字符字节限制: [0, 16] | 用户扣款银行信息 |
交易类型 | trade_type | string | 否 | 示例值: NATIVE, JSAPI, APP, MWEB 字符字节限制: [0, 16] | 支付成功才返回 "AUTH" - 行业代扣 |
交易状态 | trade_state | string | 是 | 示例值: SUCCESS 字符字节限制: [0, 32] | 支付成功才返回 “SUCCESS” - 支付成功(支付成功无需处理) “REFUND" - 转入退款(支付成功无需处理) “NOTPAY” - 未支付(重试扣款) “CLOSED" - 已关闭(换单号重试) “REVOKED” - 已撤销(换单号重试) “USERPAYING” - 用户支付中(重试扣款) “PAYERROR” - 支付失败(换单号重试) |
交易描述 | trade_state_description | string | 是 | 示例值: 支付失败,请重新下单支付 字符字节限制: [0, 256] | 订单交易状态 |
欠款状态 | debt_state | string | 是 | 示例值: DEBT | NOT_DEBT:无欠款(无垫资) DEBT:有欠款(垫资支付) REPAYMENT:(已还款) |
商品信息 | description | string | 否 | 示例值: 初级中学午餐 字符字节限制: [0, 128] | 商品信息 |
商户附加信息 | attach | string | 否 | 示例值: id=1 字符字节限制: [0, 128] | 商品附加描述,长度不大于128 |
支付成功时间 | success_time | string | 否 | 示例值: 2015-05-20T13:29:35.120+08:00 字符字节限制: [0, 32] | 使用ISO 8601所定义的格式: |
微信订单号 | transaction_id | string | 否 | 示例值: 4200032343298099898 字符字节限制: [0, 32] | 支付成功才返回 |
还款微信订单号 | repayment_transaction_id | string | 否 | 示例值: 1217752501201407033233368018 字符字节限制: [0, 32] | 订单为垫资支付且用户已还款时产生的微信交易订单号,当欠款单状态为REPAYMENT时返回 |
商户订单号 | out_trade_no | string | 是 | 示例值: 1217752501201407033233368018 字符字节限制: [0, 32] | 商户订单号 |
错误分类 | error_type | string | 否 | / | trade_state为PAYERROR时存在,“NOT_ENOUGH”和“NOTENOUGH”表示用户余额不足 |
payer定义如下:
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
公众下的openid | sp_openid | string | 否 | 示例值: fefewfwe 字符字节限制: [0, 128] | 付款用户信息 |
子公众下的openid | sub_openid | string | 否 | 示例值: fefewfwe 字符字节限制: [0, 128] | 付款用户信息 |
amount定义如下:
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
订单金额 | total | int64 | 是 | 示例值: 3 | 金额,单位:分 |
用户支付金额 | pay_total | int64 | 是 | 示例值: 3 | 金额,单位:分 |
货币类型 | currency | string | 是 | 示例值: CNY | 货币类型,目前只支持人民币 |
用户支付货币类型 | pay_currency | string | 是 | 示例值: CNY | 货币类型,目前只支持人民币 |
返回码处理建议:
httpcode | 错误码 | 处理方式 |
200 | 请求正确处理,应该判断订单状态 | “SUCCESS” - 支付成功(支付成功无需处理) “REFUND”-转入退款(支付成功无需处理) “NOTPAY”-未支付(24小时内参数不变重试扣款) “CLOSED”-已关闭(参数不变换单号重试) “REVOKED”-已撤销(参数不变换单号重试) “USERPAYING”-用户支付中(24小时内参数不变重试扣款) “PAYERROR”-支付失败(换单号重试) |
500 | SYSTEM_ERROR | 请稍后重试,建议同一笔订单每天重试不要超过5次,频繁重试会导致该用户无法扣款 |
400 | PARAM_ERROR | 参数错误,请检查参数 |
400 | INVALID_REQUEST | 目前子商户未开通权限、凭证已经使用过并且扣款成功、请求参数和凭证信息不一致、凭证正在扣款又换单号重试、重入请求变更了参数都会返回该错误码,表示请求参数符合格式,但不符合业务规则,需要服务商定位问题并修正代码 |
429 | RATELIMIT_EXCEEDED | 请求达到速率限制 |
# 4.9 签约查询接口
根据签约id查询签约信息。
接口定义
GET https://api.mch.weixin.qq.com/v3/offlineface/contracts/{contract_id}?appid=XXXX
请求参数
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
签约id | contract_id | string | 是 | 示例值: CI8CD208Z7e9906f89 | 签约回调通知、用户查询接口返回签约ID |
appid | appid | string | 否 | 示例值: wx8888888888 | 必须和商户号有绑定关系,建议扣款接口、商户签约小程序和该字段保持一致 |
返回结果
状态码 | 描述 |
200 | 成功 |
其它 | 失败 |
状态码为200时,结果参数为:
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
签约ID | contract_id | string | 是 | 示例值: wx88888888 字符字节限制: [0, 64] | 用户签约ID |
商户号 | mchid | string | 是 | 示例值: 2480278041 字符字节限制: [0, 32] | 允许扣款商户号 |
机构id | organization_id | string | 是 | 示例值: OAABBCCDDeeff 字符字节限制: [0, 64] | 机构唯一ID,由数字、字母组成 |
用户id | user_id | string | 是 | 示例值: FU40F305Z4e2bb7d 字符字节限制: [0, 64] | 刷脸用户ID |
签约用户openid | openid | string | 否 | 示例值: AFDSJfhdf8744 字符字节限制: [0, 128] | 传入appid时返回,扣款微信号对应openid |
签约状态 | contract_state | string | 是 | 示例值: CONTRACTED 字符字节限制: [0, 32] | 已签约:CONTRACTED 未签约:NOT_CONTRACTED 已解约:TERMINATED |
签约时间 | contract_signed_time | string | 是 | 示例值: 2018-06-08T10:34:56+08:00 字符字节限制: [0, 32] | 签约时间 |
解约时间 | contract_terminated_time | string | 否 | 示例值: 2018-06-08T10:34:56+08:00 字符字节限制: [0, 32] | 解约时间,已解约时返回 |
签约模式 | contract_mode | string | 是 | 示例值: PRIORITY_BANK_CARD 字符字节限制: [0, 32] | LIMIT_BANK_CARD:指定卡签约; PRIORITY_BANK_CARD:优先卡签约; LIMIT_NONE:任意卡签约 |
签约卡来源 | contract_bank_card_from | string | 是 | 示例值: MERCHANT_LIMITED_BANK_CARD 字符字节限制: [0, 64] | MERCHANT_LIMITED_BANK_CARD:商户指定的签约卡; USER_SELECT_FREE:用户选择的签约卡。 |
# 4.10 签约状态变更回调通知(签约、解约都会回调)
能力背景
服务商为学校开发基于师生的用户管理体系时,需要维护用户的采集和签约状态,并同步至刷脸设备。目前,服务商只能获取用户签约信息,不能获取用户解约信息,导致服务商无法维护用户状态,影响用户正常使用。
能力简介
刷脸用户在完成签约或解约后,微信会通知商户用户签约状态变更。商户需要接收处理,并返回应答。
具体开发内容请点击《离线刷脸签约状态变更回调》进行查阅。
接入流程
详情接入请见《申请用户解约通知申请表》。
接入周期
每周五12:00截止本周配置信息收集,并在下个工作日上午12:00前配置完成。
# 4.11 还款小程序跳转协议
appid:wxa834b152dd018e25
path:pages/index/index?business_product_id=XXXX(2表示K12,11表示企业团餐)
# 4.12 查询重采请求接口
离线刷脸业务中,偶尔会出现前期采集头像质量不高,导致算法升级后,旧的头像无法生成有效的人脸特征,影响用户使用刷脸服务。因此,需要对用户的头像进行重采。
接口定义
GET https://api.mch.weixin.qq.com/v3/offlineface/face-collections/{collection_id}。
请求参数
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
重采ID | collection_id | string | 是 | 示例值: FC2353ZJIHOJKHOIIOI; 字符字节限制: [0, 64] | 微信侧为人脸重采生成的唯一请求ID |
返回结果
状态码 | 描述 |
200 | 成功 |
404 | 重采ID不存在, 说明不需要重采 |
状态码为200时,结果参数为:
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
重采ID | collection_id | string | 是 | 示例值: FC2353ZJIHOJKHOIIOIJ 字符字节限制: [0, 64] | 微信侧为人脸重采生成的唯一请求ID |
刷脸用户ID | user_id | string | 是 | 示例值: FUxxxxxxxxxx 字符字节限制: [0, 64] | 刷脸用户ID |
机构ID | organization_id | string | 是 | 示例值: Oxxxxfefwefwfewfwe 字符字节限制: [0, 64] | 机构唯一ID,由数字、字母组成 |
重采状态 | collection_state | string | 是 | 示例值: COLLECTION_REQUIRED 字符字节限制: [0, 64] | 合法的重采状态有:COLLECTION_REQUIRED: 该刷脸用户需要进行重采; PHOTO_UPLOADED: 照片已上传; COMPLETE: 支付用户已经确认照片, 重采结束。 |
注册照上传时间 | register_photo_upload_time | string | 否 | 示例值: 2018-05-23T12:13:50+08:00 字符字节限制: [0, 64] | 商户通过集中采集功能或者用户自行采集人脸照片后,照片上传成功的时间。 |
支付用户确认时间 | confirm_time | string | 否 | 示例值: 2018-05-23T12:13:50+08:00 字符字节限制: [0, 64] | 支付用户确认注册照的时间, 用户确认之后, 该注册照将作为人脸识别的底照; 当用户确认注册照后, 重采就全部完成了。 |
# 4.13 查询重采用户列表接口
通过该接口,商户可以获取需要重采的用户列表。 根据该列表,可以安排进入学校进行集中采集或者通知家长配合采集。
采集完成后,通过小程序的重采确认接口,让用户确认重采的人脸照片。
建议商户在收到重采通知后,或者是定时轮询(轮询周期不用太高, 填级别即可),通过该接口获取重采列表, 安排后续工作。
接口定义
GET https://api.mch.weixin.qq.com/v3/offlineface/face-collections?organization_id={organization_id}。
请求参数
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
机构ID | organization_id | string | 是 | 示例值: Ofewewfwefweewf 字符字节限制: [0, 64] | 机构ID |
列表偏移 | offset | uint64 | 是 | 示例值: 30 | 非0整数,该次请求资源的起始位置,从0开始计数。调用方选填,默认为0。 offset需要根据结果集的个数动态调整,当结果集为0时,表明已经拉取完毕了。 |
资源个数 | limit | uint64 | 是 | 示例值: 20 | 非0非负的整数,该次请求可返回的最大资源条数。调用方选填,默认值建议为20。 |
返回结果
状态码 | 描述 |
200 | 成功 |
状态码为200时,结果参数为:
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
重采列表 | face_collections | 数组 | 是 | 详情见下表 | 重采列表为空时, 表明没有更多资源了; 详情见下表。 |
重采列表单个对象结构:
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
重采ID | collection_id | string | 是 | 示例值: FC2353ZJIHOJKHOIIOIJ 字符字节限制: [0, 64] | 微信侧为人脸重采生成的唯一请求ID |
刷脸用户ID | user_id | string | 是 | 示例值: FUxxxxxxxxxx 字符字节限制: [0, 64] | 刷脸用户ID |
机构ID | organization_id | string | 是 | 示例值: Oxxxxfefwefwfewfwe 字符字节限制: [0, 64] | 机构ID |
重采状态 | collection_state | string | 是 | 示例值: COLLECTION_REQUIRED 字符字节限制: [0, 64] | 合法的重采状态有:COLLECTION_REQUIRED: 该刷脸用户需要进行重采; PHOTO_UPLOADED: 照片已上传; COMPLETE: 支付用户已经确认照片, 重采结束。 |
注册照上传时间 | register_photo_upload_time | string | 否 | 示例值: 2018-05-23T12:13:50+08:00 字符字节限制: [0, 64] | 商户通过集中采集功能或者用户自行采集人脸照片后,照片上传成功的时间。 |
支付用户确认时间 | confirm_time | string | 否 | 示例值: 2018-05-23T12:13:50+08:00 字符字节限制: [0, 64] | 支付用户确认注册照的时间, 用户确认之后, 该注册照将作为人脸识别的底照; 当用户确认注册照后, 重采就全部完成了。 |
# 4.14 查单接口
接口定义
GET https://api.mch.weixin.qq.com/v3/offlineface/transactions/out-trade-no/{out_trade_no}?sp_mchid={sp_mchid}&sub_mchid={sub_mchid}&business_product_id={business_product_id}
请求参数
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
商户订单号 | out_trade_no | string | 是 | 示例值: 1217752501201407033233368018 字符字节限制: [0, 32] | 商户订单号 |
服务商商户号 | sp_mchid | string | 是 | 示例值: 198798777 字符字节限制: [0, 32] | 服务商商户号 |
子商户商户号 | sup_mchid | string | 是 | 示例值: 3233122121 字符字节限制: [0, 32] | 子商户号 |
平台产品ID | business_product_id | int | 是 | 示例值: 2 | 2:K12项目 11:企业团餐 |
状态码 | 描述 |
200 | 成功 |
其他 | 失败 |
状态码为200时:body和申请扣款接口一致。
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
服务商公众号appid | sp_appid | string | 是 | 示例值: wx333333333333333 字符字节限制: [0, 32] | 服务商公众号appid |
服务商商户号 | sp_mchid | string | 是 | 示例值: 198798777 字符字节限制: [0, 32] | 服务商商户号 |
子商户公众号appid | sub_appid | string | 否 | 示例值: wx3333333333 字符字节限制: [0, 32] | 子商户公众号appid |
子商户商户号 | sub_mchid | string | 是 | 示例值: 3233122121 字符字节限制: [0, 32] | 子商户号 |
支付用户信息 | payer | object | 否 | 详情见下表 | 详情见下表 |
金额信息 | amount | object | 否 | 详情见下表 | 详情见下表 |
优惠信息 | promotion_detail | array | 否 | 暂无 | 暂不支持,可不关注 |
支付场景信息 | scene_info | object | 否 | 暂无 | 与请求信息定义相同 |
付款银行 | bank_type | string | 否 | 示例值: 招商银行 字符字节限制: [0, 16] | 用户扣款银行信息 |
交易类型 | trade_type | string | 否 | 示例值: NATIVE, JSAPI, APP, MWEB 字符字节限制: [0, 16] | 支付成功才返回 "AUTH" - 行业代扣 |
交易状态 | trade_state | string | 是 | 示例值: SUCCESS 字符字节限制: [0, 32] | 支付成功才返回 “SUCCESS”-支付成功(支付成功无需处理); “REFUND”-转入退款(支付成功无需处理); “NOTPAY”-未支付(重试扣款); “CLOSED”-已关闭(换单号重试); “REVOKED”-已撤销(换单号重试); “USERPAYING”-用户支付中(重试扣款); “PAYERROR”-支付失败(换单号重试)。 |
交易描述 | trade_state_description | string | 是 | 示例值: 支付失败,请重新下单支付 字符字节限制: [0, 256] | 订单交易状态 |
欠款状态 | debt_state | string | 是 | 示例值: DEBT | NOT_DEBT:无欠款(无垫资); DEBT:有欠款(垫资支付); REPAYMENT:(已还款) |
商品信息 | description | string | 否 | 示例值: 初级中学午餐 字符字节限制: [0, 128] | 商品信息 |
商户附加信息 | attach | string | 否 | 示例值: id=1 字符字节限制: [0, 128] | 商品附加描述,长度不大于128 |
支付成功时间 | success_time | string | 否 | 示例值: 2015-05-20T13:29:35.120+08:00 字符字节限制: [0, 32] | 使用ISO 8601所定义的格式 |
微信订单号 | transaction_id | string | 否 | 示例值: 4200032343298099898 字符字节限制: [0, 32] | 支付成功才返回 |
还款微信订单号 | repayment_transaction_id | string | 否 | 示例值: 1217752501201407033233368018 字符字节限制: [0, 32] | 订单为垫资支付且用户已还款时产生的微信交易订单号,当欠款单状态为REPAYMENT时返回 |
商户订单号 | out_trade_no | string | 是 | 示例值: 1217752501201407033233368018 字符字节限制: [0, 32] | 商户订单号 |
payer定义如下:
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
公众下的openid | sp_openid | string | 否 | 示例值: fefewfwe 字符字节限制: [0, 128] | 付款用户信息 |
子公众下的openid | sub_openid | string | 否 | 示例值: fefewfwe 字符字节限制: [0, 128] | 付款用户信息 |
amount定义如下:
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
订单金额 | total | int64 | 是 | 示例值: 3 | 金额,单位:分 |
用户支付金额 | pay_total | int64 | 是 | 示例值: 3 | 金额,单位:分 |
货币类型 | currency | string | 是 | 示例值: CNY | 货币类型,目前只支持人民币 |
用户支付货币类型 | pay_currency | string | 是 | 示例值: CNY | 货币类型,目前只支持人民币 |
返回码处理建议:
httpcode | 错误码 | 处理方式 |
200 | 请求正确处理,应该判断订单状态 | “SUCCESS”-支付成功(支付成功无需处理) “REFUND”-转入退款(支付成功无需处理) “NOTPAY”-未支付(24小时内参数不变重试扣款) “CLOSED"-已关闭(参数不变换单号重试) “REVOKED”-已撤销(参数不变换单号重试) “USERPAYING”-用户支付中(24小时内参数不变重试扣款) “PAYERROR”-支付失败(换单号重试) |
500 | SYSTEM_ERROR | 请稍后重试,建议同一笔订单每天重试不要超过5次,频繁重试会导致该用户无法扣款 |
400 | PARAM_ERROR | 参数错误,请检查参数 |
400 | INVALID_REQUEST | 目前子商户未开通权限、凭证已经使用过并且扣款成功、请求参数和凭证信息不一致、凭证正在扣款又换单号重试、重入请求变更了参数都会返回该错误码,表示请求参数符合格式,但不符合业务规则,需要服务商定位问题并修正代码 |
429 | RATELIMIT_EXCEEDED | 请求达到速率限制 |
# 4.15 获取还款链接接口
接口定义
POST https://api.mch.weixin.qq.com/v3/offlineface/repayment-url
请求参数
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
商户用户ID | out_user_id | string | 是 | 123456 | 欠款用户在商户侧的唯一标识 |
机构ID | organization_id | string | 是 | Obeeeee | 机构id |
返回结果
状态码 | 错误码 | 错误说明 |
200 | 请求正确处理 | 获取authinfo成功 |
500 | SYSTEM_ERROR | 请稍后重试 |
400 | PARAM_ERROR | 参数错误,请检查参数 |
400 | INVALID_REQUEST | 表示请求参数符合格式,但不符合业务规则 |
429 | RATELIMIT_EXCEEDED | 请求达到速率限制 |
字段名 | 变量名 | 类型 | 必填 | 示例 | 描述 |
还款链接 | repayment_url | string | 是 | / | 还款小程序跳转链接,仅支持微信环境下打开 |
链接过期时间 | expire_at | string | 是 | 2021-05-30T12:13:50+08:00 | 还款链接的过期时间,到期后还款链接将无法跳转 |
# 5. 非刷脸交易上报
开发集成后,还需要完成APP里的微信非刷脸交易上报 , 否则会影响审批。