Skip to content

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 ​

ParameterTypeRequiredDescription
addressstringYesTRON base58 address — T followed by 33 characters

Example Requests ​

cURL ​

bash
curl https://netts.io/apiv2/compliance/TTVUvAWUZafeHqQP82sYnfk4jNFPEHCRpL

Python ​

python
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 ​

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) ​

json
{
    "code": 0,
    "status": "ok",
    "data": {
        "address": "TTVUvAWUZafeHqQP82sYnfk4jNFPEHCRpL",
        "blocked": true,
        "category": "aml_risk",
        "severity": "BLOCK",
        "reason_code": "SANCTIONS_SCREENING",
        "label": "DPRK Bitget Exploit - September 2026",
        "subtype": null,
        "subtype_status": "not_found",
        "matches": ["aml_risk"],
        "checks_complete": true,
        "checked_at": "2026-09-27T12:00:00+00:00"
    }
}

GasFree wallet — a smart contract that can receive USDT (200 OK) ​

json
{
    "code": 0,
    "status": "ok",
    "data": {
        "address": "TZEMF5vmSABaWjeUPty8kFpUsquMAKhGFp",
        "blocked": true,
        "category": "smart_contract",
        "subtype": "gasfree_wallet",
        "subtype_status": "confirmed",
        "matches": ["smart_contract"],
        "checks_complete": true,
        "checked_at": "2026-10-23T12:00:00+00:00"
    }
}

Deleted contract — the address still counts as a smart contract (200 OK) ​

json
{
    "code": 0,
    "status": "ok",
    "data": {
        "address": "TBtrogXC58EAvE7vod56ZnzRY4y5jrwtbN",
        "blocked": true,
        "category": "smart_contract",
        "subtype": "selfdestructed_contract",
        "subtype_status": "confirmed",
        "matches": ["smart_contract"],
        "checks_complete": true,
        "checked_at": "2026-10-23T21:40:00+00:00"
    }
}

Clean — in none of the sets (200 OK) ​

json
{
    "code": 0,
    "status": "ok",
    "data": {
        "address": "TWaGxHZ9pFCFwUyzKtDsGNb6hEJ7tSjxEC",
        "blocked": false,
        "category": "clean",
        "subtype": null,
        "subtype_status": "not_found",
        "matches": [],
        "checks_complete": true,
        "checked_at": "2026-09-27T12:00:00+00:00"
    }
}

Response Fields ​

FieldTypeDescription
data.addressstringThe address that was checked
data.blockedbooleantrue if the address is in any blocking set
data.categorystringaml_risk, usdt_frozen, smart_contract, spam_sender or clean (see below); the batch endpoint can also return invalid or unavailable
data.severitystringOnly for aml_risk. E.g. BLOCK, REVIEW
data.reason_codestringOnly for aml_risk. Machine code, e.g. SANCTIONS_OFAC_SDN
data.labelstringOnly for aml_risk. Human-readable label
data.subtypestring | nullRefines smart_contract. gasfree_wallet — a live GasFree wallet (see GasFree wallets); selfdestructed_contract — the contract at this address has been deleted (see Deleted contracts); null otherwise
data.subtype_statusstringconfirmed — the subtype is known by the latest confirmed state; not_found — neither subtype applies; unavailable — a subtype list could not be consulted right now, so subtype is null and says nothing
data.matchesstring[]All sets the address is in, in priority order (e.g. ["usdt_frozen", "smart_contract", "spam_sender"]). category is only the first of them
data.checks_completebooleantrue if all four sets were loaded and up to date at the time of the lookup. false means a clean answer rests on an incomplete check
data.checked_atstringUTC 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 (all of them are listed in matches):

CategoryblockedMeaning
aml_risktrueOn the central deny list: sanctions, scams, ransomware, stolen assets, fraud, law-enforcement or internal abuse findings. A curated reason is attached
usdt_frozentrueThe address is frozen by the USDT issuer (Tether). It cannot move USDT, so resource delegation to it is refused
smart_contracttrueA known smart contract address, including contracts deleted later. See the note below
spam_sendertrueConfirmed mass-spam sender
cleanfalseIn none of the sets
unavailablenullThe central deny list could not be consulted, so the address is neither confirmed clean nor blocked. Batch only; the single-address endpoint returns 503 with code 5004 instead. See Central deny-list unavailable

Smart contracts are blocked for a technical reason, not an AML one

A smart_contract verdict means the address belongs to a contract, not to a user wallet, so energy is not delegated to it and the address is refused before an order is ever placed. The set holds every address where a contract was successfully created, including contracts that were deleted later — a deleted contract does not turn its address into a user wallet. 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.

GasFree wallets ​

A GasFree wallet is a contract that lets its owner receive and send tokens and pay the network fee in those tokens. Each one is created by the GasFree controller TFFAMQLZybALaLb4uxHA9RBE7pxhUAjF3U. Such an address is reported as category: "smart_contract" with subtype: "gasfree_wallet".

The difference matters when you route funds:

Ordinary smart contractGasFree wallet
Send USDT to itnot a normal recipientyes — it is a user's wallet
Delegate energy to itnono — we do not delegate energy to GasFree wallets
category / subtypesmart_contract / nullsmart_contract / gasfree_wallet

Coverage and caveats:

  • Only deployed wallets are known. A GasFree address that has received USDT but has never sent anything is not deployed yet, so it is not in any set and comes back as clean.
  • The subtype describes where the address can receive funds. It says nothing about transfers from a GasFree wallet; screen the sender address separately.
  • subtype_status: "unavailable" means the GasFree list could not be consulted. The rest of the verdict (blocked, category, matches) is still valid.
  • The controller itself and other contracts are not GasFree wallets: they come back with subtype: null.

