docs › Data sources and rate limits
Data sources and rate limits
Every source the app reads, what it takes from each, the keyless limits, and what a free key adds.
dexterm must stay usable forever with no paid data and no shipped keys: Node, a terminal and your own Claude login are enough. Every data need has a keyless path on a public API and degrades honestly; a free key you make yourself only raises speed or limits or unlocks depth, it never gates a feature. Because every source meters by your IP or key, each user has their own quota and there is no shared server in the middle.
Sources#
| data need | keyless source | free-key upgrade | without it |
|---|---|---|---|
| screener pool | DexScreener + Jupiter Tokens v2 | Jupiter free key: 1 rps instead of 0.5 | fully keyless |
| token market | DexScreener + Jupiter | Jupiter free key: higher rate | fully keyless |
| candles and chart | GeckoTerminal | none | chart unavailable (rare) |
| trade tape and buy/sell flow | GeckoTerminal tape; DexScreener rolling windows for 5m to 24h | none | tape unavailable |
| mint and freeze authority | public Solana RPC getAccountInfo + Jupiter + GoPlus | any free RPC: faster, fewer 429s | Jupiter and GoPlus still answer |
| top holders | Jupiter aggregate: holder count + top-10 % | any free RPC key (Helius, Alchemy, QuickNode, Ankr): the ranked top-20 list with owners | count and concentration shown; the ranked list says "needs a free RPC key" |
| security checks | RugCheck + GoPlus | none | one may be unavailable, the other covers |
| new pairs | PumpPortal subscribeNewToken + subscribeMigration, Jupiter recent poll, RugCheck new_tokens | Helius: per-curve bonding % | rows from the poll; bonding is a create-time estimate |
| watchlist prices | DexScreener + Jupiter, persisted in SQLite | Jupiter free key: higher rate | fully keyless |
| fast-lane live price | public RPC WebSocket accountSubscribe on the pump.fun bonding curve, price computed on-chain | free Helius key: lower latency, higher limits (used first) | the polled price (POLL badge) |
| paper quotes | Jupiter swap/v1/quote (quote only; no build, no execute) | Jupiter free key: lower latency | fully keyless |
| product vetting | the token's own site, RDAP, the GitHub API | none | a claim stays unverifiable |
| trending board | Jupiter trending and organic-score lists, GeckoTerminal trending pools, DexScreener top boosts (counted against a coin), CoinGecko trending (macro) | none | a failing venue degrades only itself |
| news | publishers' official RSS: CoinDesk, Cointelegraph, The Block, Decrypt | none | the board works without it |
| social posts (X, Telegram) | none keyless: dexterm has no X API client and does not scrape | Login with X is on the roadmap | the live SOCIAL panel shows on-chain rows only |
| dev history, snipers, bundles | none keyless (wallet history is not public without an indexer) | Helius | columns dash + needs Helius |
The ranked holder list is the one real keyless gap: getTokenLargestAccounts is throttled or blocked on every keyless endpoint we probed, and Birdeye and Solscan need keys.
Rate limits and pacing#
One token bucket per host with the documented limit as the ceiling and a safety factor of 0.7; over-budget requests queue and the column header shows ⌛ instead of blocking. Identical in-flight requests share one promise. The chart the user is waiting on takes a high-priority slot that background work (tape, prefetch, refresh) can never consume.
| bucket | ceiling (req/min) | burst | reserved for the chart | basis |
|---|---|---|---|---|
dexscreener | 300 (×0.7 = 210 used) | 1 | — | docs.dexscreener.com/api/reference (OpenAPI), SPEC §3.1 S1 |
dexscreener-slow | 60 (×0.7 = 42 used) | 1 | — | docs.dexscreener.com/api/reference, SPEC §3.1 S1 |
jupiter | 30 (×0.7 = 21 used) | 1 | — | developers.jup.ag/docs/portal/rate-limits, SPEC §3.1 S2/S3; observed 5 per short window |
geckoterminal | 10 (×0.7 = 7 used) | 2 | 1 | docs/geckoterminal-api/api-page.md, SPEC §3.1 S4 |
rugcheck | 10 (×0.7 = 7 used) | 1 | — | undocumented; conservative guess |
solana-rpc | 30 (×0.7 = 21 used) | 1 | — | public RPC (docs: 100/10 s per IP, 40/10 s per method); conservative, no burst |
pumpfun | 6 (×0.7 = 4 used) | 1 | — | undocumented frontend API; conservative guess |
helius | 600 (×0.7 = 420 used) | 5 | — | Helius Free plan 10 rps RPC (docs/helius/pricing.md); credits metered separately |
goplus | 30 (×0.7 = 21 used) | 2 | — | undocumented keyless tier; inventory §5 starting point |
coingecko | 10 (×0.7 = 7 used) | 1 | — | CoinGecko public API keyless 10/min (INTEGRATIONS-DESIGN §4, measured 2026-10-09) |
news-rss | 10 (×0.7 = 7 used) | 4 | — | polite RSS polling (INTEGRATIONS-DESIGN §4: every 10 min, cached) |
Refresh cadence, keyless: screener table 10 s (one DexScreener batch per 30 rows), token screen 10 s, watchlist 0 s, positions 10 s, new pairs push plus a 15 s Jupiter poll and a 30 s RugCheck poll, PAPER quote 5 s while editing. The fast lane adds zero HTTP requests: it is push, capped at 24 simultaneous subscriptions (the open token, your watchlist, a few fresh launches); tokens past the cap stay on the polling lane, never dropped.
Cache#
A persistent SQLite cache (node:sqlite, one table, namespaced) makes a restart or a reopen instant and cheap. The analyst's MCP server reads the same file, so a warm dossier needs no network.
| entity | ttl |
|---|---|
| pairs (market rows) | 10 s |
| token enrichment | 1 min |
| SOL price | 30 s |
| the open candle | 30 s |
| closed candles | 1 h |
| holders | 1 min |
| audit / authorities | 10 min |
| RugCheck | 10 min |
| socials | 1 h |
| dev history | 24 h |
| feed lists | 15 s |
The last rows shown per preset are also snapshotted so a launch paints instantly, marked cached Nm old · refreshing.
Health registry#
Every source goes through a health registry: three consecutive failures or two 429s in a minute mark it degraded for a backoff window (30 s, doubling to 10 min). A panel whose source is down shows unavailable: <reason> or needs key, the header turns ◐ degraded: <source>, and the analyst's tool list is built from the healthy sources each session. A screen with no data says why instead of hanging: connecting to the live feed…, offline — can't reach the data feed, rate-limited — backing off. Press r to retry. Nothing fabricates a number.
The Helius credit meter#
Helius Free is 1M credits a month, budgeted as 33,333 a day. Each request is charged (1 credit for standard RPC methods, 10 for DAS-class); the header shows ◐ helius credits N% from 50% of the day, and at 90%, or at the per-run cap (--max-credits, default 5000), Helius switches off for the run and the keyless sources take over. Day totals persist in the SQLite file, so a restart keeps counting.
Request budget meter#
Every request is counted per source for the session and for the day (persisted), so usage is visible with --verbose and in the header. Optional soft daily caps can bound a source.