Skip to main content

Age assurance for high-risk features

Certain permissions in certain jurisdictions require a verified age before they can be enabled. For example, loot-boxes-paid-cosmetic-only, loot-boxes-paid-gameplay-impacting, targeted-ads, and profiling in Brazil (BR) require a verifiedAgeThreshold of 18. These permissions are disabled by default and can only be unlocked through either a platform signal considered verified for age requirements or a dedicated age assurance challenge (CHALLENGE_SESSION_UPGRADE_BY_AGE_ASSURANCE).

What this page helps you do

Use this page when you need to understand:

  • Why a permission is still disabled after the player has already passed the age gate
  • Whether POST /session/upgrade enables a permission immediately or returns a challenge
  • How to handle a player who meets the threshold but hasn't verified age yet
  • How to recover when a player originally claimed an age below the threshold

Verified age threshold

A verifiedAgeThreshold means the permission needs a verified age, not just a claimed or inferred age.

Currently, the main example is:

  • Brazil (BR): loot-boxes-paid-cosmetic-only, loot-boxes-paid-gameplay-impacting, targeted-ads, and profiling require a verified age of 18; direct-marketing requires a verified age of 12

Permissions with a verifiedAgeThreshold are:

  • Never managedBy: GUARDIAN
  • managedBy: PLAYER when the player is old enough but still needs verification
  • managedBy: PROHIBITED when the player is below the threshold
note

This currently applies to the Brazil permissions in the preceding list. As additional jurisdictions add verified-age requirements, the same permission model applies.

Permission state logic

When a permission has a verifiedAgeThreshold, the Permission object includes that field:

{
"name": "loot-boxes-paid-gameplay-impacting",
"enabled": false,
"managedBy": "PLAYER",
"verifiedAgeThreshold": 18
}
Player age compared to thresholdAge verified?managedByenabled
Below thresholdN/APROHIBITEDfalse
At or exceeding the thresholdNoPLAYERfalse
At or exceeding the thresholdYes, via verified platform signalPLAYERtrue
At or exceeding the thresholdYes, via age assurancePLAYERtrue

Threshold permissions are never managedBy: GUARDIAN. Guardian consent can't unlock them.

ageVerification on the session

When a verified platform signal is processed or an age assurance challenge completes, the session stores an ageVerification object:

{
"ageVerification": {
"verifiedAge": 18,
"platformName": "apple-ios",
"declarationType": "governmentIDChecked",
"verifiedAt": "2026-03-14T00:00:00Z"
}
}

This verification is reusable. Once it's on the session, later POST /session/upgrade calls for permissions with the same or lower threshold can usually be satisfied without a new challenge.

Session upgrade flow

POST /session/upgrade is the endpoint that decides whether the player can get the high-risk permission immediately or needs to verify first.

Session upgrade API

Relevant request fields:

FieldTypeDescription
platformAgeSignalPlatformAgeSignalA platform signal that can satisfy the threshold immediately
optionsobjectOptions forwarded into the age-assurance experience
options.facialAgeEstimation.passIfOverintegerMinimum age at which facial age estimation should pass
options.facialAgeEstimation.failIfUnderintegerMaximum age at which facial age estimation should fail
options.redirectUrlstringRedirect target after the challenge completes

Example request (verified platform signal satisfies the permission):

POST /api/v1/session/upgrade

{
"sessionId": "608616da-4fd2-4742-82bf-ec1d4ffd8187",
"requestedPermissions": [
{ "name": "loot-boxes-paid-gameplay-impacting" }
],
"platformAgeSignal": {
"name": "apple-ios",
"ageLow": 18,
"ageHigh": 25,
"declarationType": "governmentIDChecked"
}
}
{
"session": {
"sessionId": "608616da-4fd2-4742-82bf-ec1d4ffd8187",
"permissions": [
{
"name": "loot-boxes-paid-gameplay-impacting",
"enabled": true,
"managedBy": "PLAYER",
"verifiedAgeThreshold": 18
}
],
"ageVerification": {
"verifiedAge": 18,
"platformName": "apple-ios",
"declarationType": "governmentIDChecked",
"verifiedAt": "2026-03-14T00:00:00Z"
}
}
}

Example request (player meets the threshold but still needs age assurance):

POST /api/v1/session/upgrade

{
"sessionId": "608616da-4fd2-4742-82bf-ec1d4ffd8187",
"requestedPermissions": [
{ "name": "loot-boxes-paid-gameplay-impacting" }
],
"options": {
"redirectUrl": "https://mygame.com/callback"
}
}
{
"session": {
"sessionId": "608616da-4fd2-4742-82bf-ec1d4ffd8187",
"permissions": [
{
"name": "loot-boxes-paid-gameplay-impacting",
"enabled": false,
"managedBy": "PLAYER",
"verifiedAgeThreshold": 18
}
]
},
"challenge": {
"challengeId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"type": "CHALLENGE_SESSION_UPGRADE_BY_AGE_ASSURANCE",
"url": "https://family.k-id.com/session/upgrade/age-assurance?token=..."
}
}

