⓪ 实人认证(独立刷脸核验)
不涉及开票的纯身份核验:发一个链接给本人,现场人脸与公安基准照比对 + 手机号短信验证码,两项都过才算通过。司机打卡、领料签收、现场确认这类「每次都要一个独立核验结果」的场景用它。★与②散户入驻的区别:入驻一个人只做一次、拿的是入驻状态;这里每次都是一次新的、独立的核验结果。被认证人不需要有工商银行卡、也不需要在工行开过户。
属「工商银行 · 业务型接口」——底层编排 乐企直联原子接口,你只调这一个。
发起认证
接口 · 发起认证(页面类)
POST https://openapi.kailingteck.com/api/v1/rinv/face/start
鉴权:X-App-Key + X-Timestamp + X-Sign(= sha256(appKey + 时间戳 + 报文 + appSecret))。
请求参数
| 字段 | 必填 | 大白话说明 |
|---|---|---|
outUserId | 必填 | 被认证人在你方的唯一编号(同一个人请长期保持同一个编号,工行以它识别人) |
custName | 必填 | 姓名 |
certNo | 必填 | 身份证号(工行目前仅支持身份证) |
mobile | 必填 | 本人手机号——认证过程中工行会往这个号发短信验证码,填错就做不完 |
jumpUrl | 必填 | 认证成功后页面「确认」按钮的回跳地址(可以带参数,便于你识别是哪次打卡) |
failJumpUrl | 选填 | 认证失败后的回跳地址;不传则与 jumpUrl 相同 |
transNo | 选填 | 本次认证流水号。★工行要求全局唯一、不可重复;不传则平台自动生成一个,建议你自己传业务单号方便对账 |
callbackUrl | 选填 | 你方接收认证结果通知的地址。传了平台就把工行的结果转发给你;不传则只能靠主动查询 |
authScene | 选填 | 工行认证场景字典,不传默认 01 |
请求示例
{
"outUserId": "DRIVER001",
"custName": "张三",
"certNo": "500101199001011234",
"mobile": "13800001234",
"jumpUrl": "https://你的系统/checkin/done?id=8899",
"transNo": "CHECKIN20260923001",
"callbackUrl": "https://你的系统/notify/face"
}返回
所有接口都用同一层信封:code/msg/requestId/timestamp/data。业务字段都在 data 里,下表列的就是 data 的内容。code 为 CYT_00000 表示调用成功。
返回参数(data)
| 字段 | 大白话说明 |
|---|---|
pageUrl | ★把这个地址交给本人在手机上打开,直接 location.href 过去即可——工行的签名和表单由平台代办,你不用处理 |
transNo | 本次认证流水号,查结果、对回调都用它 |
outUserId | 回显 |
返回示例(成功)
{
"code": "CYT_00000",
"msg": "success",
"data": {
"transNo": "CHECKIN20260923001",
"outUserId": "DRIVER001",
"pageUrl": "https://openapi.kailingteck.com/api/v1/icbc/redirect/rxxxx",
"mock": false
}
}异常与报错
| 情形 | 含义与处理 |
|---|---|
| transNo 已被使用过 | 工行要求每次认证流水号全局唯一,换一个新的 |
| 页面打不开摄像头 | 让本人用手机浏览器或微信打开并允许摄像头权限;链接必须整行完整转发,断行丢参数会报错 |
前端怎么用
const r = await post('/api/v1/rinv/face/start', body);
location.href = r.data.pageUrl; // 或把 pageUrl 转成二维码让本人扫★pageUrl 即用即取:链接里含工行签名的时间戳,有时效,别提前很久生成放着。★transNo 重复会被工行直接拒绝,平台也会先帮你拦一道(返回 400 提示已使用过)。
查认证结果
接口 · 查认证结果(数据类)
POST https://openapi.kailingteck.com/api/v1/rinv/face/status
鉴权:X-App-Key + X-Timestamp + X-Sign(= sha256(appKey + 时间戳 + 报文 + appSecret))。
请求参数
| 字段 | 必填 | 大白话说明 |
|---|---|---|
transNo | 必填 | 发起认证时的流水号 |
outUserId | 选填 | 不传则自动用发起时登记的那个(工行要求两头一致) |
请求示例
{ "transNo": "CHECKIN20260923001" }返回
所有接口都用同一层信封:code/msg/requestId/timestamp/data。业务字段都在 data 里,下表列的就是 data 的内容。code 为 CYT_00000 表示调用成功。
返回参数(data)
| 字段 | 大白话说明 |
|---|---|
passed | ★直接看这个:true=本人核验通过 |
authResult | 工行原始状态:00 初始 / 01 认证中 / 02 认证成功 / 03 认证失败 |
authResultText | 上面那个码的中文说法 |
failReason | 失败原因(失败时才有) |
hint | 查不到结果时的人话解释(比如本人还没打开链接) |
notifiedResult | 工行异步通知已到达时回显通知结果(1 通过 / 0 未通过),与主动查询互为印证 |
返回示例(成功)
{
"code": "CYT_00000",
"data": {
"transNo": "CHECKIN20260923001",
"passed": true,
"authResult": "02",
"authResultText": "认证成功",
"notifiedResult": "1"
}
}异常与报错
| 情形 | 含义与处理 |
|---|---|
| 查不到结果 / hint 提示尚未开始 | 本人还没打开链接,或人脸、短信验证码两步没走完,稍后再查 |
| passed=false 且 authResult=03 | 工行判定认证失败,看 failReason;常见是人脸与公安基准照比对不通过、或短信验证码没完成 |
前端怎么用
const r = await post('/api/v1/rinv/face/status', { transNo });
if (r.data.passed) 打卡通过(); else 提示(r.data.hint || r.data.failReason);本人还没打开链接、或人脸与短信两步没走完时,工行返回「查询结果为空」,平台会在 hint 里说明,不要当成失败。★结果通知:认证完成后工行把结果推给平台,平台再转发到你发起时传的 callbackUrl,报文形如 {transNo, outUserId, verifyResult, passed}(verifyResult:1 通过 / 0 未通过)。工行只往平台推,所以你不需要向工行报备出口 IP;没传 callbackUrl 就用本接口轮询,两种方式结果一致。
所有接口通用的报错(平台层)
| HTTP / code | 含义与处理 |
|---|---|
400 · CYT_40001 | 必填参数没传,data.hint 里写了缺哪个 |
401 · CYT_40100 / 40102 | 缺鉴权头,或签名算错。签名 = sha256(appKey + 时间戳 + 报文原文 + appSecret),参与签名的报文必须与实际发送的逐字节一致 |
401 · CYT_40103 | 时间戳与服务器相差超过 300 秒,校准本机时间后重试 |
403 · CYT_40301 | 这把密钥的产品或渠道不对(工行接口需要「反向开票」产品 + 「工商银行」渠道) |
429 · CYT_42901 | 超过每分钟 120 次限流,稍后重试 |
502 · CYT_50200 | 工行侧暂时不可达。注意工行测试环境每晚 19:00 后关闭、次日恢复,联调请排在工作时间 |
200 · data.mock=true | 尚未配置工行凭据,返回的是演示数据、并未真调工行 |
