等级决定会员能做哪些业务。结论由我方给,资料可由商户服务端提交和更新,也可使用托管页面。
KYC 概览与等级
三个等级
| 等级 | 怎么算出来的 | 大致解锁 |
|---|---|---|
| 0 | 什么都没过 | 收款、看余额、站内转账(视配置) |
| 1 | L1 档案审核通过 | 发卡、扫码付、理财、兑换、提现等大部分线 |
| 2 | 在 L1 之上,L2 档案也通过 | 汇款一类需要更完整资料的业务 |
GET /v1/kyc 返回的字段名是 level,不是 kyc_level。
⚠ 照
kyc_level取会拿到undefined,而undefined >= 1在 JS 里是
false—— 表现是「所有人都没实名」,不报错。(
kyc_level是会员对象上的字段名,两处不同名。)
⚠ 取严:L2 通过而 L1 没通过(数据异常)时算 0 —— 不是 1,也不是 2。
判据是「L1 没过就直接 0」。反过来会让一个 L1 都没过的人被你当成实名用户。
「哪条线要几级」不要硬编码
GET /v1/kyc/requirements
返回各条业务线当前要求的等级。它会变(我方或你的配置调整),所以:
⚠ 在你这边写死一张「发卡要 L1、汇款要 L2」的表,会在门槛调整的当天失效 ——
而失效的表现是你的用户被你自己的前端挡住,或者反过来,走完六屏才在最后
一步拿到
kyc_required。
覆盖九条线
remittance.express · remittance.pobo · card · exchange · earn · withdraw · transfer.send · transfer.receive · qrpay
⚠ 转账收发是两行。 合成一行取严会把只收不发的会员判成不够格。
⚠
card按你看得见的卡产品取最低值,不是恒为 1 —— 卡产品可以要求 L2。
扫码付那一条要特别看
它的闸不是等级,是一条累计触发线:未过 L1 的会员可以一直付,直到累计消费超过 kyc_trigger_amount 才要求 L1。
所以它的 required_level 是 0,另带两个字段:
| 字段 | 意思 |
|---|---|
kyc_trigger_amount | 累计超过它之后升级(没有触发线时这个字段不出现) |
kyc_trigger_level | 升到几级(1) |
⚠ 只看
required_level: 0会漏判 —— 用户某一笔会突然被拒。把它当成 1 又是高报 —— 现在完全能付的用户被你挡住。两个数一起用。
这张表不回答「这条线能不能用」
它只回答要几级。可用性(开没开通、有没有被停售)走GET /v1/merchant/lines —— 一行配置都没有时这里照样给 0。
拿到 kyc_required 之后怎么办
错误码不告诉你差的是 L1 还是 L2 —— 六个内部原因(缺 L1 / 缺 L2 ×汇款 / 发卡 / 兑换 / 理财)全部折成同一个对外码 kyc_required。
恢复路径固定是三步:
GET /v1/kyc→ 拿当前levelGET /v1/kyc/requirements→ 拿这条线要几级(注意上面那条「只有五条」)- 差 L1 →
POST /v1/kyc/applications;差 L2 →POST /v1/kyc/l2/applications,见 L2 那一页
⚠ 少了第 3 步的分叉,你的接入代码会对一个缺 L2 的用户
反复发 L1 托管屏链接 —— 而他每次都能填完、每次都通过,
level却永远停在 1。
典型接入序列
POST /v1/members → 建会员
↓ 会员去下单
拿到 kyc_required
↓
GET /v1/kyc/requirements → 得知这条线要 level 1
↓
POST /v1/kyc/sessions → 换一条托管屏链接,转给终端用户
↓ 他在我方的页面上填表 + 拍照
kyc.result.updated 事件 → 通过 / 驳回 / 待补件
这条序列的泳道图(谁在什么时候做什么、失败往哪走)在创建会员与 KYC 全流程。
会员的 KYC 结论不跨商户继承
一个自然人在别的商户下已经完成实名,不会让他在你这里的 level 变成 1。
判据是你这个商户下的这一行会员:新建的会员没有指向任何 L1 档案,所以 POST /v1/members 之后 level 恒为 0,无一例外。
⚠ 别写「新建会员后先读
level,≥1 就直接放行」—— 那个分支永远不会命中。
但身份是跨商户共享的,这带来一个真实的坏路径
我方按邮箱(不区分大小写)认「同一个自然人」。于是:
| 情况 | 结果 |
|---|---|
| 同一个人、同一个邮箱在两个商户下建会员 | 同一个身份。他在你这里做 L1 不会被判重复 |
| 同一个人、换了一个邮箱 | 两个身份。他在你这里做 L1 时,证件号撞上他自己在别处那份档案 → kyc_identity_taken |
⚠⚠
kyc_identity_taken没有任何人工通道。 终端用户填完 15 个字段、传完三张证件照,在提交那一刻拿到一行红字,然后这条路对他永久关闭。
而你这一侧收不到任何信号:没有事件,
GET /v1/kyc仍然是none。你会一直等一个不会来的结论。
能做的预防只有一件:建会员时用这个人真实、长期在用的邮箱,
别用你自己拼出来的别名(
u88123@yourapp.com这种)。
同样的规则也适用于邮箱本身:该邮箱已被另一个身份的档案用过 → kyc_email_taken,同样是提交期 400、同样没有人工通道。
被驳回时把理由给出来
GET /v1/kyc 在 status: "rejected" 时带 reject_reason —— 审核员写的人话,不是错误码。L2 那一级是 l2_reject_reason,两级各一条不合并(L1 通过而 L2 被驳是常态,合成一个字段就分不出该让用户补哪一级的材料)。
没被驳回时两者恒为空串 —— 一条「上次被驳回的理由」挂在已通过的档案上,会让你的界面在用户已经过了之后还催他整改。
⚠ 这是自由文本,直接展示给终端用户,别拿它做分支判断 ——
审核员换一种说法你的分支就失效了。空串也可能只是老数据没写过理由,
那时按「未说明原因」处理。
直接更新资料:PATCH /v1/kyc
商户在自己的页面采集修改后的资料,由服务端调用接口,无需跳转托管页面。
PATCH /v1/kyc
x-on-behalf-of: <会员 external_member_id 或 mem_uuid>
x-idempotency-key: <本次更新的唯一值>
Content-Type: application/json
{"profile":{"first_name":"Alex","occupation":"designer","address":"25 Main Street","phone_zone_number":"1","phone":"2025550123"}}
姓名、性别、生日、邮箱、电话、证件类型与有效期、照片、居住类型、地址等均可修改。证件号码 identity_number、国籍 nationality、证件签发国家 identity_issue_country、居住国家 address_country 不可修改;传入这些字段会拒绝整次更新。
需 kyc:write 权限,照常附带访问令牌与请求签名。只传要修改的字段;未传的证件照片、地址等保留。照片对象按子字段合并,居留许可 URL 数组整组替换。未传的字段保持原值;空字符串或空数组是显式修改,仍须通过校验,不能用 null 表示不修改。字段清单见 直接更新 KYC。
成功返回 kyc_id、status: pending、review_status: UNREVIEWED、level: 0。已通过的档案也会重新审核,对应卡产品的 KYC 记录同步退回待审。复审通过前,需要实名等级的业务不可继续。
本接口更新实名档案,不直接同步已存在的卡或上游持卡人的联系资料。对于因手机号占用而失败的开卡申请,更新资料、复审通过后,应使用新的幂等键重新发起开卡;旧申请不会自动恢复。POST /v1/kyc/applications 会复用已有已通过档案,不能用来覆盖手机号。
空更新、未知字段和不合法的手机号会被拒绝。还没建档返回 not_found;快捷 KYC 资料不允许在此修改。并发编辑返回 state_invalid,用新的幂等键重试。
托管页面是可选接入方式
需要托管页面时,仍可使用 POST /v1/kyc/profile-sessions 获取更新链接。商户服务端可以直接使用 PATCH /v1/kyc,不必先取链接。创建资料可使用 POST /v1/kyc/applications;影像通过 POST /v1/kyc/files 上传。GET /v1/kyc 仍只返回结论,不回显完整档案和证件影像。
快捷 KYC 不是实名
GET /v1/kyc/quick 与 GET /v1/kyc 上的 quick_kyc 字段,说的是平台资料池里独占绑给这个会员的身份包。只用来开卡。
⚠ 有快捷绑定 ≠
level1。速汇、兑换、理财、提现仍然看会员自己的 L1。也不要把这条路写成
POST /v1/kyc/applications(那条复用的是会员自己已过审的档案,会抬
level),或发卡「快捷申请」(库存盲发)。
详见 快捷 KYC。
接着读
相关端点
GET /v1/kycGET /v1/kyc/quickGET /v1/kyc/requirementsPOST /v1/kyc/sessionsPOST /v1/kyc/applicationsGET /v1/kyc/supplements
服务端直交 L1:POST /v1/kyc/applications
商户自己收件、不走托管页时,用这一条交这个会员的一份 L1。审核按人,不是按卡头。证件照先逐张 POST /v1/kyc/files,把返回的私有 file_url写进 profile.identity_photos。不要传你自己的对象存储地址或 base64。
请求体必填 profile(带 x-on-behalf-of)。card_product_id 可选:传了只盖一枚产品快照,发卡方与卡头由我方从产品解析;省略则只交人档。不要自己传发卡方。
POST /v1/kyc/applications 完整 profile(card_product_id 可省略)
↓
GET /v1/kyc pending 则等;rejected 则改资料再交
↓ status=approved / level=1
POST /v1/cards/applications 换 product_id 开第二款、第三款
⚠ L1 通过之后不要为每个卡头再调一次本接口。 开卡只看这个人过没过。
第一份还在
pending时去交另一款会state_invalid。同一产品未结束或已通过再打是
200回已有单;被驳回的可以再交。
收到 pending 后轮询 GET /v1/kyc(或等 kyc.result.updated)。提交当时不推送事件。产品要 L2 的,仍须另走 L2,与卡头个数无关。