Waterfall flow
Age verification with k-ID is a privacy-preserving process that allows users to prove their age without revealing personal information. This approach uses a Waterfall flow model.
Waterfall flow
AgeKit+ acts as a single-point orchestrator for age checks, automatically cascading through a waterfall of verification providers to confirm a user's age. In practice, one API call to k-ID presents the configured methods in sequence. For example, starting with email inference or a facial age estimation and then falling back to an ID document scan or other methods as needed, until the user's age is verified or all options are exhausted. This means developers integrate once with k-ID's API, and the platform handles trying multiple verification techniques behind the scenes, combining methods to maximize the chances of a successful verification.
The verification flow is initiated with an API call that returns a URL to be hosted in an iframe or mobile web view, where users complete the verification process. The available verification methods are determined by your product configuration in the Compliance Studio, ensuring compliance with jurisdiction requirements.
| API | Scenario |
|---|---|
/age-verification/perform-access-age-verification | To verify the age of a user before getting access to a feature, mature content, or the product itself. |
/age-verification/perform-trusted-adult-verification | To perform trusted adult (parent or guardian) verification. |
/age-verification/perform-age-appeal | For users who have failed age verification but want to appeal the decision. |
The Age Verification APIs are standardized in terms of the request & response format.
Request body
| Property | Description | Required? |
|---|---|---|
jurisdiction | The jurisdiction in which the age verification should happen | Yes |
criteria | The criteria for age verification | Yes |
subject.email | If the user verified their age with k-ID in any other context with an email address, then the original age is returned instead of asking the user to estimate or prove their age again. | No |
subject.claimedAge | If a user was asked for their age in an age gate, used to inform the age estimation process | No |
subject.id | An identifier used across multiple verification methods to report multiple failed attempts. This can be a temporary session ID, or hashed user ID. | No |
options.facialAgeEstimation.minAge | The minimum acceptable age from facial age estimation results. This should typically be set higher than criteria.age to account for the inherent variance in age estimation technology. For example, if your requirement is 18+, setting minAge to 21-25 provides a confidence buffer that reduces false positives. This ensures users who pass facial age estimation are more likely to meet your actual age requirement. | No |
Sample:
{
"jurisdiction": "US-CA",
"subject": {
"email": "user@example.com",
"claimedAge": 23,
"id": "3854909b-8888-4bed-9282-24b74c4a3c97"
},
"criteria": {
"ageCategory": "DIGITAL_YOUTH_OR_ADULT"
},
"options": {
"facialAgeEstimation": {
"minAge": 21
}
}
}
Response body
A successful request to the Age Verification API returns the following response.
| Property | Description |
|---|---|
id | A unique verification ID generated by Age Verification Service |
url | The age verification URL that must be embedded in an iframe and presented to the user, for them to verify themselves. |
Sample:
{
"id": "7854909b-9124-4bed-9282-24b44c4a3c97",
"url": "https://family.k-id.com/verify?token=eyJ..."
}
Embedding the verification interface
Use the returned URL to create an iframe in your website or app. Users complete their verification through this interface, with available methods automatically adapting to jurisdictional requirements.

<div id="verification-container">
<iframe
id="verification-widget"
src="VERIFICATION_URL"
width="100%"
height="600"
frameborder="0"
allow="camera;payment;publickey-credentials-get;publickey-credentials-create">
</iframe>
</div>
The allow attribute is required to enable the following features:
camera: Required for facial age estimationpayment: Required for credit card verificationpublickey-credentials-getandpublickey-credentials-create: Required for WebAuthn-based verification methods
Verification result
Once the user has successfully completed the age verification, or the user has retried the maximum number of times and hasn't succeeded, the Age Verification Result is delivered through both client-side and server-side channels. Implementations should use a combination of both: client-side events are best for controlling UI elements, while for data integrity, the actual results should come from either a webhook or a call to /age-verification/get-status.
Client-side (DOM events) - If the URL from the response body is included in an iframe, it's sent to the parent frame as a window message (MessageEvent) with a Verification.Result structure.
Server-side (webhooks) - An event is sent to the registered webhook in the form of a Verification.Result event.
Example of accessing the window message:
const handleMessage = (event: MessageEvent) => {
const message = event.data;
if (message.eventType === "Verification.Result") {
// Use DOM Events for immediate UI updates
updateUI(message);
}
};
window.addEventListener("message", handleMessage);
For data integrity, always verify results with events from webhooks or by calling /age-verification/get-status rather than relying solely on DOM Events. DOM Events are best suited for responsive UI updates.
The data element of the window event and the webhook event contains the following properties.
| Property | Description |
|---|---|
id | The verification ID for which this is the result. |
status | Indicates a PASS or FAIL status, based on whether the user met the age criteria or not. |
ageCategory | Indicates the age category the user belongs to in the jurisdiction specified in the request. Supported values are adult, digital-youth or digital-minor |
method | Indicates the method used for the verification. Supported values are id-document, age-estimation, age-attestation, credit-card, social-security-number |
failureReason | The reason the verification failed. Supported values are age-criteria-not-met, max-attempts-exceeded, or fraudulent-activity-detected. This is only set if status is FAIL |
age | Returns the lower bound and higher bound of the estimated or verified age as low and high. |
Sample:
{
"eventType": "Verification.Result",
"data": {
"id": "5a58e98a-e477-484b-b36a-3857ea9daaba",
"status": "PASS",
"ageCategory": "adult",
"method": "id-document",
"age": {
"low": 25,
"high": 25,
}
}
}
Handling a window event:
const handleMessage = (event: MessageEvent) => {
const message = event.data;
if (message.eventType === "Verification.Result" && ) {
if (message.data.status === "PASS") {
window.location.href = `https://www.example.com/success?verificationId=${message.data.id}`
}
if (message.data.status === "FAIL") {
window.location.href = `https://www.example.com/fail?verificationId=${message.data.id}`
}
}
};
window.addEventListener("message", handleMessage);
Verification error
If an unexpected error has occurred, a JavaScript event fires so that your implementation can gracefully handle the error.
For detailed information about the event structure, see Verification.Error.
Sample Message:
{
"eventType": "Verification.Error",
"method": "credit-card",
"status": "ERROR"
}
Checking verification status
In addition to sending events both in JavaScript and through the k-ID webhook, it's also possible to query for status for a verification. This is useful to be able to handle cases where the registered webhook was unreachable for a period of time, and the status event was never sent. To get status for a verification, use the /age-verification/get-status API. The data structure returned is identical to the Verification.Result event data sent to the webhook. For more information about webhook events, see Webhooks.
Limiting verification attempts
Each verification request allows users three attempts per available verification method. A verification fails if:
- All available verification methods have been exhausted and an age can't be determined
- An age is determined but falls below the required threshold for your criteria
When a verification fails, you can allow users to initiate a new verification attempt. However, to prevent misuse and abuse of the verification system, you should implement rate limiting on additional verification attempts. For example, you might limit users to three verification attempts within a 24-hour period.
Use the subject.id field in the verification request to track attempts across multiple verification requests. This field should contain a consistent identifier for the user (such as a temporary session ID or hashed user ID), allowing you to:
- Track the number of verification attempts per user
- Implement time-based rate limiting (for example, 3 attempts per 24 hours)
- Prevent users from bypassing limits by creating new sessions
Implement rate limiting on your server before initiating verification requests. This prevents unnecessary API calls and helps protect your system from abuse.
Verification methods
For detailed information about all available verification methods, see Verification methods.