Screening API

Perform real-time screening of individuals and organisations against global sanctions lists, PEPs (Politically Exposed Persons), watchlists, and adverse media sources.

Test Mode Supported

Real screening calls are only made in live mode. In test mode, all screenings return deterministic mock results instantly - no credits consumed, no external API calls. Results are controlled by keywords in the entity name. See test mode triggers ↓

What Gets Screened

  • Sanctions: OFAC, UN, EU, UK HMT, DFAT and more
  • Watchlists: Regulatory enforcement, disqualified directors
  • PEPs: Politically Exposed Persons and their relatives/close associates
  • Adverse Media: Negative news, fraud allegations, financial crime

How Screening Works

Screening is an asynchronous process:

1. Submit
POST /screening/
Returns 202 immediately
2. Process
asynchronously
Potential risks found
3. Get Results
Webhook or GET
Review risk profiles
One Screening Per Entity

Each entity can only be screened once. Subsequent requests return 409 Conflict with the existing screening details.

Screen Entity

Submit an existing entity for KYC/AML screening. Returns immediately while screening runs asynchronously.

POST /api/v1/screening/
POST /api/v2/screening/

Request Body

ParameterTypeRequiredDescription
entity_iduuidYesID of existing entity to screen
webhook_urlstringNoWebhook URL for completion notification (overrides tenant default)
monitoring_enabledbooleanNo Explicitly enable or disable ongoing monitoring. If omitted, the tenant's default setting is used.

Returns 202 Accepted immediately. The screening runs asynchronously.

Screen Entity

curl -X POST https://api.kycgenie.com/api/v1/screening/ \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: screen-entity-550e8400" \
  -d '{
    "entity_id": "550e8400-e29b-41d4-a716-446655440000",
    "webhook_url": "https://your-domain.com/webhooks/screening"
  }'
curl -X POST https://api.kycgenie.com/api/v2/screening/ \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: screen-entity-550e8400" \
  -d '{
    "entity_id": "550e8400-e29b-41d4-a716-446655440000",
    "webhook_url": "https://your-domain.com/webhooks/screening",
    "monitoring_enabled": true
  }'
import requests

entity_id = "550e8400-e29b-41d4-a716-446655440000"

response = requests.post(
    "https://api.kycgenie.com/api/v1/screening/",
    headers={
        "Authorization": "Bearer YOUR_API_KEY",
        "Content-Type": "application/json",
        "Idempotency-Key": f"screen-entity-{entity_id}",
    },
    json={
        "entity_id": entity_id,
        "webhook_url": "https://your-domain.com/webhooks/screening",
    },
)
result = response.json()
print(f"Screening ID: {result['screening_id']}")
from kycgenie import KYCGenie

client = KYCGenie(api_key="YOUR_API_KEY")

result = client.screening.screen(
    entity_id="550e8400-e29b-41d4-a716-446655440000",
    webhook_url="https://your-domain.com/webhooks/screening",
    monitoring_enabled=True,
)

print(f"Screening ID: {result.screening_id}")
print(f"Status: {result.screening_status}")
const entityId = "550e8400-e29b-41d4-a716-446655440000";

const res = await fetch("https://api.kycgenie.com/api/v1/screening/", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
    "Idempotency-Key": `screen-entity-${entityId}`,
  },
  body: JSON.stringify({
    entity_id: entityId,
    webhook_url: "https://your-domain.com/webhooks/screening",
  }),
});
const result = await res.json();
console.log(`Screening ID: ${result.screening_id}`);
const entityId = "550e8400-e29b-41d4-a716-446655440000";

const res = await fetch("https://api.kycgenie.com/api/v2/screening/", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
    "Idempotency-Key": `screen-entity-${entityId}`,
  },
  body: JSON.stringify({
    entity_id: entityId,
    webhook_url: "https://your-domain.com/webhooks/screening",
    monitoring_enabled: true,
  }),
});
const result = await res.json();
console.log(`Screening ID: ${result.screening_id}`);

