Challenge.StateChange
Emitted when a parental consent challenge changes state.
A 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
| Field | Type | Required | Description |
|---|---|---|---|
eventType | string | yes | Always "Challenge.StateChange" |
data | object | yes | Challenge state change data |
data.id | string (UUID) | yes | Challenge ID |
data.productId | number | yes | The productId for the product |
data.status | string | yes | One of PASS, FAIL, IN_PROGRESS |
data.dob | string (YYYY-MM-DD) | no | Player date of birth; present when available |
data.sessionId | string (UUID) | no | Present when status is PASS |
data.approverEmail | string | no | Present when status is PASS |
data.kuid | string | no | The kuid (k-ID user ID); present when available |
Example
- PASS
- FAIL
- IN_PROGRESS
{
"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"
}
}
{
"eventType": "Challenge.StateChange",
"data": {
"id": "9d6b056e-7d62-4a9e-907a-3d0f6f1d1b9a",
"productId": 11472,
"status": "FAIL"
}
}
{
"eventType": "Challenge.StateChange",
"data": {
"id": "9d6b056e-7d62-4a9e-907a-3d0f6f1d1b9a",
"productId": 11472,
"status": "IN_PROGRESS"
}
}
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.
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
| Aspect | Webhook Event | API Endpoint |
|---|---|---|
| Status values | PASS, FAIL, IN_PROGRESS | PASS, FAIL, PENDING, IN_PROGRESS |
| Structure | Wrapped in { eventType, data } | Direct response object |
productId | Always included | Not included |
kuid | Included when available | Not included |
| When available | Only when challenge state changes | Can be polled at any time |
Status types
PASS
The trusted adult approved the consent request. A session has been created or updated with the approved permissions.
Availability:
- Webhook: ✅ Sent when consent is approved
- API Endpoint: ✅ Returned when consent has been approved
FAIL
The trusted adult explicitly denied the consent request. This only occurs when a parent actively clicks "Deny" in Family Connect. Challenges don't automatically fail due to timeout or expiration.
Availability:
- Webhook: ✅ Sent when consent is denied
- API Endpoint: ✅ Returned when consent has been denied
IN_PROGRESS
The trusted adult has accessed the challenge (clicked the link, scanned the QR code, or entered the OTP) but hasn't yet completed the consent flow.
Availability:
- Webhook: ✅ Sent when the trusted adult begins the flow
- API Endpoint: ✅ Returned when the flow is in progress
PENDING
The challenge has been created but no trusted adult 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 IDproductId(number) - Product IDstatus("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 itapproverEmail(string) - Email of the trusted adult who approvedkuid(string) - k-ID user ID, if the player has one
API endpoint
Always included:
id(UUID) - Challenge IDstatus("PASS")sessionId(UUID) - The created or updated session ID
Sometimes included:
dob(string, YYYY-MM-DD) - Player's confirmed date of birthapproverEmail(string) - Email of the trusted adult who approved
- Use the
sessionIdto fetch the full session withGET /session/get - Store the
approverEmailfor customer support cases - The
dobmight differ from what the player originally entered if the trusted adult corrected it
Status: FAIL
Webhook events
Always included:
id(UUID) - Challenge IDproductId(number) - Product IDstatus("FAIL")
Never included:
sessionId- No session is created when consent is deniedapproverEmail- Not provided for denied requests
API endpoint
Always included:
id(UUID) - Challenge IDstatus("FAIL")
Never included:
sessionIdapproverEmail
- A
FAILstatus 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 IDproductId(number) - Product IDstatus("IN_PROGRESS")
Never included:
sessionIdapproverEmaildob
API endpoint
Always included:
id(UUID) - Challenge IDstatus("IN_PROGRESS")
- 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
PASSorFAIL
Status: PENDING (API only)
API endpoint
Always included:
id(UUID) - Challenge IDstatus("PENDING")
Never included:
- All other fields
- 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
| Field | PASS | FAIL | IN_PROGRESS |
|---|---|---|---|
id | always | always | always |
productId | always | always | always |
status | always | always | always |
sessionId | always | never | never |
dob | sometimes | never | never |
approverEmail | sometimes | never | never |
kuid | sometimes | never | never |
API endpoint
| Field | PASS | FAIL | PENDING | IN_PROGRESS |
|---|---|---|---|---|
id | always | always | always | always |
status | always | always | always | always |
sessionId | always | never | never | never |
dob | sometimes | never | never | never |
approverEmail | sometimes | never | never | never |
Implementation checklist
- Handle all three webhook statuses:
PASS,FAIL,IN_PROGRESS - On
PASS, extractsessionIdand 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
approverEmailwhen 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