API v1 reference
Programmatic access to the same forensic engine behind the app: token scans, verdicts, and X account identity checks.
Overview
Base URL: https://ricomaps.fun. Every endpoint speaks JSON. Failed /api/v1/* requests use one envelope: { "success": false, "error": "..." }. The component-health endpoint, GET /api/status, is the exception: its 429 body is { "error": "Too many requests" } and its 500 fallback returns a snapshot-shaped body with overall set to unknown.
Verdict language is SAFE, CAUTION, or DANGER. Risk scores run 0-100 where higher means riskier. Confidence is coverage-driven: it tells you how much of the holder population a scan saw, not how strong the signal is.
CORS: quick-scan and x-account are browser-callable. analyze has no CORS headers by design; call it server side so your key never ships to a browser.
Auth & API keys
Only /api/v1/analyze needs a key. Pass it as apiKey in the JSON body. Keys look like rico_live_..., are shown once at issuance, and reissuing rotates the old key out. Connect a wallet holding $RICO to mint a Free-tier key right here; Pro and Enterprise keys come with a subscription.
What $RICO unlocks
Hold any amount of $RICO- Live X-FeedNew posts from a token's linked X account pop onto the chart in real time.
- Wash RadarLive tape coloring every swap organic / suspected / wash: the real volume behind the chart.
- Cabal RadarKnown-crew, bundle, and sniper supply surfaced on the map before you ape.
- API keySelf-serve key for the public scan API. Wire RicoMaps forensics into your own tools and agents.
- Advanced viewFull forensic breakdown: deployer history, holder PnL, and deeper wallet intel.
Verification is a free wallet signature. It proves you hold $RICO and authorizes no transaction.
Tiers & limits
| Tier | Rate limit | Monthly quota |
|---|---|---|
| Free | 10 requests/min | 1,000 requests/month |
| Pro | 60 requests/min | 50,000 requests/month |
| Enterprise | 300 requests/min | Unlimited |
A tier changes access only. It never changes scan output or scores. Quota months are UTC calendar months.
Quick scan
/api/v1/quick-scanFast token forensics without a key. Scans the top holders (default 50, deployment-tunable) with a shallow funder pass and returns the same SAFE/CAUTION/DANGER verdict the app shows.
Auth: None
Rate limit: 15 requests per minute per IP. 429 responses include a Retry-After header in seconds.
CORS: Open (browser calls allowed).
| Parameter | Type | Required | Description |
|---|---|---|---|
address | string | yes | Token mint address. Wallet addresses are rejected with 400. |
curl -X POST https://ricomaps.fun/api/v1/quick-scan \
-H "Content-Type: application/json" \
-d '{"address": "9wKrtBEsToKenExampLeMintRicoMapsDocsAbcdpump"}'{
"success": true,
"verdict": {
"level": "CAUTION",
"score": 46,
"confidence": "medium",
"topFlags": [
{
"evidenceId": "wash:volume-share",
"label": "38% of volume looks washed",
"severity": "high"
},
{
"evidenceId": "deployer:serial",
"label": "Serial deployer (4 launches)",
"severity": "medium"
}
],
"coverageNote": "Analyzed the top 50 of 3120 holders"
},
"traderRead": {
"action": "wait",
"label": "Wait",
"confidence": "medium",
"score": 55,
"summary": "Mixed signals. Wash volume is elevated and the deployer has prior launches.",
"signals": [
{
"tone": "warn",
"label": "Elevated wash volume",
"weight": 2
}
],
"version": "v2-weighted",
"shadow": false
},
"stats": {
"totalHolders": 3120,
"analyzedHolders": 50,
"analysisIncomplete": false,
"rugScore": {
"score": 42,
"level": "yellow",
"confidence": "medium",
"factors": []
},
"botActivityScore": {
"score": 18,
"level": "green",
"confidence": "medium",
"factors": [],
"metrics": {}
},
"supplyConcentration": {
"top10Pct": 31.2,
"cabalSupplyPct": 6.4,
"holderCoveragePct": 1.6
},
"holderQuality": {
"winners": 9,
"exitLiquidity": 3,
"analyzed": 40
}
},
"data": {
"nodes": [],
"links": []
},
"tokenSecurity": {
"hasFreezeAuthority": false,
"hasMintAuthority": false,
"isMutable": false,
"riskLevel": "low",
"riskFactors": []
},
"tokenMetadata": {
"name": "Example Token",
"symbol": "EXMPL",
"priceUsd": 0.0012,
"marketCap": 118000
},
"deployerInfo": {
"address": "DepLoyerExampLeRicoMapsDocs11111111111111111",
"isSerialDeployer": true,
"pastLaunchCount": 4,
"isRugDev": false
}
}verdict.levelOne of SAFE, CAUTION, or DANGER. verdict.score is 0-100 where higher means riskier.verdict.confidenceCoverage-driven, not signal strength: it reports how much of the holder population the scan saw. coverageNote appears whenever confidence is not high.statsThe full scan stats object (rug score, bot activity, supply concentration, wash, bundles, and more). The example above is trimmed; see the response shapes section for the key fields.dataThe full bubble-map graph: data.nodes and data.links, exactly what the web app renders.traderReadA plain-language read (entry, wait, or avoid) with weighted signals. Treat it as a heuristic summary, not advice.| Status | Body | When |
|---|---|---|
| 400 | {"success": false, "error": "Invalid address"} | The address is not valid base58. |
| 400 | {"success": false, "error": "Address is not a token mint"} | A wallet address was passed instead of a token mint. |
| 429 | {"success": false, "error": "Too many requests"} | Per-IP rate limit hit. Retry after the Retry-After header (seconds). |
| 503 | {"success": false, "error": "Couldn't classify this address right now. Please try again in a moment."} | Upstream asset lookup is temporarily unavailable. |
| 503 | {"success": false, "error": "Token data unavailable. Try again in a moment."} | Upstream token data is temporarily unavailable. |
| 500 | {"success": false, "error": "Scan failed"} | Unexpected server error. |
Recent scans may be served from cache. Use POST /api/v1/analyze for a fresh, deeper read.
Analyze
/api/v1/analyzeDeep cabal analysis with an API key: top 100 holders, 5 funders per holder, identity enrichment.
Auth: API key in the JSON body as apiKey. Mint one above with a wallet holding $RICO, or use a Pro or Enterprise key.
Rate limit: Per key by tier: Free 10/min and 1,000/month; Pro 60/min and 50,000/month; Enterprise 300/min with no monthly cap. 429 on the per-minute limit includes Retry-After. A tier changes access only, never scan output.
CORS: None. Call it server side and keep your key out of browser code.
| Parameter | Type | Required | Description |
|---|---|---|---|
apiKey | string | yes | Your API key. |
mint | string | yes | Token mint address. "address" is accepted as an alias. |
curl -X POST https://ricomaps.fun/api/v1/analyze \
-H "Content-Type: application/json" \
-d '{"apiKey": "rico_live_YOUR_KEY", "mint": "9wKrtBEsToKenExampLeMintRicoMapsDocsAbcdpump"}'{
"success": true,
"nodes": [
{
"id": "FunderExampLeRicoMapsDocs111111111111111111",
"type": "cabal-funder",
"label": "Fund...1111",
"tokenAmount": 0,
"solBalance": 1.42,
"identity": {
"name": null,
"category": null,
"type": null,
"tags": []
},
"metadata": {
"fundedCount": 3,
"threatScore": 85,
"threatLevel": "high"
}
}
],
"links": [
{
"source": "FunderExampLeRicoMapsDocs111111111111111111",
"target": "HoLderExampLeRicoMapsDocs111111111111111111",
"value": 0.5,
"suspicious": true
}
],
"summary": {
"totalHolders": 3120,
"confidence": "medium",
"analyzedHolders": 100,
"holderCoveragePct": 3.2,
"cabalCount": 3,
"riskScore": 34,
"verdict": {
"level": "CAUTION",
"score": 34,
"confidence": "medium",
"topFlags": []
},
"snipersDetected": 5,
"bundleClustersDetected": 2,
"holderQuality": {
"winners": 22,
"exitLiquidity": 6,
"analyzed": 88
},
"coverageNote": "Analyzed the top 100 of 3120 holders"
},
"tokenSecurity": {
"hasFreezeAuthority": false,
"hasMintAuthority": false,
"isMutable": false,
"riskLevel": "low",
"riskFactors": []
},
"tokenMetadata": {
"name": "Example Token",
"symbol": "EXMPL",
"marketCap": 118000
},
"timestamp": "2026-07-01T12:00:00.000Z",
"tier": "free",
"creditsUsed": 10050,
"processingMs": 8421,
"scanProvenance": {
"cacheHit": false,
"scannedAt": 1782926400,
"schemaVersion": 3,
"profile": "deep-api",
"analyzedHolders": 100
}
}summary.riskScore / summary.verdictThe canonical SAFE, CAUTION, or DANGER verdict and its 0-100 risk score. riskScore is the same value as verdict.score.summary.confidenceCoverage measures: confidence and holderCoveragePct report analyzed holders over the true holder population. coverageNote appears whenever confidence is not high.nodes / linksThe graph the bubble map renders. metadata fields vary by node type (funding counts, threat scores, sniper timing, and more).creditsUsedAn informational estimate of upstream data cost for the scan. Your monthly quota counts requests, not credits.scanProvenanceCache status, scan time, engine schema, scan profile, and analyzed-holder depth for cross-surface comparisons.| Status | Body | When |
|---|---|---|
| 401 | {"success": false, "error": "Missing apiKey"} | No apiKey in the JSON body. |
| 403 | {"success": false, "error": "Invalid or revoked API key"} | The key is unknown or has been rotated away. |
| 429 | {"success": false, "error": "Rate limit exceeded"} | Per-minute tier limit hit. Retry after the Retry-After header (seconds). |
| 429 | {"success": false, "error": "Monthly quota exceeded for Free tier"} | The tier's monthly quota (UTC calendar month) is used up. |
| 400 | {"success": false, "error": "Invalid or missing token mint. Pass it as \"mint\" (or \"address\") in the JSON body."} | The mint is missing or not valid base58. |
| 503 | {"success": false, "error": "Token data unavailable. Try again in a moment."} | Upstream token data is temporarily unavailable. |
| 500 | {"success": false, "error": "Analysis failed"} | Unexpected server error. |
X account identity
/api/v1/x-accountResolve an X handle to its cross-time identity: current handle, prior handles seen on the same immutable user id, and linked token contract addresses.
Auth: None
Rate limit: No published limit. Fair use; heavy callers should cache responses.
CORS: Open (browser calls allowed).
| Parameter | Type | Required | Description |
|---|---|---|---|
handle | string (query) | yes | X username, with or without the @. |
curl "https://ricomaps.fun/api/v1/x-account?handle=example_handle"
{
"success": true,
"tracked": true,
"identity": {
"userId": "1234567890123456789",
"currentUsername": "example_handle",
"priorUsernames": [
"old_handle"
],
"isRecycled": true,
"followers": 5120,
"firstSeen": 1735689600,
"lastSeen": 1751328000,
"linkedMints": [
"9wKrtBEsToKenExampLeMintRicoMapsDocsAbcdpump"
]
},
"timestamp": "2026-07-01T12:00:00.000Z"
}{
"success": true,
"tracked": false,
"handle": "example_handle",
"message": "Not in the tracker yet. Queued for resolution. Check back shortly."
}identity.isRecycledMeans more than one distinct handle has been observed on the same X user id. That is evidence of a renamed or reused account, not proof of bad intent.tracked: falseAn unknown handle is queued for the tracker automatically and usually resolves on a later call.identity.linkedMintsToken contract addresses this identity has been associated with in scans.| Status | Body | When |
|---|---|---|
| 400 | {"success": false, "error": "Provide a valid X handle: ?handle=username"} | The handle query parameter is missing or invalid. |
API status
/api/v1/statusLiveness stub for uptime checks: confirms the API is serving and reports the API version.
Auth: None
Rate limit: None
curl https://ricomaps.fun/api/v1/status
{
"status": "ok",
"version": "1.0.0",
"timestamp": "2026-07-01T12:00:00.000Z"
}versionThe v1 API version string.responseAdditional health fields may be added over time; treat unknown fields as informational. For per-component health, use GET /api/status below.Component health
/api/statusPer-component health for the platform: app, database, Solana RPC, the always-on worker, live streams, and the bots. No key required.
Auth: None (no key required)
Rate limit: 30 requests per minute per IP. The snapshot behind it is cached for about 30 seconds, so faster polling returns the same data.
curl https://ricomaps.fun/api/status
{
"overall": "degraded",
"components": [
{
"component": "app",
"label": "Web app and API",
"status": "operational",
"checkedAt": "2026-07-01T12:00:00.000Z"
},
{
"component": "database",
"label": "Database",
"status": "operational",
"checkedAt": "2026-07-01T12:00:00.000Z"
},
{
"component": "solana-rpc",
"label": "Solana data",
"status": "operational",
"checkedAt": "2026-07-01T12:00:00.000Z"
},
{
"component": "worker",
"label": "Streaming worker",
"status": "operational",
"checkedAt": "2026-07-01T12:00:00.000Z"
},
{
"component": "live-streams",
"label": "Live streams (bubble map, wash radar)",
"status": "operational",
"checkedAt": "2026-07-01T12:00:00.000Z"
},
{
"component": "x-bot",
"label": "X reply bot",
"status": "operational",
"checkedAt": "2026-07-01T12:00:00.000Z"
},
{
"component": "x-stream",
"label": "X account tracking",
"status": "down",
"detail": "Stream disconnected",
"checkedAt": "2026-07-01T12:00:00.000Z"
},
{
"component": "x-feed",
"label": "Extension X feed",
"status": "operational",
"checkedAt": "2026-07-01T12:00:00.000Z"
},
{
"component": "discord",
"label": "Discord bot",
"status": "unknown",
"detail": "Not configured",
"checkedAt": "2026-07-01T12:00:00.000Z"
}
],
"generatedAt": "2026-07-01T12:00:00.000Z",
"cacheTtlSeconds": 30
}overallRoll-up banner. Only a core component (app, database, solana-rpc, worker) going down reads as a full outage; a non-core outage, like the x-stream row in the example, rolls up as degraded.components[].componentOne of: app, database, solana-rpc, worker, live-streams, x-bot, x-stream, x-feed, discord. label is the display name.components[].statusOne of: operational, degraded, down, unknown. "unknown" means the check could not reach the component, not that it is down.components[].detailOptional short context for a non-operational status.components[].checkedAtISO timestamp of the underlying check. cacheTtlSeconds states the snapshot cache window.responseThe response may gain additional fields over time; treat unknown fields as informational.| Status | Body | When |
|---|---|---|
| 429 | {"error": "Too many requests"} | Per-IP rate limit hit. Retry after the Retry-After header (seconds). |
Errors
| Status | Meaning |
|---|---|
| 400 | Invalid input: malformed address, missing mint, or a wallet passed where a token mint is required. |
| 401 | Missing apiKey in the request body (analyze only). |
| 403 | Invalid or revoked API key (analyze only). |
| 429 | Rate limit or monthly quota hit. Per-minute 429s include a Retry-After header in seconds. |
| 500 | Unexpected server error. Safe to retry after a short wait. |
| 503 | Upstream token data temporarily unavailable. Retry in a moment. |
Response shapes
Verdict
levelSAFE, CAUTION, or DANGER. The same canonical verdict shown in the app and bots.score0-100, higher means riskier.confidencehigh, medium, or low. Driven by holder coverage, not by the score.topFlagsUp to 5 ranked flags, each with a label and a severity of critical, high, medium, or low.coverageNotePresent when confidence is not high; states how many holders the scan actually saw.RugScore
score0-100, higher means riskier.levelgreen, yellow, or red traffic light.confidencehigh, medium, or low, driven by holder coverage.factorsContributing factors, sorted by points, each with a label and severity.SupplyConcentration (coverage fields)
holderCoveragePctAnalyzed holders as a percent of the true holder population. Absent when the true total is unknown.analyzedSupplyPctPercent of supply the analyzed holders represent.top10Pct / top25PctSupply share held by the top 10 and top 25 real holders.cabalSupplyPctSupply share held by shared-funder cluster members.TraderRead
actionentry, wait, or avoid, with a matching label.confidence / score / summaryHeuristic confidence, a 0-100 score, and a plain-language summary.signalsWeighted signals, each with a tone of good, warn, or bad.version / shadowModel version identifier and whether the read came from a shadow model.DeployerInfo
address / sourceDeployer wallet and how it was attributed (mint-tx-signer, creator, or update-authority).pastLaunchCount / isSerialDeployerPrior token launches by this address; null means the lookup was skipped or failed.priorRugCount / priorRugEvidence / isRugDevCross-token reputation context. Aggregate legacy counts are unverified and do not affect the verdict unless an itemized attribution receipt exists.stillHolds / heldSupplyPctWhether the deployer still holds within analyzed coverage; null means unknown, not sold.