202 Accepted Response

{
  "screening_id": "62ee34a4-28f0-4a83-a016-7441e7900d7e",
  "entity_id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "Acme Corp Ltd",
  "entity_type": "company",
  "screening_status": "pending",
  "message": "Screening initiated"
}

409 - Already Screened

{
  "code": "CONFLICT",
  "message": "Entity already screened.",
  "details": {
    "screening_id": "62ee34a4-28f0-4a83-a016-7441e7900d7e",
    "entity_id": "550e8400-e29b-41d4-a716-446655440000",
    "screening_status": "completed",
    "screened_at": "2026-01-15T10:30:00Z"
  }
}

Test Mode Triggers

When using a test API key, screenings are simulated. The result is determined by keywords in the entity's name.

How triggers work

The keyword match is case-insensitive and substring-based. If the entity name contains SANCTION anywhere (e.g. "Maria Sanction Lopez"), the sanction bucket fires. If no keyword matches, the default pass result is returned.

Trigger Keywords

Keyword in namescreening_resultCase / Alert / RiskProfile created?AML types
(none)CLEAR No - clean result, no review needed-
REVIEWHAS_PROFILES YesADVERSE_MEDIA, ADVERSE_MEDIA_V2_OTHER_MINOR
PEPHAS_PROFILES YesPEP, PEP_CLASS_1
MEDIAHAS_PROFILES YesADVERSE_MEDIA, ADVERSE_MEDIA_V2_NARCOTICS_AML_CFT, ADVERSE_MEDIA_V2_VIOLENCE_AML_CFT
SANCTIONHAS_PROFILES YesSANCTION, SANCTION_INDIVIDUAL

What gets created for non-PASS buckets

For any bucket other than pass, the full review chain is created locally in your test environment - no external calls made:

  • One Case (status open, no case ID)
  • One Alert (with a mock_alert_* reference ID)
  • One RiskProfile (status not_reviewed, with bucket-appropriate AML types)

The case.opened and alert.created webhooks are fired so you can test your webhook consumer end-to-end.

// PASS - clean, no Case created
{ "name": "Acme Consulting Ltd", "entity_type": "company" }

// REVIEW - adverse media hit, Case + Alert + RiskProfile created
{ "name": "REVIEW Holdings", "entity_type": "company" }

// PEP - politically exposed person hit
{ "name": "Mr PEP Johansson", "entity_type": "individual" }

// FAIL - high-risk adverse media
{ "name": "MEDIA Corp SA", "entity_type": "company" }

// SANCTION - sanctions hit, highest risk score
{ "name": "SANCTION Trading Ltd", "entity_type": "company" }

Get Screening Results

Retrieve screening results for an entity. Returns the most recent screening with a nested hierarchy of Cases → Alerts → RiskProfiles. This is the lightweight summary view - risk profile boolean flags only, no full sensitive data objects.

GET /api/v1/screening/{entity_id}/
GET /api/v2/screening/{entity_id}/

Returns 200 OK. Use the detailed endpoint for full PEP / sanctions / media JSON.

Get Screening Results

curl https://api.kycgenie.com/api/v1/screening/550e8400-e29b-41d4-a716-446655440000/ \
  -H "Authorization: Bearer YOUR_API_KEY"
curl https://api.kycgenie.com/api/v2/screening/550e8400-e29b-41d4-a716-446655440000/ \
  -H "Authorization: Bearer YOUR_API_KEY"
import requests

entity_id = "550e8400-e29b-41d4-a716-446655440000"

