AML screening
Retrieving the AML result
Poll or receive the webhook, then read the result correctly.
Two ways to get the result
| Way | How |
|---|---|
| Webhook | The DATABASE_CHECKS_COMPLETE event reaches the callback URL of the scenario once all checks of the session are terminal. It is one POST with the full result set. See webhooks and receiving webhooks. |
| Polling | Call database check results with the session identifier every 5 to 10 seconds until checksStatus is complete. |
The two carry the same checks, but not the same shape. See the two shapes.
When to stop
- A session.
completeneeds the session to be terminal as well as every check. While the session isidleorprocessing, more checks may still be enqueued, so even an empty list reportspending. An abandoned session never reachescomplete: its stored status staysidle, and the expiry is not written to the record. Stop polling when the session lifetime that you set in the scenario has passed. - A questionnaire record.
completeneeds the record to be committed (statusofsuccess), no check pending and the set of checks settled. A record has no time to live, so wait for the webhook instead of polling to a deadline. - A scenario with no checks answers
completewith an emptyresults. That is how "nothing was checked" differs from an unknown identifier, which answerssession not found.
The webhook can repeat
The event always carries the full result set. It is sent again whenever the session returns to a fully terminal state. Treat it as idempotent by sessionId: replace what you stored for that session with the latest set, and do not count events.
Privacy options
Each terminal check result is sent in full whatever the option that omits personal data, because without the verdict a skipped check would read as clean even on a match. The option that encrypts the body applies to the webhook. Polling always returns the full result in plain form and works without a callback URL.
The request
curl -X POST "<API_BASE_URL>/kyc/session/databases" \
-H "Content-Type: application/json" \
-d '{
"token": "<your permanent API token>",
"sessionId": "00000000-0000-0000-0000-000000000000"
}'
The two shapes
Polling returns the verdict of each check under result. The webhook has no task-status wrapper and puts the same fields one level flatter, on the entry itself.
Polling (kyc/session/databases) | Webhook (DATABASE_CHECKS_COMPLETE) | |
|---|---|---|
| Top level | sessionId, checksStatus, pending, results, responseTime | event, sessionId, schemaId, clientId, results, responseTime |
Entry of results | checker, status, outcome, notPerformedReason, missingInputs, spent, and the verdict under result | checker, spent, outcome, notPerformedReason, missingInputs and the verdict fields directly: passed, score, verified, items, totalCount, details, error |
| Verdict | results[].result.passed | results[].passed |
Normalize both into one shape before you apply your decision logic:
function normalize(check) {
const verdict = check.result ?? check; // polling nests the verdict under "result"; the webhook does not
return {
checker: check.checker,
outcome: check.outcome,
passed: verdict.passed,
items: verdict.items,
totalCount: verdict.totalCount,
};
}
How to read a result
Read outcome before passed.
outcome | Meaning |
|---|---|
performed | The source was queried and the result is meaningful. |
skipped | The check did not run because input data was missing or unusable. An empty result means not checked, not clean. |
unavailable | The source failed or could not be reached. A re-run can succeed. |
| null | The check is not finished yet. |
notPerformedReason gives the reason when there is no result: missingInput, unusableInput, identityUnresolved, ageBelowDocumentAge, providerUnavailable, providerError or unknown. For missingInput, supply the data that missingInputs names and run again.
When outcome is performed, the verdict is carried by result.passed:
passed | Meaning |
|---|---|
true | The check passed: the person was not found in a risk list, or validation succeeded. |
false | A match was found, or validation failed. |
| null | An error or a skip. |
The matched records are in result.items, their count is in result.totalCount, and the error text, if any, is in result.error.
A skipped check looks successful
A check that never ran arrives with status of success and passed of null. That is how the source reports a skip. If you branch on status alone, a check that never ran looks like a success. Branch on outcome.
for (const entry of results) {
const check = normalize(entry);
if (check.outcome !== "performed") {
// not checked: missing input, or the source was unavailable
continue;
}
if (check.passed === false) {
// a match was found: send to manual review
}
}
The status of a check
The status field is the status of the check task: idle, processing, success, failed or exception. See session statuses.
Personal data erasure
After an erasure request the object keeps its identifiers, statuses and verdicts and carries no personal values. See erase session personal data.