Skip to main content

Address checks

An address check screens one address on one asset and answers with a verdict: a score, a band, the findings that moved the score, and everything needed to read it correctly and to reproduce it later. To screen a transaction instead, see Transaction checks.

Request​

POST /v1/checks with the checks:write scope (see Authentication).

FieldRequiredDescription
subjectyes"address".
assetyesAn asset symbol exactly as listed in Supported assets, at most 20 characters.
addressyesThe address to screen, at most 160 characters. Its shape must be valid for the asset.

Unknown fields are rejected. Send an Idempotency-Key header with your own operation id so a retried request never screens or charges twice; see Idempotency.

curl -s -X POST https://api.leeri.ai/v1/checks \
-H "Authorization: Bearer $LEERI_API_KEY" \
-H "Idempotency-Key: customer-8841-onboarding" \
-H "Content-Type: application/json" \
-d '{"subject":"address","asset":"TRX","address":"'"$ADDRESS"'"}'

Response​

Successful responses use one envelope: the outer status is "ok", the check is in data, and errors is empty. Errors use the error envelope instead.

The check itself has one shape for every state. Branch only on data.status:

data.statusMeaning
completedThe verdict finished inside the request and is in the response.
pendingThe check was handed to a queue. Poll GET /v1/checks/{check_id} or wait for a webhook; see Pending and polling.
failedThe check ended without a verdict. It is never charged. POST answers 422 CHECK_FAILED; you meet this status when reading a check later.

Every field is present in every state. Where a pending or failed check has nothing to report yet, the field is null (or an empty list). This is a trimmed example of a completed check; values are illustrative.

{
"status": "ok",
"data": {
"check_id": "5b0c3f64-1a52-4c8e-9f3e-2f6c1d7a9e10",
"verdict_id": "0f4d7e1c-6b2a-4d39-8e55-3a9c2b8f7d41",
"status": "completed",
"subject": "address",
"asset": "TRX",
"chain": "tron",
"address": "TEXAMPLEexampleEXAMPLEexample00000",
"score": 74,
"band": "high",
"analysis_depth": "full",
"partial": false,
"partial_reasons": [],
"degraded_sources": [],
"ruleset_version": "v23",
"label_snapshot_id": "412345",
"chain_height": "68000000",
"findings": [
{
"rule_id": "heuristic:transit",
"category": "unknown",
"weight": "25",
"source": "chain-engine",
"source_url": "https://leeri.ai/rules/transit?v=v23",
"source_kind": "methodology",
"provider": null,
"observed": { "role": "subject", "score": 62 }
}
],
"report": {
"id": "r1_…",
"pdf_url": "…",
"json_url": "…",
"verification_url": "…"
},
"created_at": "2026-10-27T09:14:02.118Z",
"completed_at": "2026-10-27T09:14:04.907Z"
},
"errors": []
}

Reading the verdict​

Identity and timing​

FieldMeaning
check_idThe id of the check. Use it to poll and to read the check again.
verdict_idThe id of the verdict the check produced, and the id POST /v1/verdicts/{verdict_id}/rederive takes. null until the check completes.
statuscompleted, pending or failed.
subjectaddress or transaction.
assetThe asset symbol you sent.
chainThe chain the asset lives on, for example tron. null where the asset has none.
addressThe address that was screened.
created_at, completed_atWhen the check was accepted and when it finished. completed_at is null until then.

Score and band​

FieldMeaning
scoreA number from 0 to 100. null until the check completes.
bandThe band the score falls in: low, medium, high or severe. null until the check completes.
analysis_depthfull for assets screened with graph traversal and exposure by hop; label_only for assets screened by an address-to-label lookup without traversal. Both are real, charged answers; this field tells you which kind you received, so a label_only result is never mistaken for the deeper one. See Supported assets.

In the current ruleset the bands are low for scores 0 to 30, medium for 31 to 70, high for 71 to 90 and severe for 91 to 100. The boundaries belong to a ruleset version, so read the band from the band field instead of recomputing it from the score.

How complete the verdict is​

A provider outage does not turn into an error. The check answers with a verdict that says it is incomplete and why. Treat a partial verdict as a verdict with less evidence, not as a clean one.

FieldMeaning
partialtrue when a source the verdict depends on was unavailable or stale, the traversal was incomplete, or the answer is bounded by a stated engine limit.
partial_reasonsThe reasons, as stable codes. Some state a bound of the analysis (a traversal depth or size limit, direct counterparties only on Ethereum, BNB Smart Chain and Base); the verdict is then the full service for that address and is charged. Others state that a source was down; such a verdict is not charged and can be re-run later. The full list is in the API reference.
degraded_sourcesThe sources that were down, listed as provider and never by name. Any entry here makes the verdict non-billable.
provider_fallbackWhich stored answers from a third-party data source stood in because that source did not answer, and how old the oldest one is (addresses, reasons, oldest_answer_at, oldest_answer_age_days). null while the check is pending or failed. An object with an empty addresses list when none was used.
coverage_limitationsWhat the chain data source cannot show for this asset, stated on the verdict: evm_internal_transfers (native coin moved by a contract call is not visible), untraced_inbound_majority (more than half of the incoming funds could not be traced to a source, so the score may understate the exposure) and unpriced_assets (an asset that could not be valued in USD was moved). These are statements, not partial results: they do not set partial or change billing.
exposureIndexLagtrue when a newer deposit-attribution run exists than the exposure data this verdict used. Direct labels are available; deeper attribution waits for the next regeneration.

