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/upgradeenables 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, andprofilingrequire a verified age of18;direct-marketingrequires a verified age of12
Permissions with a verifiedAgeThreshold are:
- Never
managedBy: GUARDIAN managedBy: PLAYERwhen the player is old enough but still needs verificationmanagedBy: PROHIBITEDwhen the player is below the threshold
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 threshold | Age verified? | managedBy | enabled |
|---|---|---|---|
| Below threshold | N/A | PROHIBITED | false |
| At or exceeding the threshold | No | PLAYER | false |
| At or exceeding the threshold | Yes, via verified platform signal | PLAYER | true |
| At or exceeding the threshold | Yes, via age assurance | PLAYER | true |
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:
| Field | Type | Description |
|---|---|---|
platformAgeSignal | PlatformAgeSignal | A platform signal that can satisfy the threshold immediately |
options | object | Options forwarded into the age-assurance experience |
options.facialAgeEstimation.passIfOver | integer | Minimum age at which facial age estimation should pass |
options.facialAgeEstimation.failIfUnder | integer | Maximum age at which facial age estimation should fail |
options.redirectUrl | string | Redirect 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
verifiedAgeThresholdor none of them can - If the player is below the threshold, the permission stays
PROHIBITEDand no challenge is issued - A verified platform signal can satisfy some or all requested permissions immediately
- An existing
ageVerificationon 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:
- The token is parsed and validated.
- If the challenge is already resolved, the player is redirected to the completion page.
- If still pending, a verification iframe is shown with k-ID's age verification methods (such as facial age estimation or ID document scan).
- 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"
}
}
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"
}
}
| Field | Description |
|---|---|
data.id | The challengeId returned by POST /session/upgrade |
data.status | PASS, FAIL, or IN_PROGRESS |
data.sessionId | Present 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, fetchGET /session/getand use the refreshed permissions. The threshold permission should now be enabled and the session should containageVerification. - After
FAIL, the permission remains disabled. The player can retry later by callingPOST /session/upgradeagain.
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
- Direct the player to Age Appeal on AgeKit+. Call
POST /age-verification/perform-age-appealwith the appropriatejurisdictionandcriteria. 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. - 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
verificationIdthat 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.
- On success: The appeal produces a
- Invalidate the session. After a successful appeal, discard the
sessionIdon 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. - Restart the age gate flow with the k-ID signal. Send the
verificationIdfrom the appeal as ak-idplatform 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