response = requests.get(
    f"https://api.kycgenie.com/api/v1/screening/{entity_id}/",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = response.json()
print(f"Status: {data['screening']['status']}")
for case in data["screening"]["cases"]:
    for alert in case["alerts"]:
        for rp in alert["risk_profiles"]:
            print(f"  Risk profile: {rp['name']} (score={rp['matching_score']})")
from kycgenie import KYCGenie

client = KYCGenie(api_key="YOUR_API_KEY")

data = client.screening.get(
    entity_id="550e8400-e29b-41d4-a716-446655440000",
)

const entityId = "550e8400-e29b-41d4-a716-446655440000";

const res = await fetch(
  `https://api.kycgenie.com/api/v1/screening/${entityId}/`,
  { headers: { "Authorization": "Bearer YOUR_API_KEY" } }
);
const data = await res.json();
console.log(`Status: ${data.screening.status}`);
const entityId = "550e8400-e29b-41d4-a716-446655440000";

const res = await fetch(
  `https://api.kycgenie.com/api/v2/screening/${entityId}/`,
  { headers: { "Authorization": "Bearer YOUR_API_KEY" } }
);
const data = await res.json();
console.log(`Status: ${data.screening.status}`);

Response Example (200 OK)

{
  "screening": {
    "id": "62ee34a4-28f0-4a83-a016-7441e7900d7e",
    "entity": {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "John Doe",
      "entity_type": "individual"
    },
    "status": "completed",
    "screening_type": "initial",
    "latest_case_decision": "acceptable_risk",
    "creator_profile": {
      "id": "5c4fdd14-93c8-4653-9c2b-a45f58654599",
      "name": "Jane Smith",
      "email": "jane@example.com"
    },
    "decider_profile": null,
    "created_at": "2026-01-07T14:35:36Z",
    "updated_at": "2026-01-09T14:04:11Z",
    "cases": [
      {
        "id": "c8f16c1d-8e55-4ade-afe4-dbc472f49a31",
        "title": "Case for John Doe - Onboarding",
        "status": "closed",
        "decision": "acceptable_risk",
        "assigned_to": null,
        "closed_by": {
          "id": "5c4fdd14-93c8-4653-9c2b-a45f58654599",
          "name": "Jane Smith",
          "email": "jane@example.com"
        },
        "closed_at": "2026-01-09T14:04:11Z",
        "created_at": "2026-01-07T14:35:39Z",
        "updated_at": "2026-01-09T14:04:11Z",
        "alerts": [
          {
            "id": "5bc52924-8a4f-48ae-acaa-13027deae060",
            "risk_profiles": [
              {
                "id": "f67f165d-0d1e-4eb7-81e6-3494a260dcd4",
                "name": "John Doe - Adverse Media, PEP",
                "entity_type": "individual",
                "status": "false_positive",
                "matching_score": 0.3,
                "matching_name": "John Doe",
                "match_type": ["aka_exact", "name_variations_removal"],
                "dates_of_birth": ["1975", "1975-06-21"],
                "also_known_as": ["Johnathan Doe", "John Doe Jr."],
                "all_related_countries": ["AU", "BR", "US"],
                "has_pep": true,
                "has_sanctions": false,
                "has_adverse_media": true,
                "has_watchlists": false
              }
            ]
          }
        ]
      }
    ]
  }
}

Risk Profile Fields (Summary)

FieldTypeDescription
iduuidUnique risk profile identifier
namestringMatched entity name with risk types, e.g. "John Doe - PEP, Sanctions"
entity_typestringindividual or company
statusstringnot_reviewed | in_review | false_positive | true_positive
matching_scorefloatConfidence 0.0–1.0. ≥ 0.8 = high confidence; < 0.5 = likely false positive.
matching_namestringExact name from watchlist that triggered the match
match_typearrayHow the match was made: name_exact, aka_exact, name_variations_removal, etc.
dates_of_birtharrayKnown dates of birth (YYYY or YYYY-MM-DD)
also_known_asarrayAliases and alternative names
all_related_countriesarrayISO 3166-1 alpha-2 country codes associated with the risk
has_pepbooleanTrue if PEP data exists
has_sanctionsbooleanTrue if sanctions data exists
has_adverse_mediabooleanTrue if adverse media articles exist
has_watchlistsbooleanTrue if watchlist data exists

Get Detailed Results

Retrieve the same screening structure as the summary endpoint, but with full sensitive data included: pep, sanctions, media, and watchlists JSON objects on each risk profile. Use this for compliance review and inspection.

GET /api/v1/screening/{entity_id}/detailed/
GET /api/v2/screening/{entity_id}/detailed/

Additional Risk Profile Fields (Detailed View)

FieldTypeDescription
aml_typesarrayAML type strings e.g. ["sanction", "pep"]
pepobjectFull PEP data (structure varies)
sanctionsobjectFull sanctions data (structure varies)
mediaarrayAdverse media articles
watchlistsobjectWatchlist hit data (structure varies)

Get Detailed Results

curl https://api.kycgenie.com/api/v1/screening/550e8400-e29b-41d4-a716-446655440000/detailed/ \
  -H "Authorization: Bearer YOUR_API_KEY"
curl https://api.kycgenie.com/api/v2/screening/550e8400-e29b-41d4-a716-446655440000/detailed/ \
  -H "Authorization: Bearer YOUR_API_KEY"
import requests

entity_id = "550e8400-e29b-41d4-a716-446655440000"

response = requests.get(
    f"https://api.kycgenie.com/api/v1/screening/{entity_id}/detailed/",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = response.json()
for case in data["screening"]["cases"]:
    for alert in case["alerts"]:
        for rp in alert["risk_profiles"]:
            if rp["pep"]:
                print(f"PEP data: {rp['pep']}")
            if rp["sanctions"]:
                print(f"Sanctions: {rp['sanctions']}")
from kycgenie import KYCGenie

client = KYCGenie(api_key="YOUR_API_KEY")

data = client.screening.get_detailed(
    entity_id="550e8400-e29b-41d4-a716-446655440000",
)

const res = await fetch(
  `https://api.kycgenie.com/api/v1/screening/550e8400-e29b-41d4-a716-446655440000/detailed/`,
  { headers: { "Authorization": "Bearer YOUR_API_KEY" } }
);
const data = await res.json();
const res = await fetch(
  `https://api.kycgenie.com/api/v2/screening/550e8400-e29b-41d4-a716-446655440000/detailed/`,
  { headers: { "Authorization": "Bearer YOUR_API_KEY" } }
);
const data = await res.json();

Response Example (200 OK)

{
  "screening": {
    "id": "62ee34a4-28f0-4a83-a016-7441e7900d7e",
    "status": "completed",
    "cases": [
      {
        "id": "c8f16c1d-8e55-4ade-afe4-dbc472f49a31",
        "status": "closed",
        "decision": "acceptable_risk",
        "alerts": [
          {
            "id": "5bc52924-8a4f-48ae-acaa-13027deae060",
            "risk_profiles": [
              {
                "id": "f67f165d-0d1e-4eb7-81e6-3494a260dcd4",
                "name": "Jane Smith - PEP, Sanctions",
                "status": "not_reviewed",
                "matching_score": 0.92,
                "aml_types": ["sanction", "pep", "pep-class-1", "adverse-media", "adverse-media-v2-financial-aml-cft", "fitness-probity"],
                "pep": [
                  {
                    "name": "Example PEP - John Doe",
                    "aml_types": ["pep", "pep-class-1"],
                    "country_codes": ["GB"],
                    "political_positions": ["Member of Parliament"],
                    "listing_started_utc": "2019-01-01T00:00:00Z",
                    "listing_ended_utc": null,
                    "fields": [
                      { "name": "Date of Birth", "tag": "date_of_birth", "value": "1975-03-22" },
                      { "name": "Country", "tag": null, "value": "United Kingdom" }
                    ]
                  }
                ],
                "sanctions": [
                  {
                    "name": "OFAC SDN List",
                    "aml_types": ["sanction"],
                    "country_codes": ["GB"],
                    "listing_started_utc": "2023-06-15T00:00:00Z",
                    "listing_ended_utc": null,
                    "fields": [
                      { "name": "Designation Date", "tag": null, "value": "2023-06-15" },
                      { "name": "Program", "tag": null, "value": "RUSSIA-EO14024" },
                      { "name": "Sanction Type", "tag": null, "value": "Block" }
                    ]
                  }
                ],
                "media": [
                  {
                    "title": "MP faces corruption inquiry over undisclosed payments",
                    "snippet": "An investigation has been launched following allegations of undisclosed payments...",
                    "url": "https://news.example.com/article/12345",
                    "publishing_date": "2024-11-08T00:00:00Z"
                  }
                ],
                "watchlists": [
                  {
                    "name": "UK Companies House Disqualified Directors",
                    "aml_types": ["fitness-probity"],
                    "listing_started_utc": "2024-01-10T00:00:00Z",
                    "listing_ended_utc": null,
                    "fields": [
                      { "name": "Enforcement Agency", "tag": null, "value": "United Kingdom Companies House" }
                    ]
                  }
                ]
              }
            ]
          }
        ]
      }
    ]
  }
}

Case Management

Cases are review containers created when screening finds potential matches. Update case status and decision as you review the associated risk profiles.

Get Case

GET /api/v2/cases/{case_id}/

Update Case

PATCH /api/v2/cases/{case_id}/

Request Body

ParameterTypeDescription
statusstringopen | in_review | closed
decisionstringno_risk | acceptable_risk | unacceptable_risk (only when closing)
closure_reasonstringAnalyst's explanation of the decision. Recommended when setting a decision.

Setting a decision automatically closes the case.

Get Case

curl https://api.kycgenie.com/api/v1/cases/c8f16c1d-8e55-4ade-afe4-dbc472f49a31/ \
  -H "Authorization: Bearer YOUR_API_KEY"
curl https://api.kycgenie.com/api/v2/cases/c8f16c1d-8e55-4ade-afe4-dbc472f49a31/ \
  -H "Authorization: Bearer YOUR_API_KEY"
import requests

response = requests.get(
    "https://api.kycgenie.com/api/v2/cases/c8f16c1d-8e55-4ade-afe4-dbc472f49a31/",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
)
case = response.json()
print(f"Case: {case['title']}, Status: {case['status']}")
from kycgenie import KYCGenie

client = KYCGenie(api_key="YOUR_API_KEY")

case = client.screening.get_case(
    case_id="c8f16c1d-8e55-4ade-afe4-dbc472f49a31"
)
const res = await fetch(
  'https://api.kycgenie.com/api/v1/cases/c8f16c1d-8e55-4ade-afe4-dbc472f49a31/',
  { headers: { 'Authorization': 'Bearer YOUR_API_KEY' } }
);
const c = await res.json();
console.log(`${c.title} - ${c.status}`);
const res = await fetch(
  'https://api.kycgenie.com/api/v2/cases/c8f16c1d-8e55-4ade-afe4-dbc472f49a31/',
  { headers: { 'Authorization': 'Bearer YOUR_API_KEY' } }
);
const c = await res.json();
console.log(`${c.title} - ${c.status}`);

Response Example

{
  "id": "c8f16c1d-8e55-4ade-afe4-dbc472f49a31",
  "screening_id": "62ee34a4-28f0-4a83-a016-7441e7900d7e",
  "title": "Initial Screen - Jane Smith",
  "status": "closed",
  "decision": "acceptable_risk",
  "closure_reason": "DOB and nationality confirmed different individual",
  "assigned_to": null,
  "closed_by": {
    "id": "5c4fdd14-93c8-4653-9c2b-a45f58654599",
    "name": "Alex Johnson",
    "email": "alex@example.com"
  },
  "closed_at": "2026-06-14T14:49:24.500411+00:00",
  "created_at": "2026-06-13T20:27:24.160119+00:00",
  "updated_at": "2026-06-14T14:49:24.505127+00:00"
}

Close Case with Decision

curl -X PATCH https://api.kycgenie.com/api/v1/cases/c8f16c1d-8e55-4ade-afe4-dbc472f49a31/ \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: case-close-c8f16c1d" \
  -d '{"decision": "acceptable_risk", "closure_reason": "DOB and nationality confirmed different individual"}'
curl -X PATCH https://api.kycgenie.com/api/v2/cases/c8f16c1d-8e55-4ade-afe4-dbc472f49a31/ \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: case-close-c8f16c1d" \
  -d '{"decision": "acceptable_risk", "closure_reason": "DOB and nationality confirmed different individual"}'
import requests

case_id = "c8f16c1d-8e55-4ade-afe4-dbc472f49a31"

response = requests.patch(
    f"https://api.kycgenie.com/api/v1/cases/{case_id}/",
    headers={
        "Authorization": "Bearer YOUR_API_KEY",
        "Idempotency-Key": f"case-close-{case_id}",
    },
    json={
        "decision": "acceptable_risk",
        "closure_reason": "DOB and nationality confirmed different individual",
    },
)
case = response.json()
print(f"Status: {case['status']}, Decision: {case['decision']}")
from kycgenie import KYCGenie

client = KYCGenie(api_key="YOUR_API_KEY")

client.screening.update_case(
    case_id="c8f16c1d-8e55-4ade-afe4-dbc472f49a31",
    decision="acceptable_risk",
    closure_reason="DOB and nationality confirmed different individual",
)
const caseId = "c8f16c1d-8e55-4ade-afe4-dbc472f49a31";

await fetch(`https://api.kycgenie.com/api/v1/cases/${caseId}/`, {
  method: "PATCH",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
    "Idempotency-Key": `case-close-${caseId}`,
  },
  body: JSON.stringify({
    decision: "acceptable_risk",
    closure_reason: "DOB and nationality confirmed different individual",
  }),
});
const caseId = "c8f16c1d-8e55-4ade-afe4-dbc472f49a31";

await fetch(`https://api.kycgenie.com/api/v2/cases/${caseId}/`, {
  method: "PATCH",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
    "Idempotency-Key": `case-close-${caseId}`,
  },
  body: JSON.stringify({
    decision: "acceptable_risk",
    closure_reason: "DOB and nationality confirmed different individual",
  }),
});