The pin​

A verdict is derived from three coordinates, recorded on it so it can be reproduced exactly as issued.

FieldMeaning
ruleset_versionThe version of the scoring rules applied.
label_snapshot_idThe position in the label history the verdict read.
chain_heightThe chain height the verdict was derived at.
pinThe same three coordinates in one object, plus what the verdict read from the exposure index (index, and exposure with its method, execution_mode and related fields). null while pending or failed.

Store check_id, verdict_id and the pin with your own decision record. Rederiving a verdict (POST /v1/verdicts/{verdict_id}/rederive, scope checks:read) replays it under its pinned ruleset and label snapshot, never a newer one; see Rederive.

Findings​

findings lists the rules that moved the score. A finding is never an unexplained number: each one states what fired and where its evidence is.

FieldMeaning
rule_idThe rule that fired.
categoryOur label category: exchange, mixer, sanctioned, scam, contract, bridge, merchant, unknown, ransomware, exploit, gambling, illicit, high_risk_exchange or unidentified_service.
weightHow much the finding counts in the score, as a decimal string.
sourceWhere the finding comes from: a short code for a public source, chain-engine for our own heuristics, or provider when it rests on a third-party data source. No data source is ever named.
source_urlA link that always resolves and is never null.
source_kindWhat source_url points to. document is a public source document, such as an authority list or a published freeze event. methodology is a versioned page on https://leeri.ai/rules that describes what the rule detects and why it fired at this ruleset version.
providerAlways null for a finding that rests on a third-party data source.
evidence_chain, evidence_tx_hashThe chain and transaction the finding points at, when there is one.
observedWhat the screen observed behind the finding: the role of the address, counts, amounts in USD, hops, the addresses and transactions involved. null only for a check made before observations were recorded. Evidence, not score.
evidence_refsFurther structured evidence. Treat unknown keys as informational.

Exposure​

exposure states where the address's money came from or went, by category, hop and direction, so you can see how indirect a risky link is.

FieldMeaning
categoryThe category of the counterparty group.
hop, hop_toThe distance from the checked address; 0 is a direct counterparty. Beyond hop 8 a slice covers a range of hops, from hop to hop_to.
directionin for funds received, out for funds sent.
amount_usd, shareThe value of the slice and its fraction of the total, as decimal strings.
address_countHow many addresses the slice covers.
scoringWhether the slice counts toward the score or is shown for context.
sourcePresent as provider only on a slice reported by a third-party data source.

Slices from our own traversal are absent for a label_only asset, and the list is empty for an address that is itself a known token contract; in both cases that is by design, not because the traversal failed.

Wallet security warnings​

wallet_security_warnings carries signals addressed to the owner of the checked address, such as address poisoning, an impersonating lookalike or counterfeit tokens. They say nothing about the address being risky and never change the score, the band or any finding. Each has rule_id, severity (critical, high, warning or info), source, source_url, source_kind (always methodology), observed and evidence_refs. The list is always present and empty while the check is pending or failed.

Transaction fields​

tx_hash, direction, amount and risky_volume_usd describe a transaction check and are null on an address check. amount and risky_volume_usd are decimal strings, never floats. See Transaction checks.

Waiting fields​

pending_reason, deadline_at and next_attempt_at describe a check that is still pending and are null once it is terminal. See Pending and polling.

The evidence report​

report links the evidence report of a completed check; the report is included in the check price. It holds id, pdf_url, json_url and verification_url, and is null while the check is pending or failed. The id is a capability: anyone who holds it can open the report, so treat it like the report itself. The JSON twin carries a hash of its contents, and the verification page confirms the report is genuine and unaltered; see Evidence reports.

Charging and errors​

Checking the same address on the same chain again within 7 days is free; see Rate limits and quotas. Errors you should expect from POST /v1/checks:

StatusCodeWhen
400VALIDATION_ERRORAn unknown field, a missing field, or an address whose shape is invalid for the asset.
422UNSUPPORTED_ASSETThe asset is not in Supported assets.
402INSUFFICIENT_BALANCEQuota and prepaid balance are both used up.
429PROVIDER_CAPACITY_EXCEEDEDCapacity for lookups is full. Retry after Retry-After; nothing was accepted or charged.
503RULESET_UNAVAILABLENo scoring ruleset could be reached. Never a clean-looking verdict, never charged.

Authentication and rate limiting errors are covered in Authentication and Rate limits and quotas. When a webhook is registered, a completed check is also delivered to it once; see Webhooks.