Example outcome (player is below the threshold):

{
"session": {
"sessionId": "608616da-4fd2-4742-82bf-ec1d4ffd8187",
"permissions": [
{
"name": "loot-boxes-paid-gameplay-impacting",
"enabled": false,
"managedBy": "PROHIBITED",
"verifiedAgeThreshold": 18
}
]
}
}

In this case, no challenge is returned because the player isn't old enough for the permission at all.

Key behaviors:

  • All requested permissions must either all have a verifiedAgeThreshold or none of them can
  • If the player is below the threshold, the permission stays PROHIBITED and no challenge is issued
  • A verified platform signal can satisfy some or all requested permissions immediately
  • An existing ageVerification on the session can also satisfy the request
  • Only the remaining unresolved permissions turn into an age-assurance challenge

Handling the challenge result

The challenge URL points to https://family.k-id.com/session/upgrade/age-assurance?token=....

When the player opens this URL:

  1. The token is parsed and validated.
  2. If the challenge is already resolved, the player is redirected to the completion page.
  3. If still pending, a verification iframe is shown with k-ID's age verification methods (such as facial age estimation or ID document scan).
  4. On completion, the result is communicated back to your integration.

You can receive that result in three ways:

Option 1: Listen for postMessage

For iframe or webview integrations, the family portal posts a Challenge.StateChange message to the parent window:

{
"eventType": "Challenge.StateChange",
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"productId": "your-product-id",
"status": "PASS"
}
}
warning

DOM postMessage events are useful for updating your UI, but they aren't authoritative. Use a webhook or the polling endpoint for any server-side logic.

Option 2: Poll GET /challenge/get-status

GET /api/v1/challenge/get-status?challengeId=a1b2c3d4-e5f6-7890-abcd-ef1234567890

Possible statuses are PASS, FAIL, PENDING, and IN_PROGRESS.

Option 3: Receive a Challenge.StateChange webhook

k-ID posts a Challenge.StateChange webhook event to your configured endpoint whenever the challenge status changes:

{
"eventType": "Challenge.StateChange",
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"productId": 11472,
"status": "PASS",
"sessionId": "608616da-4fd2-4742-82bf-ec1d4ffd8187"
}
}
FieldDescription
data.idThe challengeId returned by POST /session/upgrade
data.statusPASS, FAIL, or IN_PROGRESS
data.sessionIdPresent on PASS: use this to fetch the refreshed session

Webhooks are the recommended approach for server-side handling because they're delivered in real time and don't require polling. For the full field reference and status lifecycle, see Challenge.StateChange.

After the result

  • After PASS, fetch GET /session/get and use the refreshed permissions. The threshold permission should now be enabled and the session should contain ageVerification.
  • After FAIL, the permission remains disabled. The player can retry later by calling POST /session/upgrade again.

Recovery flow for a player who entered an age below the threshold

Sometimes a player enters a claimed age below the threshold for a high-risk permission and ends up with a PROHIBITED permission. In that case, the normal session/upgrade flow can't fix the problem because the session already says the player is too young for that feature.

This recovery flow is for:

  • Player-managed sessions
  • Guardian-managed sessions that don't yet have an approver linked

It's not the right flow when the session is guardian-managed and already has an approver.

Recovery steps

  1. Direct the player to Age Appeal on AgeKit+. Call POST /age-verification/perform-age-appeal with the appropriate jurisdiction and criteria. Present the returned URL in an iframe or webview for the player to complete age verification. Don't invalidate the session yet: if the appeal fails, the player keeps their existing session and won't need to go through VPC again.
  2. Handle the age appeal result. Listen for the result via DOM events, webhooks, or GET /age-verification/get-status.
    • On success: The appeal produces a verificationId that proves the player's verified age.
    • On failure: The feature remains prohibited. The player stays at their originally claimed age, and the existing session is preserved.
  3. Invalidate the session. After a successful appeal, discard the sessionId on your side so the player can start fresh. A session invalidation endpoint is planned for a future release; for now, removing the session client-side is sufficient.
  4. Restart the age gate flow with the k-ID signal. Send the verificationId from the appeal as a k-id platform signal.
POST /api/v1/age-gate/check

{
"jurisdiction": "BR",
"platformAgeSignal": {
"name": "k-id",
"verificationId": "<verificationId from age appeal>"
}
}

k-ID resolves the verified age from the verificationId. If the verified age meets or exceeds the verifiedAgeThreshold, the session is created with the high-risk permission enabled.

Sequential permission upgrades

Each threshold permission is tracked independently:

  • Upgrading one permission doesn't automatically upgrade another
  • Each permission still needs to be requested through POST /session/upgrade
  • Once the session has an ageVerification, later permissions with the same or lower threshold can often be satisfied without another challenge