Risk Profile Status

Update the review status of an individual risk profile. Use this to mark matches as false positives, confirm true positives, or move them into review.

PATCH /api/v1/risk-profiles/{risk_profile_id}/status/
PATCH /api/v2/risk-profiles/{risk_profile_id}/status/

Request Body

ParameterTypeRequiredDescription
statusstringYes not_reviewed | in_review | false_positive | true_positive
notestringNo Optional note explaining the status change (e.g. "DOB mismatch - confirmed false positive")

Mark as False Positive

curl -X PATCH https://api.kycgenie.com/api/v1/risk-profiles/f67f165d-0d1e-4eb7-81e6-3494a260dcd4/status/ \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "false_positive",
    "note": "DOB mismatch - confirmed false positive"
  }'
curl -X PATCH https://api.kycgenie.com/api/v2/risk-profiles/f67f165d-0d1e-4eb7-81e6-3494a260dcd4/status/ \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "false_positive",
    "note": "DOB mismatch - confirmed false positive"
  }'
import requests

rp_id = "f67f165d-0d1e-4eb7-81e6-3494a260dcd4"

response = requests.patch(
    f"https://api.kycgenie.com/api/v1/risk-profiles/{rp_id}/status/",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={
        "status": "false_positive",
        "note": "DOB mismatch - confirmed false positive",
    },
)
print(response.status_code)  # 200
from kycgenie import KYCGenie

