Skip to main content
The Risk Score is a number between 0.0 and 10.0 that summarizes how rug-pull-y a token looks based on on-chain evidence. It’s glass-box: the full list of signals that fired, with their weights and individual contributions, is in the API response. You can re-compute the score yourself.

Formula

score = min(10.0, sum(signal.contribution for signal in fired_signals) * 10 / 5000)
The divisor 5000 is the calibration target — a raw contribution sum of 5,000 normalizes to 10.0. Real-world rug setups often reach raw sums of 20,000+; they all clip to 10.0.

Level bands

The level field bands the numeric score into four categories for UI:
levelScore range
safe0.0 ≤ score < 2.5
caution2.5 ≤ score < 5.0
warning5.0 ≤ score < 7.5
danger7.5 ≤ score ≤ 10.0

Status

statusMeaning
readyAll 12 signal inputs available; score is fully computed.
partial_dataAt least one signal couldn’t be evaluated (the underlying data isn’t onboarded yet). The score still reflects the signals that were available; missing_signals[] lists which weren’t ready.
no_dataNone of the signal inputs are available — typically because the mint isn’t yet in tracked_mints. score is null.
A partial_data score is a true lower bound — every signal in missing_signals[] is one that could have added to the score had its input been available.

Signals

Twelve signals across six categories. “Graded” signals scale their contribution with the magnitude of the underlying value (e.g. dev_held_high contributes more when the creator holds 30% vs 6%).

Holder concentration (graded)

codeTriggerWeightNotes
single_holder_50pcttop holder owns > 50% of supply7000Graded across 50–100%. Pool wallets are excluded from the “top holder” calculation.
top10_hightop-10 sum > 50% of supply5000Graded across 50–70%. Pool-excluded.
top10_very_hightop-10 sum > 70% of supply2500Graded across 70–100%. Stacks on top of top10_high.

LP + authority (boolean)

codeTriggerWeightNotes
lp_not_burntLP tokens not burnt/locked4000Returns None (signal sits in missing_signals) until the LP-lock state has been checked — avoids a false-positive during the warm-up window. Lock state is written in real time from on-chain burn/lock events and refined by a polling detector; the /tokens/{mint}/audit lock object surfaces the mechanism (burned vs locked) and a verified confidence flag. Bonding-curve venues (PumpFun, Meteora DBC) have no fungible LP, so this signal stays None there.
mint_authority_activemint authority not revoked2500Empty or null authority counts as revoked.
freeze_authority_activefreeze authority not revoked7500The heaviest single signal in the catalog — token holders can be frozen out of their positions.

Sniper concentration (graded)

codeTriggerWeightNotes
snipers_count_high≥ 10 wallets bought within first 30 slots3500Graded by count (10 → 0.1, 50+ → 1.0). A fire never yields 0 contribution.
snipers_pct_highsnipers hold > 30% of supply7500Graded across 30–50%.

Insider concentration (graded)

codeTriggerWeightNotes
insiders_pct_highinsiders hold > 30% of supply5000Graded across 30–50%. An insider is a holder who never appears as a swapper on-DEX.

Creator behavior (graded)

codeTriggerWeightNotes
dev_held_highcreator holds > 5% of supply3000Graded across 5–30%. Only fires when creator_source is non-empty — i.e. we know who the creator is.
dev_held_very_highcreator holds > 30% of supply5000Graded across 30–100%. Stacks on top of dev_held_high.

Metadata (boolean)

codeTriggerWeightNotes
no_socialsno twitter / telegram / website2000All three fields must be empty or null.
Total maximum raw contribution: 53,500 (every signal triggered at full strength).

Why this design

Glass-box so you can audit our judgment. If you disagree with a weight or threshold, you can subtract that signal’s contribution from the raw score and renormalize. The value field on each signal is the concrete measurement, not an opaque score — verifiable against the underlying on-chain data. Stacking thresholds (e.g. top10_high + top10_very_high) compound penalties for severe concentration without making any single threshold a cliff. Graded contribution keeps small differences in the underlying data from causing large score jumps. A token at 51% top-10 concentration doesn’t suddenly leap past one at 49%. Phase 0 strict precedence for dev_held_*: we only fire these when tokens.creator_source is populated. We never fall back to “largest holder is probably the creator” — that produced false positives in pre-Phase-0 testing on tokens where the largest holder was a CEX hot wallet or the AMM pool itself.

Re-computing the score

The response is glass-box on purpose. If you want to weight signals differently:
# Subtract signals you don't care about
penalty = sum(s["contribution"] for s in signals if s["code"] != "no_socials")
# Renormalize against your own divisor
my_score = min(10.0, penalty * 10 / 5000)
Or if you want a fully custom model: walk signals[*].value, ignore the weight/contribution, and feed the raw values into whatever you’d prefer.

See also

  • GET /tokens/{mint}/risk — the dedicated risk endpoint
  • GET /tokens/{mint}/intel — slim risk summary embedded in the dashboard payload
  • Quotas & errors/risk is Free-tier rate-limited; no per-endpoint cap