Estimated time: 45-60 minutes for complete configuration
What will you learn from this manual?
That manual will teach you how to configure and use the web hooks system to automatically get a notice when a check KYC That's complete. No advanced technical skills required - Just follow the steps.
Before Start - Checks list
Be sure to have these elements ready:
- Web server with public accessible URL (HTTPS required)
- Ability to receive HTTP POST requests
- Basic knowledge of APIs REST
- Access to your platform JAAK configured
- code or system editor to handle HTTP requests
Contents Index
| Section | What will you do? | Time |
|---|---|---|
| Step 1 | To understand what webhooks are | 5 min |
| Step 2 | Configure webhole at JAAK | 15 min |
| Step 3 | Prepare endpoint to get data | 20 min |
| Step 4 | Test operation | 10 min |
| Step 5 | Replay answers | 15 min |
STEP 1: What is a Webhook?
Basic Concept
A web hook's like an "automatic messenger" that JAAK send your system every time a check KYC That's complete.
1.1 How does that work?
1. Full client KYC in JAAK →
2. JAAK process information →
3. JAAK send a notification to your URL →
4. Your system looks at details in the URL included
1.2 Benefits of the Webhole
| ♪ with Webhook | ♪ Without Webhole ♪ |
|---|---|
| You get an automatic notification | You have to manually check every result |
| Real-time processing | Delays in information |
| Immediate updates | Risk of missing notifications |
| Reducer load on your system | More calls API necessary |
1.3 Information to be received
The web hook gives you a Compact notification with the identifiers and the overall result of the session. The complete details (user data, document, validations) the later queries on the URL that comes into the same payload.
- Session identifier:
idandshortKey - Time marks: Home, end and duration
- Validation mode: How the session was solved (automatic, manual or pending review)
- Final stage (stage): Adopted, rejected, under review, etc.
- Scors: Numeric scores by component (survival, document, 1:1, etc.)
- Detail URL: Link signed to endpoint JAAK with all information
Step 2: Configure Webhook at JAAK
Objective
Configure the URL where JAAK send the notification after each check is complete.
Navigation path
Main Dashboard → Settings → My Company → Edit
2.1 Access Company Setup
Step 1: At the side menu go up to the "Adjustments"
Step 2: Click "My Company"
Step 3: Press the button "Edit" (pencil icon)
2.2 Configure Webhole KYC Traditional
Section "Product Setup KYC" you will find:
ÀCampos de Webhook
| Field | Description | Example | Is that obligatory? |
|---|---|---|---|
| URL | Address where JAAK will send the notification | https://tu-servidor.com/webhook/kyc | Recommended |
| Auth Key | Security key to authenticate calls | mi-clave-secreta-123 | Optional |
2.3 Configure Webhole URL
Correct URL format
) valid URLs:
https://mi-empresa.com/api/webhook/kyc
https://api.mi-empresa.com/kyc/results
https://servidor.mi-empresa.com:8080/webhook
Invalid URLs:
http://mi-empresa.com/webhook (no HTTPS)
mi-empresa.com/webhook (sin protocolo)
localhost:3000/webhook (no accesible públicamente)
Configure Auth Key
The Auth Key is a secret key that JAAK with each request as head Api-AuthKey so that you can verify that the web hook really comes from JAAKIf you leave the field empty, JAAK will send the web holok without authentication header - your endpoint should then accept the request without credentials or validate by another mechanism (IP allowlist, signature, etc.).
Recommendations:
- Use a combination of letters, numbers and symbols
- Minimum 16 characters
- Do not use personal or predictable information
- Keep her in a secure place
Example of secure Auth Key: JK2024-webhook-Auth-789XYZ
Information
Once saved, the Auth Key gets encrypted onto our servers and doesn't show back at dashboard. See only an indicator "Configure." To change it press "To change" and write the new key. If you leave the field empty while saving, the previous key remains.
2.4 Save Configure
- Complete the field URL (and optionally) Auth Key)
- Click "Save Changes"
- See a confirmation message
- The configuration will be activated immediately
Step 3: Prepare Endpoint to get Data
Objective
Configure your server to receive and process HTTP POST requests from JAAK.
3.1 Technical Specifications
) HTTP and Header Method
POST /tu-endpoint-webhook
Content-Type: application/json
Api-AuthKey: [TU-AUTH-KEY]
Important
The authentication head's literally called Api-AuthKey and the key goes as a direct value (without prefix Bearer). If you haven't set up Auth Key on dashboard, this head isn't sent.
Data structure that you will get
{
"id": "65f8a1b2c3d4e5f600000001",
"shortKey": "ABC123X",
"startedAt": "2026-01-15T10:27:36Z",
"endedAt": "2026-01-15T10:30:00Z",
"duration": "2.40m",
"validation": "AUTOMATIC",
"stage": "approved",
"scores": {
"liveness": 96.1,
"document": 98.2,
"oneToOne": 94.7,
"blacklist": 100.0,
"total": 95.5,
"status": "PASS",
"livenessPass": true,
"documentPass": true,
"oneToOnePass": true
},
"detailsURL": "https://api.jaak.ai/api/v1/kyc/session/65f8a1b2c3d4e5f600000001"
}
Information
The web hook includes personal information from the user (name, date of birth, document). To get that information please check the endpoint indicated at detailsURL using your API Key of JAAK.
3.2 Implementation of the Endpoint
Python (Flask) example
from flask import Flask, request, jsonify
app = Flask(__name__)
# Your Auth Key set up JAAK (if you set up)
AUTH_KEY = "JK2024-webhook-Auth-789XYZ"
@app.route('/webhook/kyc', methods=['POST'])
def webhook_kyc():
# Check authentication (only if you set up Auth Key at JAAK)
if AUTH_KEY:
received_key = request.headers.get('Api-AuthKey', '')
if received_key != AUTH_KEY:
return jsonify({"error": "Invalid auth key"}), 401
# Data processing
try:
data = request.get_json()
# Main fields of the web gain
session_id = data['id']
short_key = data['shortKey']
stage = data['stage'] # approved | rejected | in_review | ...
validation = data['validation'] # AUTOMATIC | MANUAL | NEED _ REVIEW
details_url = data['detailsURL']
print(f"KYC Closed Session: {session _ id} ({short _ key})")
print(f"stage: {stage} | Validation: {validation}")
# Business logic
process_kyc_result(data)
# To get personal information, name, document, etc.
# make an authenticated request to details _ url
return jsonify({"received": True}), 200
except Exception as e:
print(f"Error processing web hook: {e}")
return jsonify({"error": "Processing failed"}), 500
def process_kyc_result(data):
"""Your custom logic here"""
stage = data['stage']
if stage == "approved":
# Approved session - to activate account, send welcome, etc.
activate_user_account(data['id'])
elif stage == "rejected":
# Rejected meeting - notify, request reattempt, etc.
handle_rejection(data['id'])
elif stage == "in_review":
# Required manual review - notify compliance equipment
notify_manual_review(data['id'])
if __name__ == '__main__':
app.run(host='0.0.0.0', port=443, ssl_context='adhoc')
Example at Node.js (Express)
const express = require('express');
const app = express();
// Your Auth Key set up JAAK (if you set up)
const AUTH_KEY = "JK2024-webhook-Auth-789XYZ";
app.use(express.json());
app.post('/webhook/kyc', (req, res) => {
// Check authentication (only if you set up Auth Key at JAAK)
if (AUTH_KEY) {
const receivedKey = req.headers['api-authkey'] || '';
if (receivedKey !== AUTH_KEY) {
return res.status(401).json({ error: 'Invalid auth key' });
}
}
try {
const data = req.body;
const sessionId = data.id;
const shortKey = data.shortKey;
const stage = data.stage; // approved | rejected | in_review | ...
const validation = data.validation; // AUTOMATIC | MANUAL | NEED _ REVIEW
const detailsURL = data.detailsURL;
console.log(`KYC Completado - Sesión: ${sessionId} (${shortKey})`);
console.log(`Stage: ${stage} | Validación: ${validation}`);
processKycResult(data);
// To get personal information, name, document, etc.
// make an authenticated request to details
res.status(200).json({ received: true });
} catch (error) {
console.error('Error processing webhook:', error);
res.status(500).json({ error: 'Processing failed' });
}
});
function processKycResult(data) {
switch (data.stage) {
case 'approved':
activateUserAccount(data.id);
break;
case 'rejected':
handleRejection(data.id);
break;
case 'in_review':
notifyManualReview(data.id);
break;
}
}
app.listen(443, () => {
console.log('Webhook server running on port 443');
});
Example in PHP
<?php
header('Content-Type: application/json');
// Your Auth Key set up JAAK (if you set up)
$AUTH_KEY = "JK2024-webhook-Auth-789XYZ";
// Check HTTP method
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode(['error' => 'Method not allowed']);
exit;
}
// Check authentication (only if you set up Auth Key at JAAK)
if ($AUTH_KEY !== '') {
$receivedKey = $_SERVER['HTTP_API_AUTHKEY'] ?? '';
if ($receivedKey !== $AUTH_KEY) {
http_response_code(401);
echo json_encode(['error' => 'Invalid auth key']);
exit;
}
}
// Data processing
try {
$input = file_get_contents('php://input');
$data = json_decode($input, true);
if (!$data) {
throw new Exception('Invalid JSON');
}
$sessionId = $data['id'];
$shortKey = $data['shortKey'];
$stage = $data['stage'];
$validation = $data['validation'];
$detailsURL = $data['detailsURL'];
error_log("KYC Complete - Session: $sessionId ($shortKey)");
error_log("Status: $stage | Validation: $validation");
processKycResult($data);
http_response_code(200);
echo json_encode(['received' => true]);
} catch (Exception $e) {
error_log('Error processing webhook: ' . $e->getMessage());
http_response_code(500);
echo json_encode(['error' => 'Processing failed']);
}
function processKycResult($data) {
switch ($data['stage']) {
case 'approved':
activateUserAccount($data['id']);
break;
case 'rejected':
handleRejection($data['id']);
break;
case 'in_review':
notifyManualReview($data['id']);
break;
}
}
?>
3.3 Response requirements
Expected response
JAAK considers success if you get an HTTP 2xx status (ideally 200). isn't validated by JAAKbut it's good practice to give back a confirmed JSON:
HTTP/1.1 200 OK
Content-Type: application/json
{
"received": true
}
Timeout and Reattempts
- Timeout: JAAK expects a maximum of 10 seconds If your endpoint takes longer, the request gets aborted.
- Fire-and-get delivery: JAAK send the web hook onceIf your server's down or responded with error, No automatic reattempts.
- Recommendations:
- Answer quickly (200 OK) within 10 seconds. If your logic is heavy, get the event through and get it back to ground.
- The
id/shortKeyOn your side you barely get the web hole so you can reconcile. - If you need to re-get the result of a session, check the endpoint indicated at
detailsURLwith you API Key.
Step 4: Test Operation
Objective
Check that your web hook's functioning with a session KYC Test.
4.1 Prepare Test
Checklist Pre- Test
- URL web hold set up in JAAK
- Auth Key set up in JAAK (optional)
- Endpoint implemented and functioning
- Internet-accessible server (HTTPS)
- Loks enabling monitoring
4.2 Creating Test Session
-
Go to JAAK Dashboard:
KYC → Sesiones → Crear nueva sesión -
Complete form:
- Contact name: "Test Webhole"
- Flow name: "Prove -Webhook -001"
- Redirection URL: Your confirmation page
- Country of documentation: Your country set up
- Flow type: "KYC Traditional "
-
Save and copy URL: A URL as
https://kyc.sandbox.jaak.ai/session/ABC123X
4.3 Complete Verification
- Open Session URL in browser
- Following KYC:
- Allow camera access
- Capture document (front and back)
- Capture selfie / biometric
- Expected processing
- Monitoring login from your server while processing
4.4 Check Webhook Reception
What to Search in your Logs
If everything works properly, you should see:
[INFO] POST /webhook/kyc - Autenticación exitosa
[INFO] KYC Completado - Sesión: 65f8a1b2c3d4e5f600000001 (ABC123X)
[INFO] Stage: approved | Validación: AUTOMATIC
[INFO] Respuesta 200 enviada a JAAK
If there's problems, you can see:
[ERROR] POST /webhook/kyc - Api-AuthKey inválida
[ERROR] JSON malformado en webhook
[ERROR] Timeout procesando webhook
4.5 Validate JAAK Dashboard
- Go to:
KYC → Sesiones - Search your session: "Prove -Webhook -001"
- Check status: It should appear as complete
- Review logs: If there's a bad web hole, they'll come up here.
Step 5: Replay Answers from the Webhole
Objective
Fully understand the data you get from the web hold to implement the right business logic.
5.1 Campos del Webhook
| Field | Type | Description |
|---|---|---|
id | string | Unique session identifier (ObjectId). Use as a key to your system. |
shortKey | string | Legible short key, same as shown on dashboard from JAAK. |
startedAt | string (ISO8601) | Date and time of the sitting. |
endedAt | string (ISO8601) | Date and time when the session ended. |
duration | string | Total duration in minutes with format "N.NNm" (g: "2.40m"). |
validation | string (enum) | Resolution mode: AUTOMATIC, MANUAL or NEED_REVIEW. (see 5.2) |
stage | string (enum) | Final stage of the sitting: approved, rejected, in_review, expired(see 5.3) |
scores | object | Numeric scores by component (see 5.4). |
detailsURL | string (URL) | Endpoint JAAK where to check full details of the session. |
5.2 validation
| Value | Meaning |
|---|---|
AUTOMATIC | The session was automatically decided by the JAAK No human intervention. |
MANUAL | The session was manually revised and decided by an operator from the dashboard of JAAK. |
NEED_REVIEW | The session remained under manual review (the automatic motor was unable to decide). |
5.3 stage
The most common values you will get at an end session are:
| Value | Meaning | Recommended action |
|---|---|---|
approved | Successful verification | To activate account, conduct with onboarding |
rejected | Verification failed | Request Retrying or Additional Documents |
in_review | Requires manual review | Notify compliance equipment |
expired | The sitting expired without completion | Notify user, allow retrying |
lapsed | The session was defeated by inactivity | Notify user |
5.4 Field scores
Numeric scores by component. The values by component range from 0 to 100 (to more number, more confidence). status To sum up the overall result.
| Field | Type | Description |
|---|---|---|
liveness | number | Liveness detection Checks Stamp |
document | number | The document's check score |
oneToOne | number | Match score 1:1 (face vs. photo document) |
blacklist | number | Checks at restrictive lists |
total | number | Combined global score |
status | string | Additional result: PASS, FAIL, NEED_REVIEW, ERROR, EXPIRED |
livenessPass | boolean | If liveness passed the set threshold at your company |
documentPass | boolean | If document passed the set threshold |
oneToOnePass | boolean | If oneToOne passed the set threshold |
5.5 Check Extended Details
The web hook is deliberately compact. To get personal data extracted (name, date of birth, document number), captured images or detailed breakdown by step, check endpoint at detailsURL with an authenticated request using your API Key of JAAK.
curl -X GET "$DETAILS_URL" \
-H "Authorization: Bearer $JAAK_API_KEY"
5.6 Recommended Business Logic
Decision Flow
def process_kyc_webhook(data):
stage = data['stage']
validation = data['validation']
scores = data.get('scores', {}) or {}
total_score = scores.get('total', 0)
if stage == "approved":
if total_score >= 90:
# high confidence - automatic approval
auto_approve_user(data)
elif total_score >= 70:
# Medium confidence - monitoring approval
approve_with_monitoring(data)
else:
# Low confidence - internal manual review
queue_for_manual_review(data)
elif stage == "rejected":
# Analyse what component failed
if scores.get('livenessPass') is False:
request_retry_with_instructions(data, "liveness")
elif scores.get('documentPass') is False:
request_different_document(data)
else:
manual_review_required(data)
elif stage == "in_review":
# It requires manual review by JAAK
notify_compliance_team(data)
elif stage in ("expired", "lapsed"):
# Uncompleted meeting
send_retry_notification(data)
5.7 Special cases
Situations to be considered
High global confidence but some component failed:
{
"stage": "approved",
"scores": {
"total": 95.0,
"status": "PASS",
"livenessPass": true,
"documentPass": true,
"oneToOnePass": false
}
}
Action: Check manually - potential legitimate document but different person.
Low confidence while the session was adopted:
{
"stage": "approved",
"scores": {
"total": 65.0,
"status": "PASS",
"livenessPass": true,
"documentPass": true,
"oneToOnePass": true
}
}
Action: Adopt with additional monitoring - potential photo quality problem.
Session marked as in_review:
{
"stage": "in_review",
"validation": "NEED_REVIEW"
}
Action: Wait for an operator to JAAK or from your computer solve the session manually and you will get a second web hook with the final result (approved or rejected).
Common Problem Resolution
Common
Webhook isn't received
| Problem | probable cause | Resolution |
|---|---|---|
| No requests | Wrong URL at JAAK | Check configuration with "My Company" |
| Error 404 / 502 | Endpoint doesn't exist or server down | Check that your server's functioning |
| SSL / TLS error | Invalid certificate | Using valid HTTPS or renewal certificate |
| Timeout | Server slow response | Answer at < 10s and process at background |
| He only arrives once | Fire-and-forget, without retcondiciones | Check detailsURL to reconcile |
Authentication errors
| Error | Description | Resolution |
|---|---|---|
| "Missing Api-AuthKey" | Leader Api-AuthKey Not present | Check that your server reads the right header |
| Invalid auth key | The value of Api-AuthKey That doesn't match | Review Auth Key in Configure JAAK |
| constant error 401 | bad set up Auth Key | Regenerate Auth Key at JAAK |
Important
Make sure your server reads the header Api-AuthKey (JAAK Do not use Authorization: Bearer).
Procedural challenges
| Symptoms | Cause | Fix |
|---|---|---|
| JSON malformed | Data parseying error | Add robust bug management |
| Missing data | Structure changes | Check fields before using |
| Timeout while processing | Very slow logic | Move heavy processing to background |
Advanced Debugging
Highlights
import logging
import json
logging.basicConfig(level=logging.DEBUG)
@app.route('/webhook/kyc', methods=['POST'])
def webhook_kyc():
logger = logging.getLogger(__name__)
# Log headers completos
logger.debug(f"Headers recibidos: {dict(request.headers)}")
# Log body raw
raw_data = request.get_data()
logger.debug(f"Body raw: {raw_data}")
# Log IP origen
logger.debug(f"IP origen: {request.remote_addr}")
try:
data = request.get_json()
logger.info(f"Webhook procesado: {data.get('id')} ({data.get('shortKey')})")
# Log data structure
logger.debug(f"complete structure: {json.cg (data, indent = 2)}")
return jsonify({"received": True}), 200
except Exception as e:
logger.error(f"Reprocessing bug: {str (e)}", exc_info=True)
return jsonify({"error": str(e)}), 500
Test Webhole
To try your endpoint without a session KYC complete:
curl -X POST https://tu-servidor.com/webhook/kyc \
-H "Content-Type: application/json" \
-H "Api-AuthKey: JK2024-webhook-Auth-789XYZ" \
-d '{
"id": "65f8a1b2c3d4e5f600000001",
"shortKey": "TEST123",
"startedAt": "2026-01-15T10:27:36Z",
"endedAt": "2026-01-15T10:30:00Z",
"duration": "2.40m",
"validation": "AUTOMATIC",
"stage": "approved",
"scores": {
"liveness": 96.1,
"document": 98.2,
"oneToOne": 94.7,
"blacklist": 100.0,
"total": 95.5,
"status": "PASS",
"livenessPass": true,
"documentPass": true,
"oneToOnePass": true
},
"detailsURL": "https://api.jaak.ai/api/v1/kyc/session/65f8a1b2c3d4e5f600000001"
}'
Do you need additional help?
When to contact technical support
- Configure errors you can't solve
- Persistent connectivity challenges
- Changes to the data structure of the web gain
- Questions about integration with specific systems
Information to have ready at contact with support
- URL of your web hook set up
- Special bug logs with tipprints
- Example of request that's missing
- Environmental configuration (development / production)
- Problem Session ShortKey (if applicable)
Additional
- Documentation API JAAK: To check the details extended by
detailsURL - Postman Collection: To try endpoints manually
- SDK/ Libraries: If they are available for your language
- Status Page: To check service status JAAK
Final Summary
You have learned to:
- Configure URL webhole and Auth Key at JAAK
- Implement endpoint to receive notification
- To process and validate the web hold fields
- To manage different values of
stageandvalidation - Consult
detailsURLto get advanced data - To solve common problems
Future Recommended Steps
- Configure monitoring: Loks, alerts, metric
- Implement background processing: To respond quickly at < 10s
- Add additional validation: According to your business rules
- Document process: For your computer and future references
- Test in production: with actual transaction volumes
Congratulations! Now you have a complete system of websites for KYC Your system can now automatically get notifications and check with details of all the identity checks performed at JAAK.