Verification.Result
Emitted with the result of a verification attempt.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
eventType | string | yes | Always "Verification.Result" |
data | object | yes | Verification result data |
data.id | string (UUID) | yes | The unique verification ID |
data.status | string | yes | Can be PASS or FAIL |
data.ageCategory | string | no | The estimated age category. Can be adult, digital-youth, or digital-minor. Only present when status is PASS and age is present |
data.method | string | no | The verification method used. Always present for PASS status. For FAIL status, only present if failureReason is age-criteria-not-met |
data.failureReason | string | no | The reason the verification failed. Always present when status is FAIL. Can be age-criteria-not-met, max-attempts-exceeded, or fraudulent-activity-detected |
data.age | object | no | The age details. Present when both age.low and age.high are available. For FAIL status, only present if failureReason is age-criteria-not-met |
data.age.low | number | no | The lower bound of the estimated age. In the case of a hard age verification method, such as an ID document check, this is the exact age |
data.age.high | number | no | The upper bound of the estimated age. In the case of a hard age verification method, such as an ID document check, this is the exact age |
data.dob | string (YYYY-MM-DD) | no | Verified date of birth. Only included when the verification method provides it. Always included if available from the method |
Example
- PASS
- FAIL (Conclusive)
- FAIL (Inconclusive)
{
"eventType": "Verification.Result",
"data": {
"id": "4e57301e-a4d1-498f-ac3f-f3d4de19abf6",
"status": "PASS",
"method": "id-document",
"age": {
"low": 43,
"high": 43
},
"dob": "1981-06-20"
}
}
{
"eventType": "Verification.Result",
"data": {
"id": "fe10accb-b845-4fc8-ac44-6130b7e0b8bd",
"status": "FAIL",
"method": "age-estimation-scan",
"age": {
"low": 13,
"high": 17
},
"failureReason": "age-criteria-not-met"
}
}
{
"eventType": "Verification.Result",
"data": {
"id": "123e4567-e89b-12d3-a456-426614174002",
"status": "FAIL",
"failureReason": "max-attempts-exceeded"
}
}
Verification event contract
Overview
This section defines the API contract for verification status delivered to you through two mechanisms:
- Webhook Events:
Verification.Resultwebhook events sent when a verification completes - API Endpoint:
GET /age-verification/get-statusendpoint for polling verification status
This contract specifies field presence rules, data types, and interpretation guidance for all possible outcome types. While both mechanisms provide similar data, there are important differences in status values, field presence, and structure that you must be aware of.
Verification results are also communicated to front-end applications via DOM messages for UI control purposes. However, only webhook events and the GET /age-verification/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": "Verification.Result",
"data": {
"id": "uuid",
"status": "PASS" | "FAIL",
"ageCategory": "adult" | "digital-youth" | "digital-minor" | null,
"method": "id-document" | "credit-card" | "self-confirmation" | "social-security-number" | "email-confirmation" | "age-estimation-scan" | null,
"age": {
"low": number,
"high": number
} | null,
"dob": "YYYY-MM-DD" | null,
"failureReason": string | null
}
}
API endpoint response structure
The GET /age-verification/get-status endpoint returns a direct response:
{
"id": "uuid",
"status": "PASS" | "FAIL" | "PENDING" | "IN_PROGRESS",
"ageCategory": "adult" | "digital-youth" | "digital-minor" | null,
"method": "id-document" | "credit-card" | "self-confirmation" | "social-security-number" | "email-confirmation" | "age-estimation-scan" | null,
"age": {
"low": number,
"high": number
} | null,
"dob": "YYYY-MM-DD" | null,
"failureReason": string | null
}
Query Parameters:
id(required): The verification IDincludeDob(optional, default:false): Iftrue, includes thedobfield when available
For complete endpoint documentation, see GET /age-verification/get-status.
Key differences between webhook and API endpoint
| Aspect | Webhook Event | API Endpoint |
|---|---|---|
| Status Values | Only PASS or FAIL | PASS, FAIL, PENDING, IN_PROGRESS |
| Structure | Wrapped in { eventType, data } | Direct response object |
| DOB Field | Always included if available | Only included if includeDob=true query parameter is set |
| AgeCategory | Only present when status is PASS | Present for both PASS and FAIL statuses |
| Method | Only present when status is PASS | Present for both PASS and FAIL statuses |
| When Available | Only when verification completes | Can be polled at any time, including during verification |
Status types
PASS
The verification successfully determined that the user meets the age criteria.
Availability:
- Webhook: ✅ Sent when verification completes successfully
- API Endpoint: ✅ Returned when verification is complete and successful
FAIL
The verification determined that the user doesn't meet the age criteria, or the verification process failed because a conclusive age determination couldn't be made, or deceptive behavior was detected. These scenarios result in a FAIL status with the appropriate failureReason values.
Availability:
- Webhook: ✅ Sent when verification completes with failure
- API Endpoint: ✅ Returned when verification is complete and failed
Status: PENDING
The verification request has been created but hasn't yet started processing.
Availability:
- Webhook: ❌ Never sent (webhooks only fire on completion)
- API Endpoint: ✅ Returned when verification is in initial state
API Endpoint Response for PENDING:
id(UUID) - always includedstatus("PENDING") - always included- All other fields are absent
Status: IN_PROGRESS
The verification is currently being processed.
Availability:
- Webhook: ❌ Never sent (webhooks only fire on completion)
- API Endpoint: ✅ Returned when verification is actively being processed
API Endpoint Response for IN_PROGRESS:
id(UUID) - always includedstatus("IN_PROGRESS") - always included- All other fields are absent
Field presence rules by status
Webhook events
Webhook events are only sent when a verification completes (status is PASS or FAIL). They don't include intermediate statuses such as PENDING or IN_PROGRESS.
Status: PASS
Webhook events
Always included:
id(UUID)status("PASS")method(string) - The verification method used
Sometimes included:
ageCategory(string) - One of:adult,digital-youth,digital-minor(only present whenageis present)age(object) - Contains bothlowandhighbounds (only present when the verification method provides age information)dob(string, YYYY-MM-DD format) - Verified date of birth, only when the verification method provides it (see Date of birth field section for specific methods). Always included if available.
Never included:
failureReason
API endpoint
Always included:
id(UUID)status("PASS")method(string) - The verification method used (if available)
Sometimes included:
ageCategory(string) - One of:adult,digital-youth,digital-minor(when age is present)age(object) - Contains bothlowandhighbounds (when the verification method provides age information)
Sometimes included:
dob(string, YYYY-MM-DD format) - Only included ifincludeDob=truequery parameter is set AND the verification method provides it (see Date of birth field section for specific methods)
Never included:
failureReason
- Treat PASS status as a successful verification
- Use the
ageCategoryfield to determine user permissions and access levels when it's present - Don't rely solely on
age.loworage.highfor access control whenageCategoryis present, useageCategoryinstead - You can use
dobif it's provided, but don't assume it's always available - For the API endpoint: Set
includeDob=truein your query parameters if you need DOB data (seeGET /age-verification/get-status)
Status: FAIL
Webhook events
Always included:
id(UUID)status("FAIL")failureReason(string) - Reason for the failure
Sometimes included:
method(string) - Only present if failure isn't due tomax-attempts-exceededorfraudulent-activity-detectedage(object) - Only present iffailureReasonisage-criteria-not-metdob(string) - Only present when the verification method provides it (see Date of birth field section for specific methods). Always included if available.
Never included:
ageCategory- Webhook events only includeageCategorywhen status isPASS
API endpoint
Always included:
id(UUID)status("FAIL")failureReason(string) - Reason for the failure
Sometimes included:
method(string) - Only present if failure is due toage-criteria-not-metage(object) - Only present iffailureReasonisage-criteria-not-metageCategory(string) - Only present ifageis presentdob(string) - Only included ifincludeDob=truequery parameter is set AND the verification method provides it (see Date of birth field section for specific methods)
Never included:
ageCategorywhenageisn't present
- Treat
FAILstatus as an unsuccessful verification, don't grant access or permissions - Always check
failureReasonto understand why the verification failed - Don't assume
agefields are present for FAIL status, they might not be available - If
ageis present in aFAILresult, you can use it for logging or analytics, but don't use it for access control decisions - Handle cases where
methodandageare absent, this indicates a system-level failure, not an age determination failure - For webhook events:
ageCategorywon't be present forFAILstatus, so don't try to use it - For API endpoint: Even if
ageCategoryis present forFAILstatus, don't use it for access control decisions
Common Failure Reasons:
age-criteria-not-met- User's verified age doesn't meet the required thresholdmax-attempts-exceeded- User has exhausted all available verification attempts (this is the final failure reason when users exhaust retries after failed or inconclusive age determinations)fraudulent-activity-detected- System detected suspicious or fraudulent behavior
Age field population rules
When age object is present
The age object contains two fields:
low(number): The lower bound of the age estimate, or the exact age for hard verification methods (for example, ID document)high(number): The upper bound of the age estimate, or the exact age for hard verification methods, or 150 if only the minimum age is known
Conditions for age to be present:
- The verification method provided age information
- For FAIL status:
failureReasonisage-criteria-not-met
- Always check that both
age.lowandage.highexist before accessing theageobject - Don't assume that
age.low === age.highmeans you have an exact age, it might, but it depends on the verification method - Don't use
agefields for access control whenstatusisn't PASS - For PASS status, prefer using
ageCategoryover rawagevalues when making access decisions
When ageCategory is present
The ageCategory field is derived from the age and jurisdiction information.
Values:
adult- User is classified as an adultdigital-youth- User is classified as a digital youth (age-restricted but not a minor)digital-minor- User is classified as a digital minor
Conditions for ageCategory to be present:
ageobject is present- Age category was successfully calculated from the age and jurisdiction
- For FAIL status:
failureReasonisage-criteria-not-met
- Use
ageCategoryfor access control decisions when it's present and status is PASS - Don't assume
ageCategoryis always present, even whenageis present - Handle cases where
ageis present butageCategoryis absent - For FAIL status, don't use
ageCategoryfor access control decisions, even if it's present
When age and ageCategory are absent
Conditions:
- The verification failed with
failureReasonofmax-attempts-exceeded- No age determination was made - The verification failed with
failureReasonoffraudulent-activity-detected- Age data is excluded for security reasons - The verification method didn't provide age information
- Don't assume age information is always available, handle missing age fields gracefully
- Don't try to infer age from other fields when
ageis absent - For FAIL status without age fields, rely on
failureReasonto understand what went wrong
Date of birth field
Format: YYYY-MM-DD (ISO 8601 date format)
When present:
The dob field is only included when the verification method provides a verified date of birth. It's not included for methods that only provide age estimates or age ranges. Given the various combinations of verification methods and jurisdictions, you shouldn't perform validation or have expectations about when dob must be present. The field is provided when it's available from the verification method, but its presence can't be guaranteed across all scenarios.
Methods that can provide dob:
id-document- When the ID document contains readable date of birth informationcredit-card- When the credit card verification provides date of birth (not all credit card verifications include DOB)social-security-number- When the SSN verification provides date of birthprivy- Always provided (Indonesian identity verification)korean-real-name- Always provided (Korean real-name verification via Inicis)age-attestation- When the attestation includes birth date informationsingpass- Always provided (Singapore national identity verification)
Methods that NEVER provide dob:
age-estimation-scan- Only provides age ranges, not verified DOBemail-confirmation- Only provides age estimates, not verified DOBemail-estimation- Only provides age estimates, not verified DOBself-confirmation- No verified DOB available
Status conditions:
- Present for PASS status when the method provides it
- Present for FAIL status when the method provided it before determining the user didn't meet age criteria
- Don't assume
dobis always present, even for PASS status - If
dobis present, validate that it's inYYYY-MM-DDformat - You can use
dobfor additional validation or logging, but don't rely on it as your primary way to determine age
Method field
When present:
- Always present for PASS status
- Present for FAIL status when
failureReasonisage-criteria-not-met
Possible values:
id-document- Government-issued ID document verification (can include DOB)credit-card- Credit card verification (can include DOB)self-confirmation- Self-declared age confirmation (no DOB)age-estimation-scan- Age estimation via document scan (no DOB, only age ranges)social-security-number- SSN-based verification (can include DOB)email-confirmation- Email-based age verification (no DOB, only age estimates)email-estimation- Email-based age estimation (no DOB, only age estimates)privy- Indonesian identity verification (always includes DOB)korean-real-name- Korean real-name verification via Inicis (always includes DOB)age-attestation- Age attestation via k-ID (can include DOB)singpass- Singapore national identity verification (always includes DOB)connect-id- Australian ConnectID verification
- You can use
methodfor analytics or logging purposes - Don't use
methodfor access control decisions
Failure reason values
Common failureReason values:
age-criteria-not-met- User's verified age doesn't meet the required thresholdmax-attempts-exceeded- User has exhausted all available verification attemptsfraudulent-activity-detected- System detected suspicious or fraudulent behavior
- Handle unknown
failureReasonvalues gracefully, don't break if you see something unexpected - Don't make access decisions based solely on
failureReason, always consider thestatusfield - It's a good idea to log
failureReasonfor debugging and analytics purposes
Complete field matrix
Webhook events
| Field | PASS | FAIL |
|---|---|---|
id | always | always |
status | always | always |
method | always | sometimes¹ |
ageCategory | sometimes² | never |
age | sometimes² | sometimes³ |
dob | sometimes⁴ | sometimes⁴ |
failureReason | never | always |
¹ Present unless failureReason is max-attempts-exceeded or fraudulent-activity-detected
² Present only if both age.low and age.high are available
³ Present only if both age.low and age.high are available AND failureReason isn't max-attempts-exceeded or fraudulent-activity-detected
⁴ Always included if available from the verification method
API endpoint
| Field | PENDING | IN_PROGRESS | PASS | FAIL |
|---|---|---|---|---|
id | always | always | always | always |
status | always | always | always | always |
method | never | never | sometimes² | sometimes¹ |
ageCategory | never | never | sometimes² | sometimes² |
age | never | never | sometimes² | sometimes³ |
dob | never | never | sometimes⁴ | sometimes⁴ |
failureReason | never | never | never | always |
¹ Present unless failureReason is max-attempts-exceeded or fraudulent-activity-detected
² Present only if both age.low and age.high are available
³ Present only if both age.low and age.high are available AND failureReason isn't max-attempts-exceeded or fraudulent-activity-detected
⁴ Only included if includeDob=true query parameter is set AND available from the verification method
Example payloads
Webhook event examples
PASS status with age information
{
"eventType": "Verification.Result",
"data": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"status": "PASS",
"method": "id-document",
"ageCategory": "adult",
"age": {
"low": 25,
"high": 25
},
"dob": "1998-05-15"
}
}
FAIL status with age information
{
"eventType": "Verification.Result",
"data": {
"id": "123e4567-e89b-12d3-a456-426614174001",
"status": "FAIL",
"method": "age-estimation-scan",
"failureReason": "age-criteria-not-met",
"age": {
"low": 16,
"high": 17
}
}
}
FAIL status without age information
{
"eventType": "Verification.Result",
"data": {
"id": "123e4567-e89b-12d3-a456-426614174002",
"status": "FAIL",
"failureReason": "max-attempts-exceeded"
}
}
API endpoint response examples
PENDING status
{
"id": "123e4567-e89b-12d3-a456-426614174003",
"status": "PENDING"
}
IN_PROGRESS status
{
"id": "123e4567-e89b-12d3-a456-426614174004",
"status": "IN_PROGRESS"
}
PASS status with age information (without DOB)
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"status": "PASS",
"method": "id-document",
"ageCategory": "adult",
"age": {
"low": 25,
"high": 25
}
}
PASS status with DOB (includeDob = true)
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"status": "PASS",
"method": "id-document",
"ageCategory": "adult",
"age": {
"low": 25,
"high": 25
},
"dob": "1998-05-15"
}
FAIL status with age information
{
"id": "123e4567-e89b-12d3-a456-426614174001",
"status": "FAIL",
"method": "age-estimation-scan",
"failureReason": "age-criteria-not-met",
"age": {
"low": 16,
"high": 17
},
"ageCategory": "digital-minor"
}
FAIL status without age information
{
"id": "123e4567-e89b-12d3-a456-426614174002",
"status": "FAIL",
"failureReason": "max-attempts-exceeded"
}
Implementation checklist
Webhook events
- Handle both status types: PASS and FAIL (webhooks never send PENDING or IN_PROGRESS)
- Check for presence of
ageobject before accessingage.loworage.high - Use
ageCategoryfor access control when status is PASS andageCategoryis present - Don't use
ageCategoryfor FAIL status (it won't be present in webhook events) - Handle cases where
methodis absent (system-level failures) - Handle cases where
ageandageCategoryare absent (certain failure scenarios) - Validate
dobformat (YYYY-MM-DD) if present - Log
failureReasonfor debugging - Don't grant access for FAIL status
- Handle unknown
failureReasonvalues gracefully
API endpoint
- Handle all status types: PENDING, IN_PROGRESS, PASS, and FAIL
- For PENDING and IN_PROGRESS statuses, only expect
idandstatusfields - Set
includeDob=truequery parameter if DOB data is needed (seeGET /age-verification/get-status) - Check for presence of
ageobject before accessingage.loworage.high - Use
ageCategoryfor access control when status is PASS andageCategoryis present - Don't use
ageCategoryfor access control when status is FAIL, even if present - Handle cases where
methodis absent (system-level failures) - Handle cases where
ageandageCategoryare absent (certain failure scenarios) - Validate
dobformat (YYYY-MM-DD) if present - Log
failureReasonfor debugging - Don't grant access for FAIL status
- Handle unknown
failureReasonvalues gracefully - Implement appropriate polling strategy for PENDING and IN_PROGRESS statuses
Implementation notes
The ageCategory field is only included when status is PASS in webhook events. This ensures that age category information is only provided when the verification is successful. Note that the API endpoint can include ageCategory for FAIL status in some cases, but you shouldn't use it for access control decisions.
Version history
- 2024-12-05: Initial API contract document