Deleted contracts ​

A contract can delete itself (self-destruct). The address stays in the smart_contract set: it was a contract address, not a user wallet, and Netts does not delegate resources or send payouts to it. Such an address is reported as category: "smart_contract" with subtype: "selfdestructed_contract".

  • confirmed means deleted by the latest state confirmed by a TRON node. It is not a promise about the future: a contract can be deployed at the same address again, and then the subtype is removed while the address stays a smart_contract.
  • A self-destruct call alone does not mean deletion: on TRON a contract created in an earlier transaction keeps its code after it. Only the node state counts.
  • If an address is both a deleted contract and in a GasFree list, selfdestructed_contract wins — the address is not reported as a working GasFree wallet.
  • subtype_status: "unavailable" means the list of deleted contracts could not be consulted; the rest of the verdict is still valid, and no address is confirmed as a GasFree wallet until it can be consulted again.

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/stats

Aggregate sizes of the sets behind the verdict, from the same cache. Open and keyless.

json
{
    "code": 0,
    "status": "ok",
    "data": {
        "aml_risk": 1079,
        "usdt_frozen": 8022,
        "smart_contract": 7581686,
        "spam_sender": 27039018,
        "gasfree_wallets_subset": 512487,
        "selfdestructed_contracts_subset": 4065766,
        "total": 34629805,
        "revision": 1117,
        "checked_at": "2026-10-23T21:40:00+00:00"
    }
}

smart_contract is the largest AML-neutral part of the total — see the note about contracts above. gasfree_wallets_subset (live GasFree wallets) and selfdestructed_contracts_subset (deleted contracts) are parts of smart_contract; they are not added to total. If one of these two counters cannot be read right now, it is null and the other numbers are still returned.

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 (including subtype, subtype_status, matches and checks_complete), plus category: "invalid" (with an error field) for any malformed entry — one bad entry does not fail the whole batch. If the central deny list is not loaded, an otherwise-clean address comes back as category: "unavailable" (blocked: null, with an error field) rather than clean — see Central deny-list unavailable.

json
{
    "code": 0,
    "status": "ok",
    "data": {
        "count": 2,
        "checked_at": "2026-09-27T12:00:00+00:00",
        "results": [
            { "address": "TTVUvAWUZafeHqQP82sYnfk4jNFPEHCRpL", "blocked": true, "category": "aml_risk", "subtype": null, "subtype_status": "not_found", "matches": ["aml_risk"], "checks_complete": true, "severity": "BLOCK", "reason_code": "SANCTIONS_SCREENING", "label": "DPRK Bitget Exploit - September 2026" },
            { "address": "TWaGxHZ9pFCFwUyzKtDsGNb6hEJ7tSjxEC", "blocked": false, "category": "clean", "subtype": null, "subtype_status": "not_found", "matches": [], "checks_complete": true }
        ]
    }
}

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:

PeriodLimit
1 second200 requests
1 minute12,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) ​

json
{
    "code": 1001,
    "status": "error",
    "msg": "Invalid TRON address format (expected base58, 'T' + 33 chars)"
}

Service temporarily unavailable (503) ​

json
{
    "code": 5003,
    "status": "error",
    "msg": "compliance service temporarily unavailable"
}

Central deny-list unavailable (503, code 5004) ​

The verdict is served from an in-memory cache. If that cache is reachable but the central AML deny list is not currently loaded, or its current revision fails an integrity check, the endpoint does not fall back to clean — that would report an unchecked address as safe. Instead it tells you plainly that it could not produce a verdict:

json
{
    "code": 5004,
    "status": "error",
    "msg": "compliance deny-list temporarily unavailable, verdict cannot be produced"
}

What this means: the address is neither confirmed clean nor blocked. The service could not screen it against the sanctions/AML list right now. Do not treat the address as clean — retry shortly.

A definite block is still returned normally: if the address is a frozen-USDT, smart-contract or spam-sender match (sets that do not depend on the central list), you get the usual blocked: true verdict even in this state. Only a would-be clean answer becomes 5004.

In the batch endpoint the same situation is reported per-address as category: "unavailable" (blocked: null, with an error field); the rest of the batch is unaffected. This is a rare, transient state.

Registry unavailable (503, code 5005) ​

The sets are updated in place and stay readable while they are updated, so a routine update never affects the verdict. Only if a set failed to apply can an otherwise-clean address not be confirmed clean. The single-address endpoint then returns:

json
{
    "code": 5005,
    "status": "error",
    "msg": "address registry temporarily unavailable, verdict cannot be produced, retry shortly"
}

As with 5004, a definite block is still returned normally, and the batch endpoint reports the case per address as category: "unavailable". Retry later.

Error Code Reference ​

CodeDescriptionHTTP Status
0Success200
1001Invalid TRON address format400
5003Cache backend temporarily unavailable503
5004Central deny list not loaded — verdict cannot be produced (retry)503
5005A set failed to apply — verdict cannot be produced (retry)503

Rate Limits ​

There are two tiers, enforced at the gateway:

EndpointAuthLimited by1 second1 minute
GET /apiv2/compliance/{address}open, keylessIP10300
GET /apiv2/compliance/statsopen, keylessIP10300
POST /apiv2/compliance/batchAPI keykey20012,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) ​

json
{
    "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.