AXO SAFE Public API
Free REST API for on-chain token safety intelligence. Score any token's risk profile across Robinhood Chain, Ethereum and Solana, probe token existence, and scan wallets for suspicious dust — all reads are on-chain or public RPC, no private keys involved.
Quick start
One endpoint, three actions. Send JSON with an action field. Responses are JSON. CORS is open (Access-Control-Allow-Origin: *) so you can call it straight from a browser.
Example response (real output from the live API):
check-token — full token risk scan
Runs the full safety check on a token. Returns a 0-100 safety score, a verdict and the per-check results.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| action | string | required | Must be "check-token". |
| chain | string | required | One of robinhood, ethereum, solana. |
| address | string | required | Token contract address (0x… for EVM chains) or SPL mint address (base58) for Solana. |
| website | string | optional | Project website URL (optional context). |
| string | optional | Project X/Twitter handle (optional context). |
Score bands
The verdict is derived from the score band, so the number and label always agree.
Response fields
| Field | Description |
|---|---|
| ok | Always true on success. |
| action | Echo of the requested action ("check-token"). |
| chain | Echo of the requested chain. |
| meta | Token metadata. EVM: name, symbol, decimals, supply, address, chain. Solana: address, decimals, supply, chain, mintAuthority, freezeAuthority. Null when nothing was found at the address. |
| checks | Array of per-check results: { id, title, risk, riskLevel, detail, weight }. risk is a label (SAFE / LOW RISK / MEDIUM RISK / HIGH RISK / DANGEROUS), riskLevel its 0-4 numeric value, weight its contribution to the score. |
| score | Safety score 0-100 (100 = safest). |
| verdict | Score-band label: SAFE, LOW RISK, MEDIUM RISK, HIGH RISK or DANGEROUS. |
| worstLevel | Numeric worst band 0-4. |
| notFound | true when no contract/mint exists at the address (still returns the checks that ran). |
| originSignals | Off-chain clues array: { id, title, confidence, detail, riskHint }. confidence is Strong / Weak / Speculative; riskHint is safe / warn / danger / neutral. Includes website domain-age signals (when website is supplied), social signals (when twitter is supplied) and deployer trail (EVM only). |
| disclaimer | "Warning signs, not predictions… Always do your own research." |
Example response — live result for the AXO token on Robinhood Chain (checks array abridged, real score):
exists-token — lightweight existence probe
Fast, cheap probe: does a contract (EVM) or mint account (Solana) exist at this address? Used by the AXO SAFE web app for smart chain auto-detection.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| action | string | required | Must be "exists-token". |
| chain | string | required | One of robinhood, ethereum, solana. |
| address | string | required | Token contract address (0x… for EVM) or SPL mint (base58) for Solana. |
Response
| Field | Description |
|---|---|
| ok | Always true on success. |
| action | "exists-token". |
| chain | Echo of the requested chain. |
| exists | true if contract code (EVM) or a parsed mint account (Solana) was found at the address. |
Example response (real output from the live API):
scan-wallet — dust / scam token scan
Scans a wallet's token balances (up to 25) and flags suspicious unsolicited tokens.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| action | string | required | Must be "scan-wallet". |
| chain | string | required | robinhood or solana (ethereum returns the availability notice above). |
| address | string | required | Wallet address (0x… for EVM, base58 for Solana). |
Response
| Field | Description |
|---|---|
| ok | Always true. |
| action | "scan-wallet". |
| chain | Echo of the requested chain. |
| tokens | Suspicious tokens, highest score first. EVM: { address, name, symbol, decimals, balance, score, risk, reasons[] }. Solana: { address, mint, balance, score, risk, reasons[], mintAuthority, freezeAuthority }. Empty array when nothing suspicious was found. |
| scanned | Number of token balances examined (max 25). Present when balances loaded. |
| note | Present instead of scanned when token balances could not be loaded, e.g. "Could not load token balances." |
| disclaimer | "Flags unsolicited tokens with scam traits. Never interact with unknown tokens." |
| error / warning | Only when the scan could not run (e.g. Ethereum, Solana RPC rate limit): {"error": "...", "warning": true} with HTTP 200. |
Scoring starts at 30 for any unsolicited token and adds points for mimicry (+25), no liquidity (+20), active mint authority (+25 Solana), active freeze authority (+15), unverified contract (+10 EVM). Risk labels: 70+ DANGEROUS, 50+ HIGH RISK, 35+ MEDIUM RISK, below that LOW RISK.
Example response (real output from the live API — here the explorer could not return balances, so a note replaces scanned):
Supported chains
Pass the chain key as the chain parameter on every action.
| Key | Network | Type | check-token | exists-token | scan-wallet |
|---|---|---|---|---|---|
| robinhood | Robinhood Chain (chainId 4663) | EVM | Full | Full | Full |
| ethereum | Ethereum (chainId 1) | EVM | Full | Full | Coming soon |
| solana | Solana mainnet | SPL | Full | Full | Full |
Rate limits
| Scope | Limit | Window | On exceed |
|---|---|---|---|
| /api/axo-safe-token (all actions) | 20 requests per IP | 1 hour | HTTP 429 — {"error": "Rate limit reached (20/hour). Try again later."} |
| /api/axo-safe-pro (action=key-signup) | 5 signups per IP | 1 hour | HTTP 429 — {"error": "Too many signups from this IP. Try again later."} |
The limit is enforced in memory per server instance and resets on cold start. Exceeding requests are rejected before any chain work runs, so a 429 never costs you scan time.
HTTP methods
POST only for scans — any other method returns 405 {"error": "POST only."}. A plain GET on /api/axo-safe-token returns a health check: {"ok": true, "service": "axo-safe-token"}.
Error codes
| Status | Body | When |
|---|---|---|
| 400 | {"error": "Unknown chain. Use robinhood, ethereum, or solana."} | Bad or missing chain value. |
| 400 | {"error": "Missing address."} | address absent or not a string. |
| 400 | {"error": "Invalid address."} | Malformed EVM/Solana address on exists-token or scan-wallet. |
| 500 | {"error": "Scan failed: invalid address (argument="address", …)"} | Malformed EVM address on check-token — surfaced as a scan failure, message truncated to 200 chars. |
| 400 | {"error": "Unknown action. Use check-token, exists-token, or scan-wallet."} | Bad or missing action value. |
| 405 | {"error": "POST only."} | Any non-POST method other than GET. |
| 429 | {"error": "Rate limit reached (20/hour). Try again later."} | More than 20 requests from your IP in the last hour. |
| 500 | {"error": "Scan failed: …"} | Unexpected failure during a scan (message truncated to 200 chars). |
API keys — free signup
Reserve a key for the upcoming authenticated tier — higher limits and priority scanning. Being upfront: keys are not enforced yet. All endpoints on this page remain open today under the IP rate limits above (20 requests/hour). Your key is shown once at signup, so save it.
Save this key now — it is shown once and will not be displayed again. It will be required for the authenticated tier when it launches; current endpoints remain open with IP rate limits.
v1 storage note: keys are stored server-side in a JSON file (data/api-keys.json). If you lose your key, sign up again from the same email address flow — a new key will be issued.
Try it live
Run a real exists-token probe against the live API from this page — no key required.
// press "Run probe" — the real API response appears here