已验证家长关联 (VPL)
已验证家长关联 (VPL) 让玩家可以主动邀请自己的家长进入您的产品。玩家发出邀请,家长完成身份验证后,即可查看并设置该玩家的各项控制。邀请处于等待状态期间,您的产品不会阻断任何内容;即使家长始终没有接受,也不会有任何东西出问题。
本指南完整介绍整个流程:创建会话、发送邀请、跟踪状态、取消邀请,以及处理任一方发起的解除关联。
已验证家长关联 (VPL) 解释了 VPL 为何是关联而不是门禁,以及它为何与 VPC 互斥。那里说明的资格规则决定了本指南中的调用是否会成功。
前提条件
开始之前,您需要:
- 一个 k-ID 产品:在 Compliance Studio 中创建并配置您的产品。
- API 密钥:在产品的 Developer Settings 页面生成。本指南中的所有调用都是服务器到服务器的调用。参见身份验证。
- 一个 webhook 端点:用于接收
Challenge.StateChange和Session.Unlink的 HTTPS 端点。参见 Webhooks。 - 订阅您要处理的事件:端点只会收到它已订阅的事件类型,其余的 k-ID 会直接丢弃,既不尝试投递也不返回错误。请在 Compliance Studio 中该产品的 Developer Settings 页面上,为该端点选中
Challenge.StateChange和Session.Unlink。 - 您的组织已启用 VPL:请联系 k-ID 为您的组织开启此功能。
所有示例使用生产环境基础 URL https://game-api.k-id.com/api/v1、Content-Type: application/json 以及 Authorization: Bearer <api-key> 请求头。测试模式请使用 https://game-api.test.k-id.com/api/v1。
第 1 步:创建玩家的会话
调用 POST /age-gate/check 为玩家创建会话。
POST /age-gate/check
{
"jurisdiction": "US-CA",
"age": 17
}
在 age、dateOfBirth 和 kuid(针对您已缓存 kuid 的回访玩家)中最多传入一个。传入多个会返回 400。该端点还接受哪些年龄信号,请参见 /age-gate/check。
成功的响应中包含会话:
{
"status": "PASS",
"session": {
"sessionId": "b1a6482d-5242-4b4a-aa88-3fa52595a672",
"status": "ACTIVE",
"managedBy": "PLAYER",
"hasApproverEmail": false
}
}
请把 sessionId 保存到您自己的用户记录上。本指南中的每个调用都以它为键,并且它在关联、解除关联和重新关联之间保持不变。
如果状态是 CHALLENGE 而不是 PASS,说明玩家未达其司法管辖区的访问年龄,需要父母同意。请把他们引导到 VPC,不要调用邀请端点,因为并不存在可供邀请家长的会话。
即使返回了 PASS,如果会话带有由 GUARDIAN 管理的权限,它仍然不符合 VPL 的条件。在展示邀请入口之前检查会话的 permissions[],或者在第 3 步处理 FEATURE_DISABLED 错误。
第 2 步:展示邀请入口
把它放在适合您产品的位置,例如设置、玩家资料页或引导流程。玩家点击后,收集家长的邮箱地址。
由于 VPL 是可选的且不会阻断任何内容,这只是一个普通的产品入口,而不是插屏。玩家可以一直忽略它。
第 3 步:发送邀请
调用 POST /challenge/invite-parent。
POST /challenge/invite-parent
{
"sessionId": "b1a6482d-5242-4b4a-aa88-3fa52595a672",
"parentEmail": "parent@example.com",
"playerName": "Alex",
"locale": "en"
}
| 字段 | 必填 | 说明 |
|---|---|---|
sessionId | 是 | 第 1 步中的会话 |
parentEmail | 是 | 邀请的发送地址 |
playerName | 否 | 玩家的显示名称,1 到 63 个字符。会在邀请邮件中展示给家长。省略时家长会看到通用占位内容 |
locale | 否 | 邀请邮件的 IETF BCP 47 标签。省略时,如果 k-ID 已经认识这位家长,会先使用该家长自己保存的语言,然后回退到产品的主要语言,最后回退到英语 |
{
"status": "CHALLENGE",
"challenge": {
"challengeId": "ae6d4729-af32-42ea-8ef2-ff46c7664802",
"type": "CHALLENGE_PARENT_INVITE"
}
}
一次调用即完成创建挑战、绑定到会话并发送邮件。无需再调用其他接口来触发邮件,而且 /challenge/send-email 会拒绝家长邀请类挑战。
请把 challengeId 与会话一起保存。它在 webhook、状态端点和取消调用中用于标识这次邀请。
在您持有某个待处理邀请的 challengeId 期间,请勿就同一会话向另一个邮箱再发一封邀请。
邀请邮件中的链接在生产模式下有效期为 14 天,在测试模式下为 7 分钟,便于您无需等待即可验证过期行为。
需要处理的错误
错误以 HTTP 400 返回,具体代码在响应体的 error 字段中。
| 代码 | 出现时机 | 处理方式 |
|---|---|---|
FEATURE_DISABLED | Verified parent linking is not enabled。您的组织未启用 VPL | 联系 k-ID |
FEATURE_DISABLED | Verified parent linking is not available for this player。玩家未达访问年龄,或会话带有由 GUARDIAN 管理的权限 | 回退到 VPC。不要为该会话展示邀请入口 |
NOT_FOUND | 会话不存在 | 重新核对您保存的 sessionId |
INVALID_INPUT | 会话的司法管辖区未在您的产品中配置 | 在 Compliance Studio 中修正产品配置 |
INVALID_EMAIL | Session is not eligible for a new invite。会话已关联家长 | 改为展示当前的关联状态 |
第 4 步:等待,但不要阻断
邀请处于等待状态期间,请让产品保持完全可用。玩家已经通过了年龄门禁,邀请本身并不改变他们能做什么。
家长完成流程后,k-ID 会向您的 webhook 端点发送 Challenge.StateChange:
{
"eventType": "Challenge.StateChange",
"data": {
"id": "ae6d4729-af32-42ea-8ef2-ff46c7664802",
"productId": 12345,
"type": "CHALLENGE_PARENT_INVITE",
"status": "PASS",
"sessionId": "b1a6482d-5242-4b4a-aa88-3fa52595a672",
"approverEmail": "parent@example.com",
"kuid": "12b9fa0e-6d6d-4903-a1fc-f2233027b71d"
}
}
收到后:
- 用
data.id和data.sessionId匹配回您保存的玩家记录。 - 缓存
kuid。它告诉您这个会话已关联了一位家长。 - 在界面上显示家长已连接。
邀请被取消时,同一事件会以 status: FAIL 发出,但 FAIL 的负载中不包含 sessionId。请用 data.id 与您保存的 challengeId 匹配,而不是 data.sessionId,否则您的处理逻辑会漏掉每一次取消。将其视为没有家长连接。玩家可以再发一次邀请。
如果家长始终没有接受,就不会再有事件,也不会有任何变化。
第 5 步:按需查询当前状态
webhook 是状态变更的权威来源,但您经常需要在不等待事件的情况下获知当前状态,例如玩家重新打开应用时。
现在是否有家长关联
用 sessionId 调用 GET /session/get,读取两个字段:
- 家长处于关联状态期间
hasApproverEmail为true,其余情况为false。应当据以分支的是它。 kuid标识该会话所关联的儿童档案。
上一次邀请怎么样了
用保存的 challengeId 调用 GET /challenge/get-status。
| 状态 | 含义 | 建议的界面 |
|---|---|---|
PENDING | 邀请已创建且邮件已发送,但家长尚未打开 | 显示邀请处于等待中,并标明 parentEmail |
IN_PROGRESS | 家长已打开链接并开始流程 | 显示邀请处于等待中,并标明 parentEmail |
PASS | 家长已完成,会话已关联 | 显示家长已连接 |
FAIL | 邀请被取消或已终止 | 显示没有家长连接,并提供再次邀请 |
结合使用
渲染玩家资料页时:
- 调用
/session/get。若hasApproverEmail为true,显示家长已连接,并提供第 7 步的解除关联入口。 - 否则用最近的
challengeId调用/challenge/get-status:PENDING或IN_PROGRESS:把邀请显示为等待中,并提供取消。PASS但/session/get仍未显示家长:这是短暂的竞态。按等待中处理,稍后重新查询。FAIL,或没有保存的challengeId:展示邀请入口。
第 6 步:取消等待中的邀请
如果家长仍在验证过程中而玩家想撤回邀请,调用 POST /challenge/cancel-invite。
POST /challenge/cancel-invite
{
"challengeId": "ae6d4729-af32-42ea-8ef2-ff46c7664802"
}
{ "cancelled": true }
该挑战会带着 failureReason: "cancelled-by-initiator" 转为 FAIL,您会收到 status: FAIL 的 Challenge.StateChange,而已经打开验证组件的家长会看到已取消的状态。
对已取消的邀请再次取消是安全的,仍会返回 cancelled: true。
| 代码 | 出现时机 |
|---|---|
NOT_FOUND | 该产品下不存在此挑战 |
INVALID_INPUT | Invalid challenge type。此端点只能取消家长邀请类挑战 |
INVALID_INPUT | Invite already accepted。取消到达前家长已完成 |
FEATURE_DISABLED | 您的组织未启用 VPL |
出现 FAIL 之后,该会话可以立即接受新的邀请。
第 7 步:处理解除关联
任一方都可以随时结束这段关系。家长可以在 Family Connect 中解除,您也可以在产品中为玩家提供解除入口。
解除关联会让会话回到未关联状态:kuid 与家长关联被清除,家长设置的额度与各项控制也会被移除。会话本身仍为 ACTIVE,玩家的权限与已推送的数据保持不变。玩家继续使用同一个 sessionId。
在您的产品中解除关联
POST /session/unlink-parent
{
"sessionId": "b1a6482d-5242-4b4a-aa88-3fa52595a672",
"locale": "en"
}
{
"unlinked": true,
"unlinkedAt": "2026-04-20T18:42:11Z"
}
当本次调用(或之前的某次调用)结束了家长关联时,unlinked 为 true。若该会话从未关联过家长,则为 false,此时会省略 unlinkedAt。locale 用于指定 k-ID 发给家长、告知关联已结束的通知邮件所用的语言。省略时,如果 k-ID 已经认识这位家长,会先使用该家长自己保存的语言,然后回退到产品的主要语言,最后回退到英语。
该调用对 sessionId 是幂等的。关联已被解除后再次调用会返回 200 和原来的 unlinkedAt,而不是这次重复调用的时间。
| 代码 | 出现时机 |
|---|---|
NOT_FOUND | 会话不存在 |
INVALID_INPUT | 会话的司法管辖区未在您的产品中配置 |
FEATURE_DISABLED | Unlink is only available for VPL-linked sessions。该会话不在 VPL 路径上,或您的组织未启用 VPL |
Session.Unlink webhook
只要关联结束,无论来自哪一方,k-ID 都会发送 Session.Unlink。
{
"eventType": "Session.Unlink",
"data": {
"sessionId": "b1a6482d-5242-4b4a-aa88-3fa52595a672",
"productId": 12345,
"unlinkedBy": "player",
"unlinkedAt": "2026-04-20T18:42:11Z"
}
}
若解除来自您的 API,unlinkedBy 为 player;若家长在 Family Connect 中解除,则为 parent。
收到后,不再显示家长处于已连接状态。玩家可以随时发送新的邀请。
下一步是什么?
已验证家长关联接好之后,可以通过以下资源进一步深入:
- 已验证家长关联 (VPL):本指南背后的概念:关联与门禁的区别,以及 VPL 与 VPC 为何互斥
- 会话:
sessionId与kuid在关联、解除关联、重新关联之间的行为 Session.Unlink:在任一方结束关联时通知您的 webhook- Webhooks:webhook 订阅、投递与签名验证的完整指南
- 发布前检查清单:上线前需要核对的要求