Webhooks
Webhooks let you subscribe to events happening in the k-ID Engine as they happen, as opposed to polling an API to see if data is available.
Webhooks can be used for a variety of purposes, such as:
- Handling adult verification results
- Handling age assurance results
- Handling challenge state changes
Setting Up Webhooks
Webhooks are configured in the Publisher Portal, by specifying a URL that the k-ID Engine will call when an event occurs. The URL must be a secure HTTPS URL. The k-ID Engine will send a POST request to the URL with a JSON payload that contains the event data.
Webhooks can be configured on Developer Settings of a selected product. You can access this page at /products/[productId]/developer
.
Webhooks Configuration Page
The Webhooks section in Developer Settings allows you to configure HTTPS URLs for k-ID to call when specific events occur. By entering the desired webhook URLs for your application and clicking Save, your configuration is updated in the system. The changes are automatically applied to the appropriate environment — Test Mode or Live Mode — based on your current settings.
This ensures that event notifications are routed correctly and securely to your application, whether you're testing or operating in production.
Note: The Save button is different from the Push to Test and Publish Live buttons. While saving and updating a webhook does not directly impact your users, changes made using Push to Test or Publish Live may affect the overall user experience and might require a review by the k-ID team before taking effect.
Additionally, there is a Test Webhook button that allows you to verify if your endpoint is set up correctly, with or without secrets. You can find more details on validating webhook requests in the documentation. This button simulates a test event, which you can reference in the test event section of the documentation.
Webhook Event Structure
The JSON payload sent to the webhook URL will contain the following fields:
eventType
- The type of event that occurred.data
- The data associated with the event.
An X-Event-Type
header will also be sent with the event type.
Validating Webhook Requests
Webhooks are sent over the public internet, so it is important to validate that the requests are coming from k-ID. This is done by verifying the event payload signature using the configured webhook secret.
All requests will include the following headers:
X-Signature-Timestamp
- The timestamp of the request, in Unix epoch seconds.X-Signature-SHA256
- The SHA-256 hash of the webhook secret, timestamp, and request body, encoded as a hexadecimal string.
If the signature is invalid, the request should be rejected with a 401 status code.
Example code
// Your webhook secret, configured in the Publisher Portal.
const SECRET = "your-secret";
const timestamp = req.get("X-Signature-Timestamp");
const signature = req.get("X-Signature-SHA256");
const body = req.rawBody; // Raw request body, as a string.
// Calculate the expected signature using your favorite crypto library.
const expectedSignature = crypto
.createHash("sha256")
.update(SECRET + timestamp + req.rawBody)
.digest("hex");
const isVerified = crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
if (!isVerified) {
return res.status(401).end("Invalid signature");
}
Webhook Event Types
The following event types are available:
Test
Challenge.StateChange
Session.ChangePermissions
Session.Delete
Verification.Result
AdultVerification.Result
AgeAssurance.Result
Test
This event type is used to verify that the webhook is working correctly. It should be handled by the webhook receiver.
Example payload:
{
"eventType": "Test",
"data": {
"id": "12345678-1234-1234-1234-123456789abc"
}
}
Challenge State Change
Properties:
id
- The challenge ID.productId
- The product ID.status
- Can bePASS
,FAIL
, orIN_PROGRESS
.sessionId
(optional) - If the status isPASS
, the session ID.approverEmail
(optional) - If the status isPASS
, the email of the approver.kuid
(optional) - If the status ispass
, the k-ID user id.
Example payload:
{
"eventType": "Challenge.StateChange",
"data": {
"id": "683409f1-2930-4132-89ad-827462eed9af",
"productId": 42,
"status": "PASS",
"sessionId": "0ad1641f-c154-4cc2-8bb2-74dbd0de7723",
"approverEmail": "user@example.com",
"kuid": "123456"
}
}
Session Change Permissions
For Session permission changes, events of this type will only be sent to your webhook receiver when the permissions are directly modified by a parent in the k-ID Family Portal. If a player has a birthday that would put them in a different age category, or above an age threshold for their jurisdiction which would allow them access to more features, the game must invoke the /session/get
API to receive the changed permissions for the Session
.
Properties:
id
- The session ID.productId
- The product ID.
Example payload:
{
"eventType": "Session.ChangePermissions",
"data": {
"id": "78c299b2-5c33-4bde-84fe-8fc950fc7a96",
"productId": 42
}
}
Session Delete
Properties:
id
- The session ID.productId
- The product ID.
Example payload:
{
"eventType": "Session.Delete",
"data": {
"id": "2d064cf7-0726-4193-b19a-8bd387937e60",
"productId": 42
}
}
Verification Result
Properties:
id
- The unique verification ID.status
- Can bePASS
,FAIL
, orINCONCLUSIVE
.ageCategory
(optional) - The estimated age category. Can beadult
,digital-youth
, ordigital-minor
. This is only set ifstatus
isPASS
.method
(optional) - The verification method used. Can beid-document
,credit-card
, orage-estimation
. This is only set ifstatus
isPASS
.age
(optional) - The age details. This is only set ifstatus
isPASS
and if the verification scenario is configured to return the age.
age
properties:
low
- The lower bound of the estimated age. In the case of a hard age verification method, such as an ID document check, this will be the exact age.high
- The upper bound of the estimated age. In the case of a hard age verification method, such as an ID document check, this will be the exact age.confidence
- A float between 0 and 1, inclusive, indicating the confidence in the estimated age range. In the case of a hard age verification method, such as an ID document check, this will be 1.
Example payload:
{
"eventType": "Verification.Result",
"data": {
"id": "5a58e98a-e477-484b-b36a-3857ea9daaba",
"status": "PASS",
"ageCategory": "adult",
"method": "id-document",
"age": {
"low": 25,
"high": 25,
"confidence": 1
}
}
}
Adult Verification Result
Properties:
id
- The unique verification ID.status
- Can bePASS
,FAIL
, orINCONCLUSIVE
.ageRange
(optional) - Details about the estimated age range.
ageRange
properties:
minAge
- The estimated minimum age.maxAge
- The estimated maximum age.confidence
- A number between 0 and 1 indicating the confidence in the estimated age range.
Example payload:
{
"eventType": "AdultVerification.Result",
"data": {
"id": "5a58e98a-e477-484b-b36a-3857ea9daaba",
"status": "PASS"
}
}
Age Assurance Result
Properties:
id
- The unique verification ID.status
- Can bePASS
,FAIL
, orINCONCLUSIVE
.ageRange
(optional) - Details about the estimated age range.
ageRange
properties:
minAge
- The estimated minimum age.maxAge
- The estimated maximum age.confidence
- A number between 0 and 1 indicating the confidence in the estimated age range.
Example payload:
{
"eventType": "AgeAssurance.Result",
"data": {
"id": "5a58e98a-e477-484b-b36a-3857ea9daaba",
"status": "PASS",
"ageRange": {
"minAge": 18,
"maxAge": 25,
"confidence": 0.8
}
}
}