client = KYCGenie(api_key="YOUR_API_KEY")

client.risk_profiles.update_status(
    risk_profile_id="f67f165d-0d1e-4eb7-81e6-3494a260dcd4",
    status="false_positive",
    note="DOB mismatch - confirmed false positive",
)
const rpId = "f67f165d-0d1e-4eb7-81e6-3494a260dcd4";

await fetch(`https://api.kycgenie.com/api/v1/risk-profiles/${rpId}/status/`, {
  method: "PATCH",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    status: "false_positive",
    note: "DOB mismatch - confirmed false positive",
  }),
});
const rpId = "f67f165d-0d1e-4eb7-81e6-3494a260dcd4";

await fetch(`https://api.kycgenie.com/api/v2/risk-profiles/${rpId}/status/`, {
  method: "PATCH",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    status: "false_positive",
    note: "DOB mismatch - confirmed false positive",
  }),
});

Batch Screening

Screen multiple existing entities in a single request. Entities that have already been screened are automatically skipped.

POST /api/v1/screening/batch/
POST /api/v2/screening/batch/

Get Batch Job Status

GET /api/v1/screening/batch/{job_id}/
GET /api/v2/screening/batch/{job_id}/

Request Body

ParameterTypeRequiredDescription
entity_idsarrayYesArray of entity UUIDs to screen (1–10,000). Duplicates auto-removed.
webhook_urlstringNoOverrides the tenant's default webhook URL for this job.
webhook_progressbooleanNoReceive progress webhooks during processing.

