Skip to main content

Challenge.StateChange

Emitted when a challenge changes state.

Parental consent challenges don't expire

A parental consent challenge remains pending until a trusted adult either approves or denies it. Only the access methods (OTP, QR code, email link) expire, not the challenge itself. For details, see Challenge expiration and time-based authentication.

Fields

FieldTypeRequiredDescription
eventTypestringyesAlways "Challenge.StateChange"
dataobjectyesChallenge state change data
data.idstring (UUID)yesChallenge ID
data.productIdnumberyesThe productId for the product
data.statusstringyesOne of PASS, FAIL, IN_PROGRESS
data.dobstring (YYYY-MM-DD)noPlayer date of birth; present when available
data.sessionIdstring (UUID)noPresent when status is PASS
data.approverEmailstringnoPresent on PASS when a trusted adult approved the challenge
data.kuidstringnoThe kuid (k-ID user ID); present when available

Example

{
"eventType": "Challenge.StateChange",
"data": {
"id": "9d6b056e-7d62-4a9e-907a-3d0f6f1d1b9a",
"productId": 11472,
"status": "PASS",
"dob": "2011-07-12",
"sessionId": "b6d1a7c2-8f34-4c83-bf0b-3a6d4a2f9d31",
"approverEmail": "parent@example.com",
"kuid": "7a1f2c3d-4e5f-6789-abcd-ef0123456789"
}
}

Challenge event contract

This section documents the complete contract for challenge state change events, including all possible fields, their presence rules, and how to interpret different statuses.

DOM messages aren't authoritative

Challenge results are also communicated to front-end applications via DOM messages for UI control purposes. However, only webhook events and the GET /challenge/get-status endpoint responses should be considered reliable, authoritative data sources for integration logic. DOM messages are provided solely for front-end application state management and shouldn't be used as the basis for critical business decisions or data persistence.

Data structures

Webhook event structure

Webhook events are wrapped in an event envelope:

{
"eventType": "Challenge.StateChange",
"data": {
"id": "uuid",
"productId": number,
"status": "PASS" | "FAIL" | "IN_PROGRESS",
"dob": "YYYY-MM-DD" | null,
"sessionId": "uuid" | null,
"approverEmail": "string" | null,
"kuid": "string" | null
}
}

API endpoint response structure

The GET /challenge/get-status endpoint returns a direct response:

{
"id": "uuid",
"status": "PASS" | "FAIL" | "PENDING" | "IN_PROGRESS",
"dob": "YYYY-MM-DD" | null,
"sessionId": "uuid" | null,
"approverEmail": "string" | null
}

For complete endpoint documentation, see GET /challenge/get-status.

Key differences between webhook and API endpoint

AspectWebhook EventAPI Endpoint
Status valuesPASS, FAIL, IN_PROGRESSPASS, FAIL, PENDING, IN_PROGRESS
StructureWrapped in { eventType, data }Direct response object
productIdAlways includedNot included
kuidIncluded when availableNot included
When availableOnly when challenge state changesCan be polled at any time

Status types

PASS

The challenge completed successfully. A session has been created or updated with the approved permissions and sessionId is included.

Availability:

  • Webhook: ✅ Sent when the challenge completes successfully
  • API Endpoint: ✅ Returned when the challenge has completed successfully

FAIL

The challenge was explicitly rejected (for example, a trusted adult denied the request, or the player didn't meet the age criteria). Parental consent challenges don't automatically fail due to timeout or expiration; a FAIL only occurs when someone actively rejects the challenge.

Availability:

  • Webhook: ✅ Sent when the challenge is denied or fails
  • API Endpoint: ✅ Returned when the challenge has been denied or failed

IN_PROGRESS

Someone has started the challenge flow but hasn't yet completed it.

Availability:

  • Webhook: ✅ Sent when the flow begins
  • API Endpoint: ✅ Returned when the flow is in progress

PENDING

The challenge has been created but no one has accessed it yet.

Availability:

  • Webhook: ❌ Never sent (no state change has occurred)
  • API Endpoint: ✅ Returned when challenge is awaiting action

Field presence rules by status

Status: PASS

Webhook events

Always included:

  • id (UUID) - Challenge ID
  • productId (number) - Product ID
  • status ("PASS")
  • sessionId (UUID) - The created or updated session ID

Sometimes included:

  • dob (string, YYYY-MM-DD) - Player's confirmed date of birth, if the trusted adult confirmed or corrected it
  • approverEmail (string) - Email of the trusted adult who approved
  • kuid (string) - k-ID user ID, if the player has one

API endpoint

Always included:

  • id (UUID) - Challenge ID
  • status ("PASS")
  • sessionId (UUID) - The created or updated session ID

Sometimes included:

  • dob (string, YYYY-MM-DD) - Player's confirmed date of birth
  • approverEmail (string) - Email of the trusted adult who approved
What you need to know
  • Use the sessionId to fetch the full session with GET /session/get
  • Store the approverEmail for customer support cases
  • The dob might differ from what the player originally entered if the trusted adult corrected it

Status: FAIL

Webhook events

Always included:

  • id (UUID) - Challenge ID
  • productId (number) - Product ID
  • status ("FAIL")

Never included:

  • sessionId - No session is created when consent is denied
  • approverEmail - Not provided for denied requests

API endpoint

Always included:

  • id (UUID) - Challenge ID
  • status ("FAIL")

Never included:

  • sessionId
  • approverEmail
What you need to know
  • A FAIL status means the trusted adult explicitly denied the request
  • Display an appropriate message to the player explaining that their parent declined the request
  • The player can request consent again by creating a new challenge

Status: IN_PROGRESS

Webhook events

Always included:

  • id (UUID) - Challenge ID
  • productId (number) - Product ID
  • status ("IN_PROGRESS")

Never included:

  • sessionId
  • approverEmail
  • dob

API endpoint

Always included:

  • id (UUID) - Challenge ID
  • status ("IN_PROGRESS")
What you need to know
  • This status indicates a trusted adult is actively working through the consent flow
  • Consider updating your UI to show "Parent is reviewing" or similar
  • The next webhook is either PASS or FAIL

Status: PENDING (API only)

API endpoint

Always included:

  • id (UUID) - Challenge ID
  • status ("PENDING")

Never included:

  • All other fields
What you need to know
  • The challenge is waiting for a trusted adult to access it
  • Continue displaying the QR code, OTP, or email option to the player
  • Consider refreshing expired access methods with /challenge/generate-otp

Field presence summary

Webhook events

FieldPASSFAILIN_PROGRESS
idalwaysalwaysalways
productIdalwaysalwaysalways
statusalwaysalwaysalways
sessionIdalwaysnevernever
dobsometimesnevernever
approverEmailsometimesnevernever
kuidsometimesnevernever

API endpoint

FieldPASSFAILPENDINGIN_PROGRESS
idalwaysalwaysalwaysalways
statusalwaysalwaysalwaysalways
sessionIdalwaysnevernevernever
dobsometimesnevernevernever
approverEmailsometimesnevernevernever

Implementation checklist

  • Handle all three webhook statuses: PASS, FAIL, IN_PROGRESS
  • On PASS, extract sessionId and fetch the full session
  • On FAIL, display appropriate messaging to the player
  • On IN_PROGRESS, optionally update UI to show consent is being reviewed
  • Store approverEmail when available for customer support
  • Don't assume optional fields are present; check before accessing
  • Use webhook events for real-time updates, API polling as fallback