Where to read it
Pair fields describe the pair’s token of interest (the one named by
quoteToken), not the pool itself.
A null risk, or a null field inside it, means Codex has no assessment. Treat it as unknown, never as safe.
Verdicts
SCAM, VERIFIED and VERIFIED_CONTESTED come from proof or a human decision, not the score, so their score is usually null. A high score alone never produces SCAM.
Score
Each reason adds points, and a 15-point bonus applies when reasons from three or more families fire together. The total is capped at 100. The score is a weighted heuristic, not a probability: 70 does not mean a 70% chance of a scam. Not every reason adds points. Authority reasons (AUTH_*), such as a Solana mint or freeze authority, report a capability without scoring it, so you can’t rebuild the score by counting reasons.
Coverage
Coverage says how much contract analysis (simulated buys and sells, static checks) the verdict rests on. It doesn’t say what the analysis concluded.
New values can be added to this enum. Treat unknown values as
NOT_ANALYZED.
A NEUTRAL token with NOT_ANALYZED coverage has had no honeypot or tax check. Show that differently from NEUTRAL + ANALYZED.
Reasons
RiskReasonCode values are grouped by prefix:
New codes are added over time. Handle unknown codes gracefully, and don’t treat an empty list as proof the token is clean.
Freshness
Codex re-assesses tokens in the background as new data arrives; queries read the latest stored result.flaggedAt is the Unix time the assessment last changed. A re-check that reaches the same result doesn’t update it.
A new token usually gets its first assessment within a few minutes of its first pool. Until then risk is null. Early assessments often have NOT_ANALYZED coverage, and the contract analysis fills in later. There is no push when an assessment lands, so poll tokens if you need it.
Examples
Read one token
Hide risky tokens from a list
Find likely honeypots among pairs
filterTokens and filterPairs both accept riskVerdicts, riskCoverages, riskReasons, riskScore and riskFlaggedAt filters, and both can rank by riskScore or riskFlaggedAt.
Get the actual tax numbers
risk.buyTax and risk.sellTax return the tax the token charges on each side of a trade, measured by the token’s latest decisive contract analysis. The verdict and risk reasons reflect the analysis available at the last risk assessment. On pairs, riskBuyTax and riskSellTax give the tax of the pair’s token of interest.
Each side is measured on its own simulated trade: the buy tax on the buy, the sell tax on the sell. Pool fees, Uniswap V4 hook fees and launchpad platform fees are not tax and are left out. A token with a 9% tax on a launchpad that also charges a 1% fee reads buyTax: 0.09 and sellTax: 0.09. A tax-free token in a pool with a 1% hook fee reads 0 where Codex can measure that side.
- They are fractions as numbers:
0.05is 5%. nullmeans no decisive analysis could measure that side on its own. Treat it as unknown, not as 0%. On some venues only one side can be separated from the venue’s fees, for example the buy on Uniswap V3 and V4 pools, so the other side isnull.- A honeypot returns
sellTax: nullbecause its test sale failed, so no sell tax was measured. ItsbuyTaxis usually set. Read the verdict and reasons for the honeypot itself. - The tax can be newer than
verdictand risk reasons such asTAX_SELL_HIGH. A new analysis shows up at once, while the verdict and reasons update on the token’s next assessment. - You can’t filter or rank by tax. To find taxed tokens, filter on
riskReasons: [TAX_SELL_HIGH]or[TAX_BUY_HIGH], which fire at 10% or more.
extensions.token2022.transferFeeConfig on TokenExtensions exposes the configured fee schedules separately from measured risk taxes. A known configured fee can coexist with risk.buyTax: null and risk.sellTax: null when no decisive simulation established the per-side measurements. The effective fee depends on the active epoch, transfer amount, maximum fee and rounding. Plain SPL tokens have no transfer-fee configuration, so their measured risk taxes remain null.
How this relates to isScam and potentialScam
Risk filters are opt-in. They don’t change the existing scam filters:
isScamis a manual label on a small set of tokens.truemeans a moderator marked the token a scam (LABEL_MANUAL_SCAM),falsemeans a moderator verified it (VERIFIED), andnull, which covers almost every token, means it hasn’t been reviewed. Read it fromtoken.isScam. The result-levelisScamonfilterTokensresults is always null.filterTokenshides tokens withisScam: trueby default. AutomatedSCAMverdicts are not hidden unless you filter onriskVerdicts. PassincludeScams: trueinsidefiltersto include them, which you’ll need when filtering forSCAMverdicts.isVerified: truekeeps only tokens withisScam: false. It isn’t the same asriskVerdicts: [VERIFIED].potentialScamandpotentialScamReasonsare an older automated flag. They’re still available, butriskis the more complete signal.
Reading potentialScamReasons
- The reasons are recomputed from the token’s current state each time it is re-scored. A reason drops off as soon as its condition stops holding, and there is no timestamp for when a reason fired.
- An empty list means nothing fired. It is also returned when a check was skipped for missing data, so
[]is not proof the token is clean. SniperConcentrationfires when wallets that bought in the first 5 seconds currently hold at least 50% of the supply. It is only computed where sniper stats exist (launchpad tokens).MinimumLiquidityfires when the token’sliquidityis $10 or less.LiquidityUnknownmeans liquidity could not be read, so the liquidity checks did not run.- See
PotentialScamReasonfor every value.