Skip to main content
How fast a response is, how old its data can be, and what a request costs in Solana RPC calls. The numbers in the measured table come from pnpm bench:api; the guarantees above it come from the configuration and the code, not from a measurement.

Freshness guarantees

  • Snapshot TTL: 120 s by default. A wallet’s snapshot is “fresh” while freshness.age_seconds ≤ freshness.max_age_seconds, which is the request’s freshness_seconds (0…86,400, default 120, SNAPSHOT_FRESHNESS_S). A fresh snapshot is served as is.
  • Stale while refreshing (max 10 minutes). A snapshot older than the freshness target but at most 10 minutes old (MAX_STALE_SERVE_S) is served at once (200); anything older is never served and the request returns 202 with a fresh scan. A served stale snapshot carries freshness.stale: true, coverage.status: "stale", refreshing: true and a refresh_job_id, while one bounded refresh scan runs in the background. A stale snapshot never has a total_value_usd (coverage_incomplete). Request again a few seconds later for the new snapshot. With no snapshot at all, the first request returns 202 and a job to poll (the async flow).
  • ?wait=N long-poll (0…10 s). On a cold or stale request the API waits up to N seconds for the scan it just started and returns the fresh 200 if it lands in time (else the usual 202 or stale 200). The wait reads only the job status from storage, never the chain, so it adds no RPC cost. ?wait=8 covers most cold scans (see below).
  • freshness_seconds lets you trade freshness for speed: a larger value accepts older snapshots and avoids scans; 0 always triggers a refresh (and can hit the cold-scan limit, see Rate limits).
  • Prices refresh every 2 minutes (a scheduled job), not per request. Each leg shows price_as_of. A built-in on-chain price stays priced for up to 300 s and a TokenPrices price for up to 900 s; older prices are stale (shown, counted in no total) up to 24 h, and not served after that. LST redemption rates are stale from an epoch lag of 3.
  • Lending interest is valued as of each reserve’s last on-chain refresh (the leg’s context.as_of_slot), not projected forward; an old reserve sets the interest_stale flag.
  • Slots. observed_slots is the slot range of every RPC read in the scan. snapshot_consistency: "multi_slot" is normal: a scan’s reads are not one atomic read, so they can span a few slots.

RPC cost per request

  • Cached requests make 0 RPC calls. A request answered from a snapshot is read from the database only. A stale or missing snapshot also triggers one background scan for the wallet (deduplicated: concurrent requests share it).
  • A cold or refresh scan reads the wallet’s token accounts (SPL Token and Token-2022), its native SOL balance and each supported protocol’s accounts. It is capped at 40 RPC HTTP requests per scan (SCAN_MAX_REQUESTS, a batch counts once, retries included) and 20 s; a protocol that would exceed its own share is reported as an error, never as an empty result. The measured table shows what scans actually use.
  • Prices are never fetched per request. They come from the 2-minute refresh; scans read the stored prices.

Measured latency

Local measurement, 2026-11-14, not production. pnpm bench:api against wrangler dev on one laptop (local D1, live mainnet RPC through the project’s keyed endpoint), the 7 sample wallets of the viewer. Production latency adds the network path to Cloudflare and can differ either way; re-measured after each deploy. ?wait=8 spot check (local, 2026-11-14, not production): two never-scanned sample wallets each returned 200 in one call, in 4.7 s and 4.0 s (live mainnet RPC through the keyed endpoint, local D1). Consistent with the cold-scan p90 above, ?wait=8 returns the snapshot directly for most cold wallets; slower scans fall back to 202. The ages reflect this short local run (scans a few seconds to a minute old, one price refresh at the start). In production the price refresh runs every 2 minutes, so a served price is normally under about 2 minutes old plus chain finality, and a served snapshot is at most freshness_seconds old unless it is marked stale.