Integration tutorial

Sanctions screening API with Python

Run a complete Python sanctions screening example with the standard library, a sandbox key, idempotent requests and safe error handling.

Updated

Run the example
python3 screen.py

Copy the complete code below into a new file.

Runtime
Standard library

Call the API from your Python application.

Failures
HTTPError

Inspect HTTP status, code, and requestId.

1. Prepare Python and your sandbox key

Use Python 3. This example uses only json, os, re, sys and urllib from the standard library, so there is no pip install step. Create a sandbox key with screenings:write and results:read in Dashboard → API keys. Follow the quickstart if this is your first API request.

In a trusted terminal, set your sandbox key and a unique REQUEST_KEY using the commands below. Keep the same request key and body when retrying one operation; generate a new key for a new screening. In a deployed worker, supply the API key through server-side environment configuration, never a browser or committed file.

1. Prepare Python and your sandbox key
export SANCTIONSKIT_API_KEY='YOUR_SANDBOX_KEY'
export REQUEST_KEY="$(python3 -c 'import uuid; print(uuid.uuid4())')"

2. Copy the complete screening example

Save this as screen.py. It submits the invented subject Alex Morgan to sandbox@1 using HTTPS, an Authorization header and a 15-second timeout. The JSON is encoded as UTF-8. No external API client or repository checkout is required.

urllib raises HTTPError for failed HTTP responses, so the example handles that separately from a completed screening. It checks the success body before printing an ID and status. Error output is limited to HTTP status, a code and a request ID. Do not replace that with logging of the submitted subject or the full response.

2. Copy the complete screening example
# Save as screen.py. Run with Python 3: python3 screen.py
import json
import os
import re
import sys
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen

api_key = os.environ.get('SANCTIONSKIT_API_KEY')
request_key = os.environ.get('REQUEST_KEY')
if not api_key or not request_key:
    raise SystemExit('Set SANCTIONSKIT_API_KEY and REQUEST_KEY first.')

def safe_field(value):
    return value if isinstance(value, str) and re.fullmatch(r'[a-zA-Z0-9_.:-]{1,128}', value) else 'unknown'

request = Request(
    'https://www.sanctionskit.com/api/v1/screenings',
    method='POST',
    headers={
        'Authorization': 'Bearer ' + api_key,
        'Content-Type': 'application/json',
        'Idempotency-Key': request_key,
    },
    data=json.dumps({
        'subject': {'name': 'Alex Morgan', 'entityType': 'person', 'birthDate': '1984'},
        'package': 'sandbox@1',
    }).encode('utf-8'),
)

try:
    with urlopen(request, timeout=15) as response:
        payload = json.load(response)
    result = payload.get('data') if isinstance(payload, dict) else None
    if (not isinstance(result, dict) or not isinstance(result.get('id'), str)
            or not isinstance(result.get('matches'), list)
            or result.get('status') not in ('potential_match', 'no_match')):
        raise ValueError('Unexpected response format.')
    # Keep the full result in your authorized workflow, not application logs.
    print(json.dumps({'id': result['id'], 'status': result['status']}))
    # potential_match: route to review. no_match: retain coverage and versions.
except HTTPError as error:
    try:
        body = json.load(error)
        detail = body.get('error', {}) if isinstance(body, dict) else {}
        detail = detail if isinstance(detail, dict) else {}
    except (ValueError, OSError):
        detail = {}
    print('HTTP', error.code, 'code=' + safe_field(detail.get('code')),
          'requestId=' + safe_field(detail.get('requestId')), file=sys.stderr)
    raise SystemExit(1)
except (URLError, TimeoutError, OSError, ValueError):
    print('The request did not complete. Keep the same REQUEST_KEY and body when retrying.', file=sys.stderr)
    raise SystemExit(1)

3. Run it and review the outcome

Run the command below from the folder containing screen.py. A successful run prints JSON with id and status. Inspect the full result in sandbox history. A potential_match needs investigation; a no_match applies only to the selected coverage and request. The false-positive review guide explains how to compare evidence.

An error exits with code 1. For 401 or 403, check the key and scopes. For invalid input, correct the request before making a new operation. For a timeout or recoverable server error, retain the original REQUEST_KEY and body. Implement bounded retries in your application and follow the error reference; do not turn exceptions into no_match.

3. Run it and review the outcome
python3 screen.py

4. Add coverage, batches and events

For production, use a production API key and choose sources or a versioned package from source discovery. Keep unknown subject fields absent and preserve the precision of dates you actually know. Save the returned ID, coverage and versions in your authorized workflow rather than application logs.

Use batch screening when processing a portfolio, and monitoring when a retained subject needs repeated checks. For webhook receivers, verify the documented signature over the original bytes, enforce the timestamp tolerance and deduplicate event IDs before acting. The webhook guide describes the verification contract independently of language.

KEEP BUILDING

Where to go next