GET /apiv2/compliance/
Open, keyless compliance lookup for a single TRON address. It returns a verdict — is the address blocked, and in which category — served entirely from an in-memory deny-list cache. No API key, no balance, no charge. The point is to let anyone integrate the compliance layer with one HTTP GET.
The endpoint reads only a cache, never the database or a chain node, so a lookup takes a fraction of a millisecond. It is rate limited per IP by the gateway.
Endpoint URL
GET https://netts.io/apiv2/compliance/{address}No authentication headers are required.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| address | string | Yes | TRON base58 address — T followed by 33 characters |
Example Requests
cURL
curl https://netts.io/apiv2/compliance/TTVUvAWUZafeHqQP82sYnfk4jNFPEHCRpLPython
import requests
address = "TTVUvAWUZafeHqQP82sYnfk4jNFPEHCRpL"
r = requests.get(f"https://netts.io/apiv2/compliance/{address}")
data = r.json()
if r.status_code == 200:
d = data["data"]
print(f"blocked : {d['blocked']}")
print(f"category: {d['category']}")
if d["category"] == "aml_risk":
print(f"reason : {d.get('reason_code')} — {d.get('label')}")
else:
print(f"Error: {data}")JavaScript
const address = "TTVUvAWUZafeHqQP82sYnfk4jNFPEHCRpL";
const res = await fetch(`https://netts.io/apiv2/compliance/${address}`);
const { data } = await res.json();
console.log(data.blocked, data.category, data.label);Response
Blocked — on the central deny list (200 OK)
{
"code": 0,
"status": "ok",
"data": {
"address": "TTVUvAWUZafeHqQP82sYnfk4jNFPEHCRpL",
"blocked": true,
"category": "aml_risk",
"severity": "BLOCK",
"reason_code": "SANCTIONS_SCREENING",
"label": "DPRK Bitget Exploit - September 2026",
"checked_at": "2026-09-27T12:00:00+00:00"
}
}Clean — in none of the sets (200 OK)
{
"code": 0,
"status": "ok",
"data": {
"address": "TWaGxHZ9pFCFwUyzKtDsGNb6hEJ7tSjxEC",
"blocked": false,
"category": "clean",
"checked_at": "2026-09-27T12:00:00+00:00"
}
}Response Fields
| Field | Type | Description |
|---|---|---|
| data.address | string | The address that was checked |
| data.blocked | boolean | true if the address is in any blocking set |
| data.category | string | aml_risk, smart_contract, spam_sender or clean (see below) |
| data.severity | string | Only for aml_risk. E.g. BLOCK, REVIEW |
| data.reason_code | string | Only for aml_risk. Machine code, e.g. SANCTIONS_OFAC_SDN |
| data.label | string | Only for aml_risk. Human-readable label |
| data.checked_at | string | UTC ISO-8601 timestamp of the lookup |
Categories
category is a verdict, not a risk score. When an address is in more than one set, the most serious category wins, in this order:
| Category | blocked | Meaning |
|---|---|---|
aml_risk | true | On the central deny list: sanctions, scams, ransomware, stolen assets, fraud, law-enforcement or internal abuse findings. A curated reason is attached |
usdt_frozen | true | The address is frozen by the USDT issuer (Tether). It cannot move USDT, so resource delegation to it is refused |
smart_contract | true | The address is a smart contract. See the note below |
spam_sender | true | Confirmed mass-spam sender |
clean | false | In none of the sets |
Smart contracts are blocked for a technical reason, not an AML one
A smart_contract verdict means energy cannot be delegated to that address — delegation to a contract is not possible on TRON, so the address is refused before an order is ever placed. It does not mean the contract is compromised, tainted or high-risk under AML. Most contracts in this set are perfectly ordinary. Treat smart_contract as "not a delegation target", not as a risk flag.
Reason codes and the data provider
For aml_risk, the reason_code and label describe why the address is listed. Public sanctioning authorities are kept as-is — SANCTIONS_OFAC_SDN, SANCTIONS_EU_FSF, SANCTIONS_UK_FCDO and so on. The name of the commercial screening provider behind a finding is never exposed: such codes are normalised to SANCTIONS_SCREENING, and any provider name is stripped from label.
Deny-list size
GET https://netts.io/apiv2/compliance/statsAggregate sizes of the sets behind the verdict, from the same cache. Open and keyless.
{
"code": 0,
"status": "ok",
"data": {
"aml_risk": 937,
"usdt_frozen": 7633,
"smart_contract": 352047,
"spam_sender": 26963105,
"total": 27323722,
"revision": 974,
"checked_at": "2026-09-27T12:00:00+00:00"
}
}smart_contract is by far the largest AML-neutral part of the total — see the note about contracts above.
Batch lookup (API key)
To check many addresses at once, use the authenticated batch endpoint. It exists to save network round-trips: one request and one internal pipeline instead of N separate GETs. A single address is just a one-element array.
POST https://netts.io/apiv2/compliance/batch
x-api-key: YOUR_KEY
Content-Type: application/json
{ "addresses": ["TTVUvAWUZafeHqQP82sYnfk4jNFPEHCRpL", "TWaGxHZ9pFCFwUyzKtDsGNb6hEJ7tSjxEC"] }Up to 1000 addresses per request. Verdicts come back in the same order, each with the same fields as the single-address response, plus category: "invalid" (and an error field) for any malformed entry — one bad entry does not fail the whole batch.
{
"code": 0,
"status": "ok",
"data": {
"count": 2,
"checked_at": "2026-09-27T12:00:00+00:00",
"results": [
{ "address": "TTVUvAWUZafeHqQP82sYnfk4jNFPEHCRpL", "blocked": true, "category": "aml_risk", "severity": "BLOCK", "reason_code": "SANCTIONS_SCREENING", "label": "DPRK Bitget Exploit - September 2026" },
{ "address": "TWaGxHZ9pFCFwUyzKtDsGNb6hEJ7tSjxEC", "blocked": false, "category": "clean" }
]
}
}The batch endpoint requires an API key (x-api-key header) and the key can optionally be bound to an IP whitelist. Contact us to obtain a key.
Its rate limit is per key and higher than the public single-address endpoint:
| Period | Limit |
|---|---|
| 1 second | 200 requests |
| 1 minute | 12,000 requests |
Each request may carry up to 1000 addresses, so a single key can screen well over a hundred thousand addresses per second within this limit.
Error Responses
Invalid address format (400)
{
"code": 1001,
"status": "error",
"msg": "Invalid TRON address format (expected base58, 'T' + 33 chars)"
}Service temporarily unavailable (503)
{
"code": 5003,
"status": "error",
"msg": "compliance service temporarily unavailable"
}Error Code Reference
| Code | Description | HTTP Status |
|---|---|---|
0 | Success | 200 |
1001 | Invalid TRON address format | 400 |
5003 | Cache backend temporarily unavailable | 503 |
Rate Limits
There are two tiers, enforced at the gateway:
| Endpoint | Auth | Limited by | 1 second | 1 minute |
|---|---|---|---|---|
GET /apiv2/compliance/{address} | open, keyless | IP | 10 | 300 |
GET /apiv2/compliance/stats | open, keyless | IP | 10 | 300 |
POST /apiv2/compliance/batch | API key | key | 200 | 12,000 |
The open single-address endpoint is intended for interactive and light programmatic use. For bulk screening use the batch endpoint: with up to 1000 addresses per request and 200 requests/second per key, a single key screens well over a hundred thousand addresses per second. Need more? The per-key limit is a policy setting, not a technical ceiling — contact us.
Rate Limit Exceeded (429)
{
"message": "API rate limit exceeded"
}Notes
- No authentication and no cost. Anyone can call it; there is nothing to sign.
- Cache-only. The verdict never touches the database or a node, so it is fast and safe to poll within the rate limit.
- Not a full AML report. For a risk score, exposure breakdown and a signed report use the authenticated screening API (POST /apiv2/screening). This endpoint answers one narrower question: is the address on our deny list, and why.