Batch Screening

curl -X POST https://api.kycgenie.com/api/v1/screening/batch/ \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: batch-screening-20260127-001" \
  -d '{
    "entity_ids": [
      "550e8400-e29b-41d4-a716-446655440000",
      "660f9511-f30c-23e5-b827-537766551111"
    ],
    "webhook_url": "https://your-domain.com/webhooks/batch"
  }'
curl -X POST https://api.kycgenie.com/api/v2/screening/batch/ \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: batch-screening-20260127-001" \
  -d '{
    "entity_ids": [
      "550e8400-e29b-41d4-a716-446655440000",
      "660f9511-f30c-23e5-b827-537766551111"
    ],
    "webhook_url": "https://your-domain.com/webhooks/batch"
  }'
import requests, uuid

entity_ids = [
    "550e8400-e29b-41d4-a716-446655440000",
    "660f9511-f30c-23e5-b827-537766551111",
]

response = requests.post(
    "https://api.kycgenie.com/api/v1/screening/batch/",
    headers={
        "Authorization": "Bearer YOUR_API_KEY",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "entity_ids": entity_ids,
        "webhook_url": "https://your-domain.com/webhooks/batch",
    },
)
job = response.json()
print(f"Job ID: {job['job_id']}, Total: {job['total_count']}")
from kycgenie import KYCGenie

