POST /apiv2/aml
Superseded by POST /apiv2/screening
POST /apiv2/screening is the version 2 contract: one response shape for every provider and every state of the order, decimal numbers as strings instead of JSON numbers, shares on one scale, and a single error format. This endpoint keeps working and will not be withdrawn without notice.
Submit an address for AML (Anti-Money Laundering) screening. Returns risk score, risk level, and detailed exposure analysis.
All timestamps in the response are UTC. The string format is unchanged — "2026-09-09 23:01:44", without a zone suffix.
Endpoint URL
POST https://netts.io/apiv2/amlRequest Headers
| Header | Required | Description |
|---|---|---|
| Content-Type | Yes | application/json |
| X-API-KEY | Yes | Your API key from Netts dashboard |
Request Body
{
"address": "YOUR_ADDRESS_HERE",
"network": "trx",
"provider": "elliptic",
"wait": true
}Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| address | string | Yes | Blockchain address to check (10-100 characters) |
| network | string | Yes | Blockchain network identifier (see Supported Networks below) |
| provider | string | No | AML provider: elliptic (default) |
| wait | boolean | No | If true, wait for result synchronously (up to 15 seconds). If false or omitted, return immediately with pending status and client_order_id — use it to poll result via GET /apiv2/aml/{order_id} |
| response_format | string | No | Response detail level: rate (score only), full (default, complete data) |
| report_language | string | No | Language for report: en (default) |
Providers
| Provider | Score Range | Description |
|---|---|---|
elliptic | 0 — 10 | Elliptic risk score. 0 = no risk, 10 = maximum risk. null = no triggers detected |
Example Requests
cURL (synchronous)
curl -X POST https://netts.io/apiv2/aml \
-H "Content-Type: application/json" \
-H "X-API-KEY: your_api_key" \
-d '{
"address": "YOUR_ADDRESS_HERE",
"network": "trx",
"provider": "elliptic",
"wait": true
}'cURL (asynchronous)
curl -X POST https://netts.io/apiv2/aml \
-H "Content-Type: application/json" \
-H "X-API-KEY: your_api_key" \
-d '{
"address": "YOUR_ADDRESS_HERE",
"network": "trx",
"provider": "elliptic"
}'Python
import requests
url = "https://netts.io/apiv2/aml"
headers = {
"Content-Type": "application/json",
"X-API-KEY": "your_api_key",
}
payload = {
"address": "YOUR_ADDRESS_HERE",
"network": "trx",
"provider": "elliptic",
"wait": True
}
response = requests.post(url, headers=headers, json=payload)
data = response.json()
if response.status_code == 200:
result = data.get("data", {})
print(f"Order ID: {result.get('client_order_id')}")
print(f"Status: {result.get('status')}")
print(f"Risk Score: {result.get('risk_score')}")
print(f"Risk Level: {result.get('risk_level')}")
print(f"Sanctioned: {result.get('is_sanctioned')}")
else:
print(f"Error: {data}")Response
Success — Pending (200 OK)
When wait is not set or check is still processing:
{
"success": true,
"data": {
"client_order_id": "A4C666ABE24BD4A",
"status": "pending",
"address": "T...example...",
"provider": "elliptic",
"price_usdt": 0.98,
"price_trx": 4.136286,
"currency": "TRX",
"message": "AML check order accepted. Use GET /apiv2/aml/A4C666ABE24BD4A to check status."
},
"timestamp": "2026-03-10 09:56:31"
}Success — Elliptic Completed (200 OK)
Full Elliptic response with all data structures:
{
"success": true,
"data": {
"client_order_id": "A019540900E55CA",
"status": "completed",
"address": "T...example...",
"provider": "elliptic",
"report_language": "en",
"risk_score": 0.802904,
"risk_level": "low",
"is_sanctioned": true,
"created_at": "2026-03-10 15:56:28",
"completed_at": "2026-03-10 15:56:28",
"result": {
"risk_score": 0.802904473154148,
"risk_score_detail": {
"source": 0.233206,
"destination": 0.802904
},
"contributions": {
"source": [
{
"entities": [
{
"name": "Capitalist",
"is_vasp": true,
"actor_id": 53979,
"category": "Payment Services Provider",
"entity_id": "b73a9c87-...",
"category_id": "54f55bfe-...",
"is_primary_entity": true
}
],
"indirect_value": { "usd": 40194.03 },
"contribution_value": { "usd": 40194.03 },
"counterparty_value": { "usd": 0 },
"min_number_of_hops": 2,
"indirect_percentage": 31.57,
"is_screened_address": false,
"contribution_percentage": 31.57,
"counterparty_percentage": 0
},
{
"entities": [
{
"name": "KuCoin",
"is_vasp": true,
"actor_id": 11620,
"category": "Exchange",
"entity_id": "e54292da-...",
"category_id": "0a52f7a2-...",
"is_primary_entity": true
}
],
"indirect_value": { "usd": 28436.45 },
"contribution_value": { "usd": 29434.17 },
"counterparty_value": { "usd": 997.72 },
"min_number_of_hops": 1,
"indirect_percentage": 22.34,
"is_screened_address": false,
"contribution_percentage": 23.12,
"counterparty_percentage": 0.78
}
],
"destination": [
{
"entities": [
{
"name": "Bybit",
"is_vasp": true,
"actor_id": 23354,
"category": "Exchange",
"entity_id": "bddde8b7-...",
"category_id": "0a52f7a2-...",
"is_primary_entity": true
}
],
"indirect_value": { "usd": 26333.43 },
"contribution_value": { "usd": 27458.30 },
"counterparty_value": { "usd": 1124.86 },
"min_number_of_hops": 1,
"indirect_percentage": 20.69,
"is_screened_address": false,
"contribution_percentage": 21.57,
"counterparty_percentage": 0.88
}
]
},
"cluster_entities": [
{
"name": "Unknown",
"is_vasp": null,
"actor_id": -4,
"category": "Unknown",
"entity_id": "00000000-...",
"category_id": "00000000-...",
"is_primary_entity": true,
"is_after_sanction_date": false
}
],
"evaluation_detail": {
"source": [
{
"rule_id": "6c2dcb03-...",
"rule_name": "Obfuscating & Misc.",
"rule_type": "exposure",
"risk_score": 0.2332,
"matched_elements": [
{
"category": "Coin Swap Service",
"category_id": "ff85b715-...",
"contributions": [
{
"entity": "FixedFloat",
"risk_triggers": {
"category": "Coin Swap Service",
"category_id": "ff85b715-..."
},
"indirect_value": { "usd": 2891.09, "native": 0, "native_major": 0 },
"contribution_value": { "usd": 2968.66, "native": 0, "native_major": 0 },
"counterparty_value": { "usd": 77.58, "native": 0, "native_major": 0 },
"min_number_of_hops": 1,
"indirect_percentage": 2.27,
"is_screened_address": false,
"contribution_percentage": 2.33,
"counterparty_percentage": 0.06
}
],
"indirect_value": { "usd": 2891.09, "native": 0, "native_major": 0 },
"contribution_value": { "usd": 2968.66, "native": 0, "native_major": 0 },
"counterparty_value": { "usd": 0, "native": 0, "native_major": 0 },
"indirect_percentage": 100,
"contribution_percentage": 2.33,
"counterparty_percentage": 0
}
],
"matched_behaviors": []
},
{
"rule_id": "0a2b68fd-...",
"rule_name": "Illicit Activity",
"rule_type": "exposure",
"risk_score": 0.0026,
"matched_elements": [
{
"category": "Token Blacklisting",
"category_id": "94b50de8-...",
"contributions": [
{
"entity": "Tether USD",
"risk_triggers": {
"category": "Token Blacklisting",
"category_id": "94b50de8-..."
},
"contribution_value": { "usd": 1022.45, "native": 0, "native_major": 0 },
"min_number_of_hops": 3,
"contribution_percentage": 0.08
}
]
}
],
"matched_behaviors": []
},
{
"rule_id": "df59fab5-...",
"rule_name": "Sanctions",
"rule_type": "exposure",
"risk_score": 0.0024,
"matched_elements": [
{
"category": "Sanctioned Entity",
"category_id": "c1648b7a-...",
"contributions": [
{
"entity": "Garantex",
"risk_triggers": {
"category": "Sanctioned Entity",
"category_id": "c1648b7a-..."
},
"contribution_value": { "usd": 863.21, "native": 0, "native_major": 0 },
"min_number_of_hops": 3,
"contribution_percentage": 0.07
}
]
}
],
"matched_behaviors": []
}
],
"destination": []
},
"detected_behaviors": []
},
"sanctions": {
"self": false,
"self_entities": null,
"exposure": {
"share": 8.029045,
"proximity": "mixed",
"hops": 1,
"entity": "Garantex Europe OU - OFAC SDN - 5 Apr 2022",
"category": "OFAC Sanctioned Entity",
"direction": "destination",
"rule_name": "Sanctioned, TF & CSAM"
},
"items": [
{
"entity": "Garantex Europe OU - OFAC SDN - 5 Apr 2022",
"category": "OFAC Sanctioned Entity",
"share": 8.02904473154148,
"counterparty_share": 2.472410320321629,
"indirect_share": 5.556634411219852,
"hops": 1,
"proximity": "mixed",
"is_sanctioned": true,
"trigger": "sanctions_list",
"value_usd": 7494.407584232807,
"direction": "destination",
"rule_name": "Sanctioned, TF & CSAM"
}
]
}
},
"timestamp": "2026-03-10 15:56:28"
}Response Fields
| Field | Type | Description |
|---|---|---|
| data.client_order_id | string | Unique order ID for status polling |
| data.status | string | pending, processing, completed, failed, skipped |
| data.risk_score | number | null | Risk score. Elliptic: 0-10. null = no triggers |
| data.risk_level | string | null | none, low, medium, high or severe. Elliptic returns low, medium, high; BitOK adds none and severe. null when the provider detected no triggers at all |
| data.is_sanctioned | boolean | true if exposure to sanctioned entities detected. Unchanged since the endpoint launched: it does not distinguish a sanctioned address from an address merely linked to one — see data.sanctions for that |
| data.sanctions | object | null | Breakdown of the sanctions finding: whether the address itself is listed, how close the link is and how large. See Sanctions |
| data.result | object | Full provider response (when response_format=full) |
Sanctions
is_sanctioned is a single boolean, and it says true in two very different situations: the screened address is itself on a sanctions list, and the screened address once received a fraction of a percent through two intermediaries from someone who is. The flag keeps its original meaning for backward compatibility; data.sanctions tells the two cases apart.
| Field | Type | Description |
|---|---|---|
| sanctions.self | boolean | true when the screened address itself is the sanctioned entity |
| sanctions.self_entities | array | null | Names of its own sanctioned entities, when self is true |
| sanctions.exposure | object | null | The single largest sanctions link — what to show in a summary |
| sanctions.exposure.share | number | Share of funds involved, in percent (8.03 means 8.03%) |
| sanctions.exposure.proximity | string | screened_address, counterparty, indirect or mixed |
| sanctions.exposure.hops | number | null | Minimum number of transaction hops to the sanctioned entity |
| sanctions.exposure.entity | string | null | Sanctioned entity name, including the list and the date |
| sanctions.exposure.direction | string | null | source for incoming funds, destination for outgoing |
| sanctions.items | array | Every sanctions contribution, largest share first, same fields as exposure plus counterparty_share, indirect_share, value_usd and trigger |
| sanctions.related | array | null | BitOK only: exposure to exchanges under EU or UK sanctions, kept apart from the sanctions list itself |
Proximity mirrors the Closest Proximity column of an Elliptic report:
| Value | Meaning |
|---|---|
screened_address | The screened address is the trigger itself, not a counterparty |
counterparty | Direct counterparty of the screened address |
indirect | Reached through intermediaries — see hops |
mixed | Both direct and indirect flows to the same entity |
A contribution counts as a sanctions link only when the provider marks it as such — risk_triggers.is_sanctioned for Elliptic, the sanctions category for BitOK. The Elliptic rule named Sanctioned, TF & CSAM also fires on country and category triggers, so the rule name alone is not a sanctions verdict.
Elliptic result Object
| Field | Type | Description |
|---|---|---|
| risk_score | number | Precise risk score (0-10) |
| risk_score_detail | object | Breakdown: source and destination scores |
| contributions | object | source and destination arrays of fund flow contributors |
| contributions[].entities | array | Known entities associated with the contribution |
| contributions[].entities[].name | string | Entity name (e.g. "Binance", "KuCoin") |
| contributions[].entities[].category | string | Entity type (e.g. "Exchange", "Payment Services Provider") |
| contributions[].entities[].is_vasp | boolean | null | Whether the entity is a Virtual Asset Service Provider |
| contributions[].contribution_value.usd | number | Total USD volume of the contribution |
| contributions[].contribution_percentage | number | Percentage of total funds from this entity |
| contributions[].indirect_value.usd | number | USD volume received indirectly (via intermediaries) |
| contributions[].indirect_percentage | number | Percentage of funds received indirectly |
| contributions[].counterparty_value.usd | number | USD volume as direct counterparty |
| contributions[].counterparty_percentage | number | Percentage as direct counterparty |
| contributions[].min_number_of_hops | number | Minimum transaction hops from the entity (0 = direct) |
| contributions[].is_screened_address | boolean | true if this is the screened address itself |
| cluster_entities | array | Known entities directly associated with the address cluster |
| cluster_entities[].name | string | Entity name |
| cluster_entities[].category | string | Entity category |
| cluster_entities[].is_vasp | boolean | null | VASP status |
| cluster_entities[].is_after_sanction_date | boolean | true if activity occurred after entity was sanctioned |
| evaluation_detail | object | source and destination arrays of triggered risk rules |
| evaluation_detail[].rule_name | string | Rule name (e.g. "Sanctions", "Illicit Activity", "Obfuscating & Misc.") |
| evaluation_detail[].rule_type | string | Rule type (e.g. "exposure") |
| evaluation_detail[].risk_score | number | Risk score contribution from this rule |
| evaluation_detail[].matched_elements | array | Categories and entities that triggered the rule |
| evaluation_detail[].matched_elements[].category | string | Risk category (e.g. "Sanctioned Entity", "Gambling", "Token Blacklisting") |
| evaluation_detail[].matched_elements[].contributions | array | Entities within the matched category |
| evaluation_detail[].matched_elements[].contributions[].entity | string | Entity name |
| evaluation_detail[].matched_elements[].contributions[].contribution_percentage | number | Exposure percentage |
| evaluation_detail[].matched_elements[].contributions[].min_number_of_hops | number | Transaction hops |
| evaluation_detail[].matched_elements[].contributions[].is_screened_address | boolean | true when the screened address itself triggered the rule |
| evaluation_detail[].matched_elements[].contributions[].risk_triggers | object | Why the rule fired: is_sanctioned for a sanctions list, country for a jurisdiction, category for an entity type |
| evaluation_detail[].matched_behaviors | array | Detected behavioral patterns |
| detected_behaviors | array | Global behavioral patterns detected on the address |
Risk Levels
Elliptic (0-10 scale):
| Range | Level | Description |
|---|---|---|
| 0 — 3 | low | Minimal risk. No significant exposure |
| 3 — 7 | medium | Moderate risk. Some risky categories detected |
| 7 — 10 | high | High risk. Sanctioned, illicit, or high-risk entities |
| null | - | No risk triggers detected |
BitOK (0-1 scale): the provider returns the level itself — none, low, medium, high or severe.
risk_level is the single verdict used everywhere: the API response, the dashboard and the PDF report all print the same word for the same check.
Error Responses
Authentication Error (401)
{
"detail": {
"code": -1,
"msg": "API key not provided"
}
}Validation Error (400)
{
"success": false,
"error": {
"code": 4001,
"msg": "Invalid or missing address"
}
}{
"success": false,
"error": {
"code": 4002,
"msg": "Invalid provider. Use: elliptic"
}
}Insufficient Balance (402)
{
"success": false,
"error": {
"code": 4020,
"message": "Insufficient balance"
},
"timestamp": "2026-03-10 10:00:00"
}Provider Unavailable (503)
{
"success": false,
"error": {
"code": 5030,
"message": "Provider elliptic not available"
},
"timestamp": "2026-03-10 10:00:00"
}Error Code Reference
| Code | Description | HTTP Status |
|---|---|---|
-1 | Authentication failed | 401 |
4001 | Invalid or missing address | 400 |
4002 | Invalid provider | 400 |
4020 | Insufficient balance | 402 |
5030 | Provider unavailable | 503 |
Rate Limits
The following rate limits apply to all AML endpoints (per IP address):
| Period | Limit | Description |
|---|---|---|
| 1 second | 2 requests | Maximum 2 requests per second |
| 1 minute | 30 requests | Maximum 30 requests per minute |
Rate Limit Exceeded (429)
{
"message": "API rate limit exceeded"
}Result Caching
If the same address + provider combination was checked within the last 60 seconds, the cached result is returned at no charge.
Supported Networks
The network parameter is required. Use the ticker from the table below.
Elliptic — Holistic Screening
Screening is performed for a specific address on a specific network. However, Elliptic traces all assets associated with that address — including tokens, cross-chain transfers, and interactions with known entities across other networks.
| Network | Ticker | Native Asset |
|---|---|---|
| Algorand | algo | ALGO |
| Aptos | apt | APT |
| Arbitrum | arb | ETH |
| Avalanche (C-Chain) | avax | AVAX |
| Base | base | ETH |
| Binance Chain | bnb | BNB |
| Binance Smart Chain | bsc | BNB |
| Bitcoin | btc | BTC |
| Bittensor | tao | TAO |
| Cardano | ada | ADA |
| Celo | celo | CELO |
| Cosmos | atom | ATOM |
| Crypto.com | cro | CRO |
| Dogecoin | doge | DOGE |
| dYdX | dydx | DYDX |
| Ethereum | eth | ETH |
| Ethereum Classic | etc | ETC |
| Fantom | ftm | FTM |
| Filecoin | fil | FIL |
| Flare | flr | FLR |
| Gnosis | gnosis | xDai |
| Hedera | hbar | HBAR |
| HyperEVM | hype | HYPE |
| Injective | inj | INJ |
| Internet Computer | icp | ICP |
| Linea | linea | LINEA |
| Litecoin | ltc | LTC |
| MobileCoin | mob | MOB |
| Near | near | NEAR |
| Optimism | op | ETH |
| Polkadot | dot | DOT |
| Polygon | matic | MATIC |
| Ripple | xrp | XRP |
| Sei | sei | SEI |
| Solana | sol | SOL |
| Starknet | strk | STRK |
| Stellar | xlm | XLM |
| Sui | sui | SUI |
| Tezos | xtz | XTZ |
| TON | ton | TON |
| Tron | trx | TRX |
| XDC | xdc | XDC |
| XLayer | okb | OKB |
| Zilliqa | zil | ZIL |
| zkSync | zksync | ETH |
Single Asset Screening
These networks support individual address/transaction screening:
| Network | Ticker | Native Asset |
|---|---|---|
| Bitcoin Cash | bch | BCH |
| Horizen | zen | ZEN |
| ZCash | zec | ZEC |
Provider & Network Compatibility
When using provider: "elliptic" — all networks from Holistic and Single Asset tables are available (47 networks). If an unsupported network is passed, the API returns error code 4001.
Notes
- Pricing: Elliptic — $0.98 per check. Prices shown in TRX at current rate
- Sync timeout:
wait: truewaits up to 15 seconds. If check takes longer, returnspendingstatus - Processing time: Most checks complete within a few seconds. However, some requests (especially for addresses with complex transaction history) may take up to 3 minutes to process. Use asynchronous mode (omit
waitor setwait: false) and poll via GET /apiv2/aml/{order_id} for such cases - Inactive addresses: Addresses with no blockchain activity return
skippedstatus at no charge