Skip to main content

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:

  1. Handling adult verification results
  2. Handling age assurance results
  3. 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

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 be PASS, FAIL, or INCONCLUSIVE.
  • 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 be PASS, FAIL, or INCONCLUSIVE.
  • 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 be PASS, FAIL, or IN_PROGRESS.
  • sessionId (optional) - If the status is PASS, the session ID.
  • approverEmail (optional) - If the status is PASS, 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
}
}