client = KYCGenie(api_key="YOUR_API_KEY")

job = client.screening.batch_screen(
    entity_ids=[
        "550e8400-e29b-41d4-a716-446655440000",
        "660f9511-f30c-23e5-b827-537766551111",
    ],
    webhook_url="https://your-domain.com/webhooks/batch",
    webhook_progress=True,
)
print(f"Job ID: {job.job_id}, Total: {job.total_count}")

# Poll for status
status = client.screening.get_batch_status(job_id=job.job_id)
print(f"Progress: {status.processed_count}/{status.total_count}")
const res = await fetch("https://api.kycgenie.com/api/v1/screening/batch/", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: JSON.stringify({
    entity_ids: [
      "550e8400-e29b-41d4-a716-446655440000",
      "660f9511-f30c-23e5-b827-537766551111",
    ],
    webhook_url: "https://your-domain.com/webhooks/batch",
  }),
});
const job = await res.json();
console.log(`Job ID: ${job.job_id}`);
const res = await fetch("https://api.kycgenie.com/api/v2/screening/batch/", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: JSON.stringify({
    entity_ids: [
      "550e8400-e29b-41d4-a716-446655440000",
      "660f9511-f30c-23e5-b827-537766551111",
    ],
    webhook_url: "https://your-domain.com/webhooks/batch",
  }),
});
const job = await res.json();
console.log(`Job ID: ${job.job_id}`);

