curl -X POST 'https://verification.didit.me/v3/transactions/rules/' \
-H 'x-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"title": "Structuring - inbound (custom)", "description": "20+ inbound transfers under 10,000 in 30 days from the same subject.", "category": "finance", "mode": "TEST", "evaluation_mode": "ALL", "scope": {"transaction_types": ["finance"]}, "conditions": [{"field": "amount", "operator": "lt", "value": 10000}], "aggregation": [{"metric": "count", "operator": "gte", "value": 20, "window": "30d", "filters": {"direction": "INBOUND", "subject_vendor_data": "__current__"}}], "actions": [{"type": "add_score", "value": 35}]}'import os
import requests
rule = {
"title": "Structuring - inbound (custom)",
"description": "20+ inbound transfers under 10,000 in 30 days from the same subject.",
"category": "finance",
"mode": "TEST",
"evaluation_mode": "ALL",
"scope": {
"transaction_types": [
"finance"
]
},
"conditions": [
{
"field": "amount",
"operator": "lt",
"value": 10000
}
],
"aggregation": [
{
"metric": "count",
"operator": "gte",
"value": 20,
"window": "30d",
"filters": {
"direction": "INBOUND",
"subject_vendor_data": "__current__"
}
}
],
"actions": [
{
"type": "add_score",
"value": 35
}
]
}
resp = requests.post(
'https://verification.didit.me/v3/transactions/rules/',
headers={'x-api-key': os.environ['DIDIT_API_KEY']},
json=rule,
timeout=15,
)
resp.raise_for_status()
print(resp.json()['uuid'], resp.json()['mode'])const rule = {
"title": "Structuring - inbound (custom)",
"description": "20+ inbound transfers under 10,000 in 30 days from the same subject.",
"category": "finance",
"mode": "TEST",
"evaluation_mode": "ALL",
"scope": {
"transaction_types": [
"finance"
]
},
"conditions": [
{
"field": "amount",
"operator": "lt",
"value": 10000
}
],
"aggregation": [
{
"metric": "count",
"operator": "gte",
"value": 20,
"window": "30d",
"filters": {
"direction": "INBOUND",
"subject_vendor_data": "__current__"
}
}
],
"actions": [
{
"type": "add_score",
"value": 35
}
]
};
const resp = await fetch('https://verification.didit.me/v3/transactions/rules/', {
method: 'POST',
headers: {
'x-api-key': process.env.DIDIT_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify(rule),
});
if (!resp.ok) throw new Error(await resp.text());
const created = await resp.json();
console.log(created.uuid, created.mode);<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://verification.didit.me/v3/transactions/rules/",
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([
'title' => 'Structuring - inbound (custom)',
'description' => '20+ inbound transfers under 10,000 in 30 days from the same subject.',
'category' => 'finance',
'mode' => 'TEST',
'evaluation_mode' => 'ALL',
'scope' => [
'transaction_types' => [
'finance'
]
],
'conditions' => [
[
'field' => 'amount',
'operator' => 'lt',
'value' => 10000
]
],
'aggregation' => [
[
'metric' => 'count',
'operator' => 'gte',
'value' => 20,
'window' => '30d',
'filters' => [
'direction' => 'INBOUND',
'subject_vendor_data' => '__current__'
]
]
],
'actions' => [
[
'type' => 'add_score',
'value' => 35
]
]
]),
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/transactions/rules/"
payload := strings.NewReader("{\n \"title\": \"Structuring - inbound (custom)\",\n \"description\": \"20+ inbound transfers under 10,000 in 30 days from the same subject.\",\n \"category\": \"finance\",\n \"mode\": \"TEST\",\n \"evaluation_mode\": \"ALL\",\n \"scope\": {\n \"transaction_types\": [\n \"finance\"\n ]\n },\n \"conditions\": [\n {\n \"field\": \"amount\",\n \"operator\": \"lt\",\n \"value\": 10000\n }\n ],\n \"aggregation\": [\n {\n \"metric\": \"count\",\n \"operator\": \"gte\",\n \"value\": 20,\n \"window\": \"30d\",\n \"filters\": {\n \"direction\": \"INBOUND\",\n \"subject_vendor_data\": \"__current__\"\n }\n }\n ],\n \"actions\": [\n {\n \"type\": \"add_score\",\n \"value\": 35\n }\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/transactions/rules/")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"title\": \"Structuring - inbound (custom)\",\n \"description\": \"20+ inbound transfers under 10,000 in 30 days from the same subject.\",\n \"category\": \"finance\",\n \"mode\": \"TEST\",\n \"evaluation_mode\": \"ALL\",\n \"scope\": {\n \"transaction_types\": [\n \"finance\"\n ]\n },\n \"conditions\": [\n {\n \"field\": \"amount\",\n \"operator\": \"lt\",\n \"value\": 10000\n }\n ],\n \"aggregation\": [\n {\n \"metric\": \"count\",\n \"operator\": \"gte\",\n \"value\": 20,\n \"window\": \"30d\",\n \"filters\": {\n \"direction\": \"INBOUND\",\n \"subject_vendor_data\": \"__current__\"\n }\n }\n ],\n \"actions\": [\n {\n \"type\": \"add_score\",\n \"value\": 35\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://verification.didit.me/v3/transactions/rules/")
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 \"title\": \"Structuring - inbound (custom)\",\n \"description\": \"20+ inbound transfers under 10,000 in 30 days from the same subject.\",\n \"category\": \"finance\",\n \"mode\": \"TEST\",\n \"evaluation_mode\": \"ALL\",\n \"scope\": {\n \"transaction_types\": [\n \"finance\"\n ]\n },\n \"conditions\": [\n {\n \"field\": \"amount\",\n \"operator\": \"lt\",\n \"value\": 10000\n }\n ],\n \"aggregation\": [\n {\n \"metric\": \"count\",\n \"operator\": \"gte\",\n \"value\": 20,\n \"window\": \"30d\",\n \"filters\": {\n \"direction\": \"INBOUND\",\n \"subject_vendor_data\": \"__current__\"\n }\n }\n ],\n \"actions\": [\n {\n \"type\": \"add_score\",\n \"value\": 35\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"title": "<string>",
"description": "<string>",
"category": "<string>",
"mode": "ACTIVE",
"evaluation_mode": "ALL",
"scope": {
"transaction_types": [
"<string>"
],
"directions": [
"INBOUND"
],
"action_types": [
"<string>"
]
},
"conditions": [
{
"field": "<string>",
"operator": "eq",
"value": "<unknown>",
"value_type": "list",
"score": 50,
"group_index": 123,
"group_logic": "AND",
"groups_logic": "OR"
}
],
"aggregation": [
{
"value": 123,
"metric": "count",
"field": "amount",
"operator": "eq",
"window": "1d",
"filters": {}
}
],
"actions": [
{
"type": "add_score",
"value": 123
}
],
"metadata": {},
"severity": "UNKNOWN",
"source": "PRESET",
"library_key": "<string>",
"latest_triggered_at": "2023-11-07T05:31:56Z",
"run_count": 123,
"approved_count": 123,
"reviewed_count": 123,
"declined_count": 123,
"awaiting_user_count": 123,
"approved_pct": 123,
"reviewed_pct": 123,
"declined_pct": 123,
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z"
}{
"title": [
"A rule with this name already exists."
]
}Create Rule
Create a CUSTOM transaction-monitoring rule. Titles are unique per application (duplicate -> 400). A change_status action targeting AWAITING_USER must carry workflow_id. Rules created in ACTIVE mode apply to new transactions immediately - the recommended workflow is create in TEST mode, backtest, then switch mode to ACTIVE.
curl -X POST 'https://verification.didit.me/v3/transactions/rules/' \
-H 'x-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"title": "Structuring - inbound (custom)", "description": "20+ inbound transfers under 10,000 in 30 days from the same subject.", "category": "finance", "mode": "TEST", "evaluation_mode": "ALL", "scope": {"transaction_types": ["finance"]}, "conditions": [{"field": "amount", "operator": "lt", "value": 10000}], "aggregation": [{"metric": "count", "operator": "gte", "value": 20, "window": "30d", "filters": {"direction": "INBOUND", "subject_vendor_data": "__current__"}}], "actions": [{"type": "add_score", "value": 35}]}'import os
import requests
rule = {
"title": "Structuring - inbound (custom)",
"description": "20+ inbound transfers under 10,000 in 30 days from the same subject.",
"category": "finance",
"mode": "TEST",
"evaluation_mode": "ALL",
"scope": {
"transaction_types": [
"finance"
]
},
"conditions": [
{
"field": "amount",
"operator": "lt",
"value": 10000
}
],
"aggregation": [
{
"metric": "count",
"operator": "gte",
"value": 20,
"window": "30d",
"filters": {
"direction": "INBOUND",
"subject_vendor_data": "__current__"
}
}
],
"actions": [
{
"type": "add_score",
"value": 35
}
]
}
resp = requests.post(
'https://verification.didit.me/v3/transactions/rules/',
headers={'x-api-key': os.environ['DIDIT_API_KEY']},
json=rule,
timeout=15,
)
resp.raise_for_status()
print(resp.json()['uuid'], resp.json()['mode'])const rule = {
"title": "Structuring - inbound (custom)",
"description": "20+ inbound transfers under 10,000 in 30 days from the same subject.",
"category": "finance",
"mode": "TEST",
"evaluation_mode": "ALL",
"scope": {
"transaction_types": [
"finance"
]
},
"conditions": [
{
"field": "amount",
"operator": "lt",
"value": 10000
}
],
"aggregation": [
{
"metric": "count",
"operator": "gte",
"value": 20,
"window": "30d",
"filters": {
"direction": "INBOUND",
"subject_vendor_data": "__current__"
}
}
],
"actions": [
{
"type": "add_score",
"value": 35
}
]
};
const resp = await fetch('https://verification.didit.me/v3/transactions/rules/', {
method: 'POST',
headers: {
'x-api-key': process.env.DIDIT_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify(rule),
});
if (!resp.ok) throw new Error(await resp.text());
const created = await resp.json();
console.log(created.uuid, created.mode);<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://verification.didit.me/v3/transactions/rules/",
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([
'title' => 'Structuring - inbound (custom)',
'description' => '20+ inbound transfers under 10,000 in 30 days from the same subject.',
'category' => 'finance',
'mode' => 'TEST',
'evaluation_mode' => 'ALL',
'scope' => [
'transaction_types' => [
'finance'
]
],
'conditions' => [
[
'field' => 'amount',
'operator' => 'lt',
'value' => 10000
]
],
'aggregation' => [
[
'metric' => 'count',
'operator' => 'gte',
'value' => 20,
'window' => '30d',
'filters' => [
'direction' => 'INBOUND',
'subject_vendor_data' => '__current__'
]
]
],
'actions' => [
[
'type' => 'add_score',
'value' => 35
]
]
]),
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/transactions/rules/"
payload := strings.NewReader("{\n \"title\": \"Structuring - inbound (custom)\",\n \"description\": \"20+ inbound transfers under 10,000 in 30 days from the same subject.\",\n \"category\": \"finance\",\n \"mode\": \"TEST\",\n \"evaluation_mode\": \"ALL\",\n \"scope\": {\n \"transaction_types\": [\n \"finance\"\n ]\n },\n \"conditions\": [\n {\n \"field\": \"amount\",\n \"operator\": \"lt\",\n \"value\": 10000\n }\n ],\n \"aggregation\": [\n {\n \"metric\": \"count\",\n \"operator\": \"gte\",\n \"value\": 20,\n \"window\": \"30d\",\n \"filters\": {\n \"direction\": \"INBOUND\",\n \"subject_vendor_data\": \"__current__\"\n }\n }\n ],\n \"actions\": [\n {\n \"type\": \"add_score\",\n \"value\": 35\n }\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/transactions/rules/")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"title\": \"Structuring - inbound (custom)\",\n \"description\": \"20+ inbound transfers under 10,000 in 30 days from the same subject.\",\n \"category\": \"finance\",\n \"mode\": \"TEST\",\n \"evaluation_mode\": \"ALL\",\n \"scope\": {\n \"transaction_types\": [\n \"finance\"\n ]\n },\n \"conditions\": [\n {\n \"field\": \"amount\",\n \"operator\": \"lt\",\n \"value\": 10000\n }\n ],\n \"aggregation\": [\n {\n \"metric\": \"count\",\n \"operator\": \"gte\",\n \"value\": 20,\n \"window\": \"30d\",\n \"filters\": {\n \"direction\": \"INBOUND\",\n \"subject_vendor_data\": \"__current__\"\n }\n }\n ],\n \"actions\": [\n {\n \"type\": \"add_score\",\n \"value\": 35\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://verification.didit.me/v3/transactions/rules/")
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 \"title\": \"Structuring - inbound (custom)\",\n \"description\": \"20+ inbound transfers under 10,000 in 30 days from the same subject.\",\n \"category\": \"finance\",\n \"mode\": \"TEST\",\n \"evaluation_mode\": \"ALL\",\n \"scope\": {\n \"transaction_types\": [\n \"finance\"\n ]\n },\n \"conditions\": [\n {\n \"field\": \"amount\",\n \"operator\": \"lt\",\n \"value\": 10000\n }\n ],\n \"aggregation\": [\n {\n \"metric\": \"count\",\n \"operator\": \"gte\",\n \"value\": 20,\n \"window\": \"30d\",\n \"filters\": {\n \"direction\": \"INBOUND\",\n \"subject_vendor_data\": \"__current__\"\n }\n }\n ],\n \"actions\": [\n {\n \"type\": \"add_score\",\n \"value\": 35\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"title": "<string>",
"description": "<string>",
"category": "<string>",
"mode": "ACTIVE",
"evaluation_mode": "ALL",
"scope": {
"transaction_types": [
"<string>"
],
"directions": [
"INBOUND"
],
"action_types": [
"<string>"
]
},
"conditions": [
{
"field": "<string>",
"operator": "eq",
"value": "<unknown>",
"value_type": "list",
"score": 50,
"group_index": 123,
"group_logic": "AND",
"groups_logic": "OR"
}
],
"aggregation": [
{
"value": 123,
"metric": "count",
"field": "amount",
"operator": "eq",
"window": "1d",
"filters": {}
}
],
"actions": [
{
"type": "add_score",
"value": 123
}
],
"metadata": {},
"severity": "UNKNOWN",
"source": "PRESET",
"library_key": "<string>",
"latest_triggered_at": "2023-11-07T05:31:56Z",
"run_count": 123,
"approved_count": 123,
"reviewed_count": 123,
"declined_count": 123,
"awaiting_user_count": 123,
"approved_pct": 123,
"reviewed_pct": 123,
"declined_pct": 123,
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z"
}{
"title": [
"A rule with this name already exists."
]
}Authorizations
Body
Creates a CUSTOM rule. Rules in ACTIVE mode take effect immediately for new transactions - create in TEST mode and backtest first.
Rule name. Unique per application among non-deleted rules; duplicates return 400.
Risk theme used for grouping and reporting, e.g. finance, aml_ctf, anomaly_detection, fatf, device_intelligence, crypto_monitoring, travel_rule, responsible_gaming, e_commerce.
ACTIVE evaluates live. TEST evaluates and records rule runs but never touches score or status - the recommended starting mode. DISABLED is skipped.
ACTIVE, DISABLED, TEST Whether every condition must match (ALL) or at least one (ANY). Ignored when conditions use group_index.
ALL, ANY Which transactions the rule applies to. Only these three keys are accepted.
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
One rule action. A rule can carry several; all are applied together when it matches. Rules in TEST mode record what they would have done without applying any action.
- Option 1
- Option 2
- Option 3
- Option 4
- Option 5
- Option 6
Show child attributes
Show child attributes
Free-form metadata stored on the rule.
Response
The created rule.
Rule name. Unique per application among non-deleted rules; duplicates return 400.
Risk theme used for grouping and reporting, e.g. finance, aml_ctf, anomaly_detection, fatf, device_intelligence, crypto_monitoring, travel_rule, responsible_gaming, e_commerce.
ACTIVE evaluates live. TEST evaluates and records rule runs but never touches score or status - the recommended starting mode. DISABLED is skipped.
ACTIVE, DISABLED, TEST Whether every condition must match (ALL) or at least one (ANY). Ignored when conditions use group_index.
ALL, ANY Which transactions the rule applies to. Only these three keys are accepted.
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
One rule action. A rule can carry several; all are applied together when it matches. Rules in TEST mode record what they would have done without applying any action.
- Option 1
- Option 2
- Option 3
- Option 4
- Option 5
- Option 6
Show child attributes
Show child attributes
Free-form metadata stored on the rule.
Informational severity carried by library rules; not settable on custom rules.
UNKNOWN, LOW, MEDIUM, HIGH, CRITICAL PRESET rules come from the library (install/uninstall, mode-only edits); CUSTOM rules are fully yours.
PRESET, CUSTOM Stable library identifier; null for custom rules.
How many transactions matched this rule.