One request turns an address into a risk verdict. Same engine as the site: same 0–1000 score, same S–D rank, same findings. EVM, Solana and Tron, detected from the address itself.
curl "https://radarium.app/api/v1/score?address=0x28c6c06298d514db089934071355e5743bf21d60" \ -H "Authorization: Bearer rad_your_key_here"
{
"address": "0x28c6c06298d514db089934071355e5743bf21d60",
"chain": "evm",
"activeChains": ["eth", "bsc", "base"],
"score": 640,
"rank": "B",
"findings": [
{ "severity": "risk", "key": "riskyApproval",
"params": { "count": 3 }, "points": -150, "fixDelta": 790 },
{ "severity": "warn", "key": "dustExposure",
"params": { "tokenCount": 88 }, "points": -80, "fixDelta": 720 },
{ "severity": "info", "key": "lowCoverage", "points": 0 }
],
"badges": ["veteran", "multichain"],
"flagged": null,
"coverage": 0.86,
"unavailable": ["lending"],
"modelVersion": 4
}API access is part of PRO. Keys are generated from your account and shown once.
GET A KEY ▸The rank is a pure function of the score, so you can render it yourself without a second call. Radarium paints S through B in its accent color and C through D in its risk color.
A flagged address short-circuits all of this: score is 0, rank is D, and flagged carries the lists that matched. The remaining findings are still returned so you can show why.
Generate a key from your account. It is shown once and stored only as a hash, so a lost key is replaced rather than recovered. Send it as a Bearer token on every request.
Authorization: Bearer rad_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Two shapes for the same call. Use GET for quick integration, POST when the address comes from a request body you already have.
curl "https://radarium.app/api/v1/score?address=0xYourWalletHere" \ -H "Authorization: Bearer rad_your_key_here"
curl -X POST "https://radarium.app/api/v1/score" \
-H "Authorization: Bearer rad_your_key_here" \
-H "content-type: application/json" \
-d '{"address":"0xYourWalletHere"}'access-control-allow-origin: * access-control-allow-methods: GET, POST, OPTIONS access-control-allow-headers: authorization, content-type
Eleven fields, all always present. Three of them exist because the engine refuses to guess: coverage, unavailable and modelVersion. Read them before you trust a score.
| Field | Type | Meaning |
|---|---|---|
| address | string | The address exactly as you sent it. |
| chain | "evm" | "solana" | "tron" | Detected from the address format. You never pass it. |
| activeChains | string[] | Networks the wallet actually shows activity on. EVM wallets can span several. |
| score | number | 0 to 1000. Starts at 1000; only evidence deducts. Never rises above the coverage ceiling. |
| rank | "S" | "A" | "B" | "C" | "D" | Derived from score. See Ranks. |
| findings | Finding[] | What cost points, as i18n keys plus params. Never resolved text. |
| badges | BadgeKey[] | Positive signals that award no points: "veteran", "battleTested", "multichain", "cleanPortfolio". |
| flagged | { sources, kind } | null | Hard fail. kind is "sanction" or "scam"; sources names the lists that matched. When set, score is 0. |
| coverage | number | 0 to 1. Share of risk signals that could actually be computed. |
| unavailable | SourceId[] | Which signals could not be read this time. A signal in here was never counted as clean. |
| modelVersion | number | Current: 4. Increments whenever a weight changes. Compare scores only within one version. |
A finding names what cost points. severity is "info", "warn" or "risk". points is negative, or 0 for informational findings. fixDelta is the score you would land on if that one item were resolved, which is what powers the fix list on the site.
{
severity: "info" | "warn" | "risk"
key: "riskyApproval" | "nftOperator" | "honeypotToken"
| "liquidationRisk" | "fresh" | "dirtyFunding"
| "dustExposure" | "lowActivity" | "sweepPattern"
| "maliciousAddress" | "riskyDelegation" | "flagged"
| "contractAddress" | "delegatedAccount" | "itemDelegate"
| "lowCoverage"
params?: Record<string, string | number>
points: number
fixDelta?: number
}coverage is the share of risk sources that answered. Anything listed in unavailable was not counted as clean, and the score is capped accordingly. A wallet with coverage 0.6 and score 900 has not been proven safe; it has been partially checked. Sources are identity, age, lists, goplus, funding, sweep, approvals and lending.
Every error is JSON with a single error field carrying the code below. The 503 is the one worth handling deliberately.
| Status | Code | Cause |
|---|---|---|
| 400 | invalid_json | POST body was not valid JSON. |
| 401 | missing_api_key | No Authorization header, or it was not a Bearer token. |
| 401 | invalid_api_key | Key is unknown or revoked. |
| 403 | pro_required | The key belongs to an account without an active paid plan. |
| 422 | missing_address | No address parameter or body field. |
| 422 | unsupported_address | Address matched none of EVM, Solana or Tron. |
| 429 | rate_limited | Over 60 requests in the current minute. |
| 503 | chain_unavailable | The chain could not be reached. Radarium returns no result rather than a guessed one. |
There is no partial-result fallback and no synthetic data. If the chain cannot be read, you get the 503 rather than a score built on nothing. Retry it; do not cache it.
Sixty requests per minute per key. Every response carries the current window.
Findings are keys, not sentences. You get key plus paramsso you can render them in any of Radarium's 12 languages, or in your own copy. The site resolves the same keys.
Scores move. Compare scores only within one modelVersion. When it increments, weights changed and a drop is not necessarily a wallet getting worse.
CORS is open so you can call this from a browser, but a key in client-side code is a key you have published. Call it from your server.
Scores are heuristic signals, not guarantees, and not financial advice.