Skip to main content

Server Integration

Build a complete backend integration with Kora Compliance for customer onboarding screening.

Overview

A typical integration flow:

  1. Customer submits onboarding data to your server
  2. Your server sends a screening request to Kora Compliance
  3. Kora Compliance returns a risk score and decision
  4. Your server acts on the decision (approve, review, or block)
  5. For async mode, receive results via webhook

Create a Screening

const express = require("express");
const app = express();
app.use(express.json());

const API_KEY = process.env.KORA_API_KEY;
const TENANT_ID = process.env.KORA_TENANT_ID;
const BASE_URL = "https://api.korastratum.com/api/v1";

app.post("/onboard", async (req, res) => {
const { name, dateOfBirth, nationality, documentType, documentNumber } =
req.body;

// Screen the customer
const screening = await fetch(`${BASE_URL}/screenings`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"X-Tenant-ID": TENANT_ID,
"Content-Type": "application/json",
},
body: JSON.stringify({
mode: "SYNC",
purpose: "ONBOARDING",
subject: {
type: "INDIVIDUAL",
name,
date_of_birth: dateOfBirth,
nationality,
identifiers: [
{
type: documentType,
value: documentNumber,
country: nationality,
},
],
},
checks: ["SANCTIONS", "PEP", "ADVERSE_MEDIA"],
}),
});

const result = await screening.json();

// Act on the decision
switch (result.decision.outcome) {
case "APPROVE":
// Proceed with onboarding
return res.json({ status: "approved", customerId: "..." });

case "APPROVE_WITH_MONITORING":
// Approve but flag for monitoring
return res.json({ status: "approved", monitoring: true });

case "REVIEW_REQUIRED":
// Queue for compliance review
return res.json({
status: "pending_review",
message: "Your application is under review",
});

case "BLOCK":
// Deny onboarding
return res.status(403).json({
status: "blocked",
message: "Unable to proceed with onboarding",
});
}
});

Handle Webhook Callbacks

For async screenings or real-time events, set up a webhook handler:

const crypto = require("crypto");

app.post("/webhooks/compliance", (req, res) => {
// Verify webhook signature
const signature = req.headers["x-webhook-signature"];
const payload = JSON.stringify(req.body);
const expected = crypto
.createHmac("sha256", process.env.WEBHOOK_SECRET)
.update(payload)
.digest("hex");

if (signature !== expected) {
return res.status(401).send("Invalid signature");
}

const { event, data } = req.body;

switch (event) {
case "screening.completed":
console.log(`Screening ${data.screening_id}: ${data.decision.outcome}`);
// Process the screening result
break;

case "screening.match_found":
console.log(`Match found: ${data.match.source} (${data.match.score})`);
break;

case "risk.threshold_breached":
console.log(`Risk threshold breached for subject ${data.subject_id}`);
break;
}

res.status(200).send("OK");
});

Create and Manage Subjects

For ongoing monitoring, create a subject record that persists across screenings:

# Create a subject
curl -X POST https://api.korastratum.com/api/v1/subjects \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "X-Tenant-ID: YOUR_TENANT_ID" \
-H "Content-Type: application/json" \
-d '{
"type": "INDIVIDUAL",
"name": "Jane Smith",
"date_of_birth": "1985-03-20",
"nationality": "GB",
"identifiers": [
{"type": "PASSPORT", "value": "GB123456", "country": "GB"}
]
}'

# Screen the subject by ID
curl -X POST https://api.korastratum.com/api/v1/screenings \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "X-Tenant-ID: YOUR_TENANT_ID" \
-H "Content-Type: application/json" \
-d '{
"mode": "SYNC",
"purpose": "PERIODIC",
"subject_id": "subj_abc123",
"checks": ["SANCTIONS", "PEP"]
}'

# Get the subject's details
curl https://api.korastratum.com/api/v1/subjects/subj_abc123 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "X-Tenant-ID: YOUR_TENANT_ID"

Error Handling

Always check for error responses and handle them appropriately:

const response = await fetch(`${BASE_URL}/screenings`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"X-Tenant-ID": TENANT_ID,
"Content-Type": "application/json",
},
body: JSON.stringify(screeningPayload),
});

if (!response.ok) {
const error = await response.json();

switch (error.code) {
case "RATE_LIMITED":
// Back off and retry
const retryAfter = response.headers.get("Retry-After");
break;
case "VALIDATION_ERROR":
// Fix the request
console.error("Validation errors:", error.details);
break;
case "SCREENING_TIMEOUT":
// Switch to async mode
break;
default:
console.error(`Error: ${error.code} - ${error.message}`);
}
}

See Error Codes for the full error reference.