curl -X POST 'https://verification.didit.me/v3/users/aml-monitoring/' \
-H 'x-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"is_enabled": true, "vendor_data_list": ["user-123", "user-456"]}'import requests
resp = requests.post(
'https://verification.didit.me/v3/users/aml-monitoring/',
headers={'x-api-key': 'YOUR_API_KEY', 'Content-Type': 'application/json'},
json={'is_enabled': True, 'vendor_data_list': ['user-123', 'user-456']},
)
resp.raise_for_status()
job = resp.json()
print(job['status'], job['outcomes'])
for row in job['results']:
print(row['vendor_data'], row['outcome'])const resp = await fetch('https://verification.didit.me/v3/users/aml-monitoring/', {
method: 'POST',
headers: { 'x-api-key': process.env.DIDIT_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ is_enabled: true, vendor_data_list: ['user-123', 'user-456'] }),
});
const job = await resp.json();
console.log(job.status, job.outcomes);
for (const row of job.results) console.log(row.vendor_data, row.outcome);<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://verification.didit.me/v3/users/aml-monitoring/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'is_enabled' => true,
'estimate_only' => true,
'vendor_data_list' => [
'user-123',
'user-456'
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://verification.didit.me/v3/users/aml-monitoring/"
payload := strings.NewReader("{\n \"is_enabled\": true,\n \"estimate_only\": true,\n \"vendor_data_list\": [\n \"user-123\",\n \"user-456\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://verification.didit.me/v3/users/aml-monitoring/")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"is_enabled\": true,\n \"estimate_only\": true,\n \"vendor_data_list\": [\n \"user-123\",\n \"user-456\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://verification.didit.me/v3/users/aml-monitoring/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"is_enabled\": true,\n \"estimate_only\": true,\n \"vendor_data_list\": [\n \"user-123\",\n \"user-456\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"users_total": 123,
"already_enabled": 123,
"with_existing_aml": 123,
"needing_screening": 123,
"skipped_no_identity_data": 123,
"skipped_blocked": 123,
"estimated_screening_cost_usd": 0.2,
"estimated_annual_monitoring_cost_usd": 0.07,
"balance_sufficient": true,
"unmatched": [
"<string>"
]
}{
"job_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"status": "PENDING",
"is_enabled": true,
"target_type": "user",
"total": 123,
"processed": 123,
"outcomes": {
"enabled": 123,
"screened_and_enabled": 123,
"already_enabled": 123,
"disabled": 123,
"skipped_no_identity_data": 123,
"skipped_blocked": 123,
"skipped_sandbox": 123,
"failed_provider": 123,
"failed_insufficient_balance": 123
},
"results": [
{
"didit_internal_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"vendor_data": "<string>",
"outcome": "enabled"
}
],
"error": "<string>",
"created_at": "2023-11-07T05:31:56Z",
"completed_at": "2023-11-07T05:31:56Z",
"estimate": {
"users_total": 123,
"already_enabled": 123,
"with_existing_aml": 123,
"needing_screening": 123,
"skipped_no_identity_data": 123,
"skipped_blocked": 123,
"estimated_screening_cost_usd": 0.2,
"estimated_annual_monitoring_cost_usd": 0.07,
"balance_sufficient": true
},
"unmatched": [
"<string>"
]
}{
"error": "<string>",
"estimate": {
"users_total": 123,
"already_enabled": 123,
"with_existing_aml": 123,
"needing_screening": 123,
"skipped_no_identity_data": 123,
"skipped_blocked": 123,
"estimated_screening_cost_usd": 0.2,
"estimated_annual_monitoring_cost_usd": 0.07,
"balance_sufficient": true
}
}Enable or Disable AML Monitoring for Users
Turn AML ongoing monitoring on or off for many users in one call, with a cost estimate dry-run, a pollable job and a per-user outcome.
curl -X POST 'https://verification.didit.me/v3/users/aml-monitoring/' \
-H 'x-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"is_enabled": true, "vendor_data_list": ["user-123", "user-456"]}'import requests
resp = requests.post(
'https://verification.didit.me/v3/users/aml-monitoring/',
headers={'x-api-key': 'YOUR_API_KEY', 'Content-Type': 'application/json'},
json={'is_enabled': True, 'vendor_data_list': ['user-123', 'user-456']},
)
resp.raise_for_status()
job = resp.json()
print(job['status'], job['outcomes'])
for row in job['results']:
print(row['vendor_data'], row['outcome'])const resp = await fetch('https://verification.didit.me/v3/users/aml-monitoring/', {
method: 'POST',
headers: { 'x-api-key': process.env.DIDIT_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ is_enabled: true, vendor_data_list: ['user-123', 'user-456'] }),
});
const job = await resp.json();
console.log(job.status, job.outcomes);
for (const row of job.results) console.log(row.vendor_data, row.outcome);<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://verification.didit.me/v3/users/aml-monitoring/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'is_enabled' => true,
'estimate_only' => true,
'vendor_data_list' => [
'user-123',
'user-456'
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://verification.didit.me/v3/users/aml-monitoring/"
payload := strings.NewReader("{\n \"is_enabled\": true,\n \"estimate_only\": true,\n \"vendor_data_list\": [\n \"user-123\",\n \"user-456\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://verification.didit.me/v3/users/aml-monitoring/")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"is_enabled\": true,\n \"estimate_only\": true,\n \"vendor_data_list\": [\n \"user-123\",\n \"user-456\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://verification.didit.me/v3/users/aml-monitoring/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"is_enabled\": true,\n \"estimate_only\": true,\n \"vendor_data_list\": [\n \"user-123\",\n \"user-456\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"users_total": 123,
"already_enabled": 123,
"with_existing_aml": 123,
"needing_screening": 123,
"skipped_no_identity_data": 123,
"skipped_blocked": 123,
"estimated_screening_cost_usd": 0.2,
"estimated_annual_monitoring_cost_usd": 0.07,
"balance_sufficient": true,
"unmatched": [
"<string>"
]
}{
"job_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"status": "PENDING",
"is_enabled": true,
"target_type": "user",
"total": 123,
"processed": 123,
"outcomes": {
"enabled": 123,
"screened_and_enabled": 123,
"already_enabled": 123,
"disabled": 123,
"skipped_no_identity_data": 123,
"skipped_blocked": 123,
"skipped_sandbox": 123,
"failed_provider": 123,
"failed_insufficient_balance": 123
},
"results": [
{
"didit_internal_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"vendor_data": "<string>",
"outcome": "enabled"
}
],
"error": "<string>",
"created_at": "2023-11-07T05:31:56Z",
"completed_at": "2023-11-07T05:31:56Z",
"estimate": {
"users_total": 123,
"already_enabled": 123,
"with_existing_aml": 123,
"needing_screening": 123,
"skipped_no_identity_data": 123,
"skipped_blocked": 123,
"estimated_screening_cost_usd": 0.2,
"estimated_annual_monitoring_cost_usd": 0.07,
"balance_sufficient": true
},
"unmatched": [
"<string>"
]
}{
"error": "<string>",
"estimate": {
"users_total": 123,
"already_enabled": 123,
"with_existing_aml": 123,
"needing_screening": 123,
"skipped_no_identity_data": 123,
"skipped_blocked": 123,
"estimated_screening_cost_usd": 0.2,
"estimated_annual_monitoring_cost_usd": 0.07,
"balance_sufficient": true
}
}Overview
Enables or disables ongoing AML monitoring for the selected User entities, exactly as the AML Ongoing monitoring action in the Business Console does. The Console and this endpoint run the same underlying operation, so the rules, the billing and the outcomes are identical. Sendestimate_only: true first to see how many users are selected, how many need a new AML screening, the one-time screening cost and the yearly monitoring cost. Nothing is written by a dry-run.
When to use it
- Programmatic onboarding: turn monitoring on for users you imported or created through the API without re-screening them by hand.
- Offboarding: stop monitoring, and its yearly renewal, for users who left your platform.
- Cost control: preview the exact cost impact of a selection before committing to it.
How a selection is processed
- One monitored screening per user. A user who verified several times is monitored and billed once. Disabling turns monitoring off across all of that user’s screenings.
- Users without an AML screening are screened first. Didit creates a new AML verification for them (visible in the user’s Verifications tab), billed as a regular AML screening, and enables monitoring on it. This needs the user’s full name, date of birth and country; a user missing any of them is reported as
skipped_no_identity_datarather than silently dropped. - Blocked users are skipped (
skipped_blocked). Sandbox applications never create screenings (skipped_sandbox). - Balance is checked up front. Enabling is refused with
403when your balance does not cover the estimate, and the response carries the estimate so you know how much to top up. - Yearly renewal. A newly monitored user is billed the yearly monitoring price at their next renewal date, the same date the Console shows in the Ongoing monitoring column. Disabling stops the renewal; it does not refund a period already billed.
Selection and batch size
Select users withvendor_data_list, didit_internal_id_list, or both; the two lists are OR’d. A request accepts at most 1000 identifiers across both lists. Identifiers that match no user in your application are returned under unmatched, exactly as sent, and never fail the request: a selection that matches nothing completes as an empty job (total: 0) with every identifier listed, the same convention as the batch delete endpoints.
Inline or in the background
Selections of 20 users or fewer are processed inline and the call returns200 with the finished job. Larger selections return 202 with a PENDING job; poll Get AML Monitoring Job until status is COMPLETED or FAILED. Either way the job carries one results entry per user with its outcome.
outcome | Meaning |
|---|---|
enabled | Monitoring enabled on an existing AML screening. |
screened_and_enabled | A new AML screening was created (billed) and monitoring enabled on it. |
already_enabled | Monitoring was already active; nothing changed, nothing billed. |
disabled | Monitoring turned off across every screening of the user. |
skipped_no_identity_data | The user lacks the full name, date of birth or country needed to screen. |
skipped_blocked | The user is blocked. |
skipped_sandbox | Sandbox application; no screening is created. |
failed_provider | The screening could not be completed. Retry later. |
failed_insufficient_balance | Balance ran out while the job was running. |
Webhooks
Toggling monitoring emits no webhook of its own. Once monitoring is on, re-screens keep firing the usualstatus.updated and data.updated events described in Continuous AML Monitoring.
Permissions
Any active API key of the application can call this endpoint. Didit API keys are application-scoped, not role-scoped: the Console’s roles and permissions decide what a person can do in the Console and are not evaluated for Management API traffic.Related
- Get AML Monitoring Job
- Toggle AML Monitoring for Businesses
- Continuous AML Monitoring
- AML Screening API
- List Users
Authorizations
Body
Select users with vendor_data_list, didit_internal_id_list, or both (the two lists are OR'd). At most 1000 identifiers per request across both lists.
true to enable monitoring, false to disable it.
When true, returns the cost estimate and performs no writes - no screening, no billing, no job.
Your own identifiers of the users to toggle, matched exactly as sent.
Didit internal ids of the users to toggle - the didit_internal_id returned by the create, get and list endpoints.
Response
The estimate (when estimate_only is true) or the completed job for a selection processed inline.
- Option 1
- Option 2
Cost preview. Returned directly when estimate_only is true (nothing is written).
Profiles matched by the selection.
Profiles already monitored (nothing to do when enabling; these are what disabling turns off).
Profiles whose existing AML screening will be switched to monitored (no new screening).
Profiles without any AML screening that will be screened first (billed as a regular AML screening).
Profiles that cannot be screened because identity data is missing.
Blocked users that will be skipped (always 0 for businesses).
One-time cost of the new screenings.
0.2
Yearly monitoring cost of the profiles that will become monitored.
0.07
Whether the organization balance covers the screening plus the first year of monitoring.
Identifiers of the request that matched no profile in this application, exactly as sent.