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.
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
AdultVerification.Result
AgeAssurance.Result
Challenge.StateChange
Session.ChangePermissions
Session.Delete
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"
}
}
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
}
}
}
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.
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"
}
}
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
}
}