AML screening
Verify any natural or legal person against global sanctions, politically-exposed-person (PEP) and watchlist data — whether or not they are a VirtuaBroker customer. Run an instant list check with just a name, run an identity-rich screening with a stored review lifecycle, and let continuous screening re-check your verified customers automatically as list data changes.
server-side integrators
API External API v1
One call to verify
You'll need workspace credentials and a bearer token — see the Authentication guide. AML endpoints are a workspace capability: a 403 (AllowanceError) means screening is not enabled for your workspace — contact your account manager.
Choosing the right tool
The API gives you three complementary ways to keep bad actors out, from a one-line check to fully automatic monitoring:
List check
POST /v1/aml-checks — instant, stateless: send a name (and optionally an identifier) and get the live list matches back, with scores and flags. Works for anyone — no account, no verification required. Every check is stored as history.
Screening
POST /v1/aml-screenings — identity-rich: send full identity details (date of birth, nationality, tax id) for a higher-precision outcome with a review lifecycle (CLEAR / POTENTIAL_MATCH / REVIEW_REQUIRED) and idempotent retries.
Continuous screening
Automatic — every customer who completes identity verification (KYC/KYB) is enrolled in ongoing re-screening. When list data changes, compliance reviews the match. No integration work needed.
Unknown is never clear. Across every AML endpoint, match is a tri-state: true = potential matches found, false = clear, null = the check did not run. Branch on match === false to grant a pass — never on "not true". A 503 outcome must be retried, not treated as a pass.
1 · Run a list check
POST /v1/aml-checks verifies a name against sanctions, PEP and watchlist data in a single call. The subject does not need to be a VirtuaBroker customer — this is verification-as-a-service for your own onboarding, your client portfolio, or any counterparty you need to vet.
curl https://api.virtuabroker.com/v1/aml-checks \ -H "Authorization: Bearer $VB_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "id": "012345678A", "name": "El payaso Miliki", "reference": "client-check-456" }'
const res = await fetch("https://api.virtuabroker.com/v1/aml-checks", { method: "POST", headers: { Authorization: `Bearer ${access_token}`, "Content-Type": "application/json" }, body: JSON.stringify({ id: "012345678A", name: "El payaso Miliki", reference: "client-check-456", }), }); const check = await res.json();
check = requests.post("https://api.virtuabroker.com/v1/aml-checks", headers={"Authorization": f"Bearer {access_token}"}, json={ "id": "012345678A", "name": "El payaso Miliki", "reference": "client-check-456", }, ).json()
| Field | Notes | |
|---|---|---|
name | REQUIRED | Full name of the natural or legal person, 2–140 characters |
id | OPTIONAL | Identifier for your records, 3–32 characters. A Spanish DNI/NIE/NIF/CIF is recognised and used to infer the subject type — a CIF searches companies, a DNI/NIE searches persons. Any other national identifier is accepted as-is. |
entityType | OPTIONAL | INDIVIDUAL · COMPANY — overrides the inference. When neither is known the check matches both kinds. |
reference | OPTIONAL | Your correlation reference (≤64 chars), echoed back on the response |
A clean subject comes back with match: false and an empty results array:
{
"checkId": "3JyVix1grJsu1z64h047",
"reference": "client-check-456",
"status": "COMPLETED",
"match": false,
"matchCount": 0,
"checkedAt": "2026-07-20T09:00:00.000Z",
"results": []
}
A potential match returns the list entries, each with a similarity score and the reasons the entry is listed:
{
"checkId": "8kQpWv2xTzRb5cJd9eYf",
"status": "COMPLETED",
"match": true,
"matchCount": 1,
"checkedAt": "2026-07-20T09:01:00.000Z",
"results": [
{
"matchId": "Q6070218",
"name": "Pedro Sánchez",
"type": "PERSON",
"score": 1,
"flags": ["PEP"],
"title": "Prime Minister of Spain",
"countries": ["ES"],
"dateOfBirth": "1972-02-29"
}
]
}
| Result field | Meaning |
|---|---|
matchId | Stable identifier of the matched list entry — de-duplicate repeat checks on it |
type | PERSON · COMPANY · OTHER (vessels and other listed assets) |
score | Match strength 0–1 — name similarity against the list entry |
flags | Why the entry is listed: SANCTIONS · PEP · WATCHLIST · CRIME · OTHER |
title, countries, dateOfBirth | Known role or position, associated countries (ISO 3166-1 alpha-2), and date of birth where the lists record them |
results is capped at 20 entries, while matchCount always reports the true total. More than 20 hits on a name means the name is too generic — add more of it (full name rather than surname) and check again.
If the check cannot run, the response is a 503 with match: null, status: "FAILED" and a coded errors array (CHECK_NOT_COMPLETED). The failed check is stored too — retrieving it later returns the same honest FAILED view. Retry with a new check; never treat it as a pass.
2 · Retrieve a stored check
GET /v1/aml-checks/{checkId} returns a previously run check. Checks are visible only to the workspace that created them; repeat checks of the same subject each produce their own record, so your audit trail shows every verification with its timestamp.
curl https://api.virtuabroker.com/v1/aml-checks/3JyVix1grJsu1z64h047 \ -H "Authorization: Bearer $VB_TOKEN"
Every check is evidence. Store the checkId next to the client record in your systems — when an auditor asks "was this person screened, and when?", the stored check answers with the exact timestamp and result.
3 · Run an identity-rich screening
When you hold more than a name, POST /v1/aml-screenings screens with the full identity — date of birth, nationality, tax identifiers — for a higher-precision outcome and a review lifecycle. Richer identity information produces higher-quality screening.
curl https://api.virtuabroker.com/v1/aml-screenings \ -H "Authorization: Bearer $VB_TOKEN" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: onboarding-7f3a2b" \ -d '{ "entity": { "entityType": "INDIVIDUAL", "firstName": "John", "lastName": "Smith", "dateOfBirth": "1985-03-14", "nationality": "GB", "taxIdentificationNumber": "X1234567L", "taxIdentificationType": "NIE", "taxIdentificationCountry": "ES" }, "reason": "ONBOARDING", "reference": "client-check-456" }'
Companies use entityType: "COMPANY" with companyName, companyRegistrationNumber and countryOfResidence. At least one name (or an identifier that resolves to a known account) is required.
{
"screeningId": "5mRtYu8wQaSd2fGh4jKl",
"reference": "client-check-456",
"status": "COMPLETED",
"result": "CLEAR",
"match": false,
"potentialMatchCount": 0,
"reviewRequired": false,
"screenedAt": "2026-07-20T09:02:00.000Z"
}
status | result | Meaning |
|---|---|---|
COMPLETED | CLEAR | Screening ran; no potential matches (match: false) |
COMPLETED | POTENTIAL_MATCH | Potential matches require review (match: true, reviewRequired: true). A potential match is never a confirmed match. |
COMPLETED | REVIEW_REQUIRED | A match requires compliance review before proceeding (match: true) |
NOT_COMPLETED | INSUFFICIENT_DATA | Not enough identity information to screen reliably (match: null) — see errors |
— (HTTP 503) | ERROR | Screening could not be completed (match: null) — retry; never interpret as clear |
Screenings summarise the outcome — result, match, counts. Raw match details are retained for compliance review and are not returned on this resource (the list check above is the endpoint that returns match details). Retrieve a screening later with GET /v1/aml-screenings/{screeningId}.
Idempotency. Send an Idempotency-Key header (≤128 chars) to make retries safe: replaying the same key returns the original screening; reusing a key with a different payload returns 409.
4 · Continuous screening — automatic
List data changes daily: people become PEPs, sanctions are added, watchlists grow. Continuous screening closes that gap with zero integration work:
Verification enrols
Every customer who completes identity verification (KYC or KYB — see the Identity guide) is automatically enrolled in ongoing re-screening.
Lists change, we re-check
Enrolled identities are re-screened continuously against updated sanctions, PEP and watchlist data — including a daily re-sync of recently changed profiles.
Matches go to review
A new potential match opens a compliance review. Confirmed risk is handled through your workspace's compliance process — you don't need to poll anything.
Continuous screening protects the customers you verify through the platform. For subjects you only ever check (no VirtuaBroker verification), re-run POST /v1/aml-checks on your own schedule — each call runs fresh against current list data and appends to history.
Error handling & best practices
Errors
| HTTP | Cause | What to do |
|---|---|---|
400 | Validation failed — name too short, unknown field, malformed body | Fix the field named in the response and retry; the request schema is strict |
401 | Missing or expired token | Re-authenticate and retry |
403 | AllowanceError — AML screening is not enabled for this workspace | Contact your account manager to enable the capability |
404 | Unknown checkId / screeningId — or it belongs to another workspace | Verify the id; records are only visible to the workspace that created them |
409 | Idempotency-Key reused with a different payload (screenings) | Generate a fresh key per distinct request |
503 | The check/screening could not be completed — match: null | Retry later. Never treat an incomplete check as a pass. |
Best practices
- Branch on
match === false.matchis tri-state — testing "not true" turns an outage into a false pass. - Store the
checkId/screeningId. They are your audit evidence;referenceties them back to your own systems. - Retries are safe. A repeat
POST /v1/aml-checksappends a new history record; a repeat screening with the sameIdempotency-Keyreplays the original. - A score is a lead, not a verdict.
scoremeasures name similarity; a potential match needs human review before you act on it — especially common names. - Re-check long-lived counterparties. For subjects outside the platform's continuous screening, schedule periodic re-checks — list data moves.
Quick reference
| Endpoint | Purpose |
|---|---|
POST /v1/aml-checks | Instant list check by name (+ optional id); returns match details; stores history |
GET /v1/aml-checks/{checkId} | Retrieve a stored check — your audit trail |
POST /v1/aml-screenings | Identity-rich screening with review lifecycle and idempotent retries |
GET /v1/aml-screenings/{screeningId} | Retrieve a screening summary |