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’sfreshness_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 returns202with a fresh scan. A served stale snapshot carriesfreshness.stale: true,coverage.status: "stale",refreshing: trueand arefresh_job_id, while one bounded refresh scan runs in the background. A stale snapshot never has atotal_value_usd(coverage_incomplete). Request again a few seconds later for the new snapshot. With no snapshot at all, the first request returns202and a job to poll (the async flow). ?wait=Nlong-poll (0…10 s). On a cold or stale request the API waits up toNseconds for the scan it just started and returns the fresh200if it lands in time (else the usual202or stale200). The wait reads only the job status from storage, never the chain, so it adds no RPC cost.?wait=8covers most cold scans (see below).freshness_secondslets you trade freshness for speed: a larger value accepts older snapshots and avoids scans;0always 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 stayspricedfor up to 300 s and a TokenPrices price for up to 900 s; older prices arestale(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 theinterest_staleflag. - Slots.
observed_slotsis 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.