Integrate AML Screening into Your App in 10 Minutes
Regulatory requirements around Anti-Money Laundering (AML) are tightening globally, and every fintech, neobank, and crypto exchange needs a reliable sanctions screening API to stay compliant. Building an in-house AML screening engine means maintaining sanction lists, tuning fuzzy matching, and keeping up with daily updates from dozens of regulatory bodies. Or you can integrate an AML API in about ten minutes and let CirclesCheck handle all of that for you.
This guide walks you through integrating CirclesCheck's AML screening API into your application, from your first screening request to batch processing and webhooks. By the end, you will have a working AML API integration that screens individuals and entities against global sanctions, PEP, and watchlists in real time.
Prerequisites
Before you start, you need two things:
- A CirclesCheck account. Sign up at app.circlescheck.com if you have not already.
- An API key. Generate one from the API Keys section of your dashboard. Keys are prefixed with
cc_live_for production andcc_test_for sandbox testing.
All API requests go through a single base URL:
https://api.circlescheck.com/api/v1
Authentication is handled via the X-API-Key header on every request. No OAuth flows, no token refreshes -- just a single header.
Step 1: Screen a Name
The core of any AML API integration is the screening request. Send a POST to the /screenings endpoint with a name and entity type, and CirclesCheck returns matches from over 4 million sanctions, PEP, KYB, and watchlist entities.
curl
curl -X POST https://api.circlescheck.com/api/v1/screenings \
-H "Content-Type: application/json" \
-H "X-API-Key: cc_live_your_api_key" \
-d '{"name": "John Smith", "type": "individual"}'
JavaScript (fetch)
const response = await fetch('https://api.circlescheck.com/api/v1/screenings', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'cc_live_your_api_key'
},
body: JSON.stringify({ name: 'John Smith', type: 'individual' })
});
const result = await response.json();
Python (requests)
import requests
response = requests.post(
'https://api.circlescheck.com/api/v1/screenings',
headers={'X-API-Key': 'cc_live_your_api_key'},
json={'name': 'John Smith', 'type': 'individual'}
)
result = response.json()
The type field accepts "individual" for people or "entity" for companies, organizations, and vessels. Providing the correct type improves matching accuracy by narrowing the dataset the engine searches against.
Step 2: Understanding the Response
A successful screening returns a JSON object with the screening result and any matches found:
{
"id": "scr_8f3a1b2c4d5e",
"status": "completed",
"risk_level": "high",
"matches": [
{
"name": "John Robert Smith",
"score": 0.92,
"source": "OFAC SDN List",
"type": "sanction"
},
{
"name": "John David Smith",
"score": 0.85,
"source": "UN Consolidated List",
"type": "sanction"
},
{
"name": "John Smith",
"score": 0.78,
"source": "South Africa PEP List",
"type": "pep"
}
]
}
Here is what each field means:
id-- A unique identifier for the screening. Use it to retrieve or reference this screening later.status-- The screening state. Typically"completed"for synchronous requests.risk_level-- An overall assessment:"low","medium","high", or"critical". This is derived from the highest-scoring match and its source severity.matches-- An array of potential hits. Each match includes the matchedname, ascorebetween 0 and 1 indicating how closely the name matched, thesourcelist it was found on, and thetypeof listing (e.g.,"sanction","pep","watchlist").
A score of 1.0 is an exact match. Scores above 0.85 generally indicate strong matches that warrant close review. CirclesCheck uses trigram-based fuzzy matching to catch transliteration variants, common misspellings, and alias permutations.
Step 3: Handling Results
Your integration should branch on the risk_level to decide what happens next. Here is a practical pattern:
async function screenAndDecide(name, type) {
const response = await fetch('https://api.circlescheck.com/api/v1/screenings', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.CIRCLESCHECK_API_KEY
},
body: JSON.stringify({ name, type })
});
const result = await response.json();
switch (result.risk_level) {
case 'low':
// No meaningful matches — auto-approve
return { action: 'approve', screening_id: result.id };
case 'medium':
// Possible matches with moderate scores — queue for review
return { action: 'review', screening_id: result.id, matches: result.matches };
case 'high':
case 'critical':
// Strong matches against sanctions or PEP lists — block and escalate
return { action: 'block', screening_id: result.id, matches: result.matches };
}
}
For most compliance programs, low means no action is needed, medium should be routed to a compliance analyst for manual review, and high or critical should block the transaction or onboarding flow and trigger an escalation. Adjust these thresholds to match your organization's risk appetite and regulatory requirements.
Step 4: Batch Screening
When you need to screen multiple individuals or entities at once -- during periodic rescreening of your customer base, for example -- use the batch endpoint instead of making individual requests:
curl -X POST https://api.circlescheck.com/api/v1/screenings/batch \
-H "Content-Type: application/json" \
-H "X-API-Key: cc_live_your_api_key" \
-d '{
"entities": [
{"name": "John Smith", "type": "individual"},
{"name": "Acme Trading Ltd", "type": "entity"},
{"name": "Maria Garcia", "type": "individual"}
]
}'
The batch endpoint accepts an array of entities and returns results for each one. This is significantly more efficient than looping over the single screening endpoint, both in terms of network overhead and rate limit consumption.
Step 5: Webhook Setup
To receive real-time notifications when screenings complete or when underlying sanctions lists are updated, register a webhook endpoint:
curl -X POST https://api.circlescheck.com/api/v1/webhooks \
-H "Content-Type: application/json" \
-H "X-API-Key: cc_live_your_api_key" \
-d '{
"url": "https://yourapp.com/webhooks/circlescheck",
"events": ["screening.completed", "list.updated"]
}'
Two event types are particularly useful:
screening.completed-- Fired when an asynchronous or batch screening finishes processing. The payload includes the full screening result.list.updated-- Fired when CirclesCheck ingests updated sanctions or PEP data. This is your signal to rescreen existing customers against the latest lists.
Your webhook endpoint should return a 200 status code to acknowledge receipt. CirclesCheck retries failed deliveries with exponential backoff.
Error Handling
A production-ready AML API integration needs to handle errors gracefully. Here are the status codes you will encounter:
| Status Code | Meaning | What to Do |
|---|---|---|
400 |
Bad request -- missing or invalid fields | Check your request body. Ensure name is present and type is either "individual" or "entity". |
401 |
Unauthorized -- invalid or missing API key | Verify your X-API-Key header. Make sure you are using the correct key for your environment. |
429 |
Rate limited -- too many requests | Back off and retry. Use exponential backoff starting at 1 second. The Retry-After header tells you how long to wait. |
500 |
Server error | Retry with exponential backoff. If the issue persists, contact support. |
A simple retry wrapper in Python:
import time
import requests
def screen_with_retry(name, entity_type, max_retries=3):
url = 'https://api.circlescheck.com/api/v1/screenings'
headers = {'X-API-Key': 'cc_live_your_api_key'}
payload = {'name': name, 'type': entity_type}
for attempt in range(max_retries):
response = requests.post(url, headers=headers, json=payload)
if response.status_code == 200:
return response.json()
elif response.status_code == 429:
wait = int(response.headers.get('Retry-After', 2 ** attempt))
time.sleep(wait)
elif response.status_code >= 500:
time.sleep(2 ** attempt)
else:
response.raise_for_status()
raise Exception('Max retries exceeded')
Next Steps
You now have a working AML screening API integration that can screen individuals and entities, process batches, and receive webhook notifications. From here you can:
- Explore the full API reference at app.circlescheck.com/docs for additional endpoints and filtering options.
- Set up ongoing monitoring by combining the
list.updatedwebhook with batch rescreening to keep your customer base continuously screened. - Use
cc_test_API keys during development to test your integration without consuming production credits.
If you run into issues or have questions, reach out to our team through the dashboard. We are here to help you ship compliant software faster.
Ready to streamline your compliance?
Start screening against 250+ sanctions lists in minutes.
Get Started Free