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

SectionWhat will you do?Time
Step 1To understand what webhooks are5 min
Step 2Configure webhole at JAAK15 min
Step 3Prepare endpoint to get data20 min
Step 4Test operation10 min
Step 5Replay answers15 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 notificationYou have to manually check every result
Real-time processingDelays in information
Immediate updatesRisk of missing notifications
Reducer load on your systemMore 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: id and shortKey
  • 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

FieldDescriptionExampleIs that obligatory?
URLAddress where JAAK will send the notificationhttps://tu-servidor.com/webhook/kycRecommended
Auth KeySecurity key to authenticate callsmi-clave-secreta-123Optional

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

  1. Complete the field URL (and optionally) Auth Key)
  2. Click "Save Changes"
  3. See a confirmation message
  4. 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 / shortKey On 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 detailsURL with 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

  1. Go to JAAK Dashboard: KYC → Sesiones → Crear nueva sesión

  2. 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 "
  3. Save and copy URL: A URL as https://kyc.sandbox.jaak.ai/session/ABC123X

4.3 Complete Verification

  1. Open Session URL in browser
  2. Following KYC:
    • Allow camera access
    • Capture document (front and back)
    • Capture selfie / biometric
    • Expected processing
  3. 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

  1. Go to: KYC → Sesiones
  2. Search your session: "Prove -Webhook -001"
  3. Check status: It should appear as complete
  4. 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

FieldTypeDescription
idstringUnique session identifier (ObjectId). Use as a key to your system.
shortKeystringLegible short key, same as shown on dashboard from JAAK.
startedAtstring (ISO8601)Date and time of the sitting.
endedAtstring (ISO8601)Date and time when the session ended.
durationstringTotal duration in minutes with format "N.NNm" (g: "2.40m").
validationstring (enum)Resolution mode: AUTOMATIC, MANUAL or NEED_REVIEW. (see 5.2)
stagestring (enum)Final stage of the sitting: approved, rejected, in_review, expired(see 5.3)
scoresobjectNumeric scores by component (see 5.4).
detailsURLstring (URL)Endpoint JAAK where to check full details of the session.

5.2 validation

ValueMeaning
AUTOMATICThe session was automatically decided by the JAAK No human intervention.
MANUALThe session was manually revised and decided by an operator from the dashboard of JAAK.
NEED_REVIEWThe 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:

ValueMeaningRecommended action
approvedSuccessful verificationTo activate account, conduct with onboarding
rejectedVerification failedRequest Retrying or Additional Documents
in_reviewRequires manual reviewNotify compliance equipment
expiredThe sitting expired without completionNotify user, allow retrying
lapsedThe session was defeated by inactivityNotify 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.

FieldTypeDescription
livenessnumberLiveness detection Checks Stamp
documentnumberThe document's check score
oneToOnenumberMatch score 1:1 (face vs. photo document)
blacklistnumberChecks at restrictive lists
totalnumberCombined global score
statusstringAdditional result: PASS, FAIL, NEED_REVIEW, ERROR, EXPIRED
livenessPassbooleanIf liveness passed the set threshold at your company
documentPassbooleanIf document passed the set threshold
oneToOnePassbooleanIf 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

Problemprobable causeResolution
No requestsWrong URL at JAAKCheck configuration with "My Company"
Error 404 / 502Endpoint doesn't exist or server downCheck that your server's functioning
SSL / TLS errorInvalid certificateUsing valid HTTPS or renewal certificate
TimeoutServer slow responseAnswer at < 10s and process at background
He only arrives onceFire-and-forget, without retcondicionesCheck detailsURL to reconcile

Authentication errors

ErrorDescriptionResolution
"Missing Api-AuthKey"Leader Api-AuthKey Not presentCheck that your server reads the right header
Invalid auth keyThe value of Api-AuthKey That doesn't matchReview Auth Key in Configure JAAK
constant error 401bad set up Auth KeyRegenerate Auth Key at JAAK

Important

Make sure your server reads the header Api-AuthKey (JAAK Do not use Authorization: Bearer).

Procedural challenges

SymptomsCauseFix
JSON malformedData parseying errorAdd robust bug management
Missing dataStructure changesCheck fields before using
Timeout while processingVery slow logicMove 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 stage and validation
  • Consult detailsURL to get advanced data
  • To solve common problems

Future Recommended Steps

  1. Configure monitoring: Loks, alerts, metric
  2. Implement background processing: To respond quickly at < 10s
  3. Add additional validation: According to your business rules
  4. Document process: For your computer and future references
  5. 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.