202 Accepted Response

{
  "job_id": "a8d8f1e2-4c5e-4f6a-9b2c-3d4e5f6a7b8c",
  "job_type": "screening_batch",
  "status": "pending",
  "total_count": 2,
  "skipped_count": 0,
  "skipped_entity_ids": [],
  "message": "Screening 2 entities.",
  "webhook_url": "https://your-domain.com/webhooks/batch",
  "estimated_completion": "2026-01-28T10:30:45Z"
}

Batch Status Response

{
  "job_id": "a8d8f1e2-4c5e-4f6a-9b2c-3d4e5f6a7b8c",
  "job_type": "screening_batch",
  "status": "processing",
  "total_count": 2,
  "processed_count": 1,
  "failed_count": 0,
  "progress_percentage": 50.0,
  "created_at": "2026-01-28T10:30:00Z",
  "started_at": "2026-01-28T10:30:15Z",
  "completed_at": null,
  "webhook_url": "https://your-domain.com/webhooks/batch"
}
Performance & Limits

Maximum batch size is 10,000 entities. Entities already screened are automatically skipped and listed in skipped_entity_ids.

Ongoing Monitoring

Ongoing monitoring automatically re-screens an entity when their risk profile changes - for example, when they appear on a new sanctions list or are newly identified as a PEP.

PATCH /api/v2/screening/{entity_id}/monitoring/

Set monitoring to an explicit on/off state. This is idempotent - sending the same value twice has no additional effect.

Credits

Enabling monitoring for the first time charges a one-time monitoring credit. Toggling it off and back on does not incur an additional charge.

Request Body

ParameterTypeRequiredDescription
enabledbooleanYestrue to enable, false to disable

Response Fields

FieldTypeDescription
entity_iduuidEntity the monitoring state was updated for
screening_iduuidScreening record updated
monitoring_enabledbooleanCurrent monitoring state after the update

Enable Monitoring

curl -X PATCH https://api.kycgenie.com/api/v2/screening/550e8400-e29b-41d4-a716-446655440000/monitoring/ \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"enabled": true}'
import requests

entity_id = "550e8400-e29b-41d4-a716-446655440000"

# Note: monitoring endpoint is v2 only
response = requests.patch(
    f"https://api.kycgenie.com/api/v2/screening/{entity_id}/monitoring/",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={"enabled": True},
)
result = response.json()
print(f"Monitoring enabled: {result['monitoring_enabled']}")
from kycgenie import KYCGenie

client = KYCGenie(api_key="YOUR_API_KEY")

result = client.screening.update_monitoring(
    entity_id="550e8400-e29b-41d4-a716-446655440000",
    enabled=True,
)
print(f"Monitoring enabled: {result.monitoring_enabled}")
// Note: monitoring endpoint is v2 only
const entityId = "550e8400-e29b-41d4-a716-446655440000";

const res = await fetch(
  `https://api.kycgenie.com/api/v2/screening/${entityId}/monitoring/`,
  {
    method: "PATCH",
    headers: {
      "Authorization": "Bearer YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ enabled: true }),
  }
);
const result = await res.json();
console.log(`Monitoring enabled: ${result.monitoring_enabled}`);

Success Response (200 OK)

{
  "entity_id": "550e8400-e29b-41d4-a716-446655440000",
  "screening_id": "62ee34a4-28f0-4a83-a016-7441e7900d7e",
  "monitoring_enabled": true
}