stupid tokens

A free, chain-agnostic API for EVM token search and bulk USD pricing, with 1h/24h/7d price changes and token metadata. No signup, no API key, CORS enabled.

Token identity is { chainId, address }. Addresses are case-insensitive. Native currencies use the literal address native. Responses identify chains by numeric chainId only.

Endpoints

Endpoint Description
GET /v1 Machine-readable endpoint index.
GET /v1/chains Supported chains with token counts.
GET /v1/search Search by name, symbol, or exact address, ordered by market cap.
GET /v1/tokens/{chainId}/{address} Metadata for one token.
GET /v1/prices Cacheable bulk USD prices, price changes, and metadata for up to 50 tokens.
GET /health Readiness and catalog status.

Search

curl 'https://tokens.stupidtech.net/v1/search?q=usdc&chainId=8453&limit=5'

q is required (2–100 characters) and matches a case-insensitive name or symbol substring (a 2-character query matches prefixes), or an exact contract address. chainId and limit (1–100, default 20) are optional. Results are ordered by stored market cap descending, with unknown caps last, and are edge-cached for up to 60 seconds.

{
  "tokens": [
    {
      "chainId": 8453,
      "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
      "name": "USDC",
      "symbol": "USDC",
      "decimals": 6,
      "imageUrl": "https://assets.coingecko.com/coins/images/6319/large/USDC.png",
      "marketCapUsd": "74000000000",
      "marketCapUpdatedAt": "2026-09-20T18:48:50.540Z",
      "metadataUpdatedAt": "2026-09-20T18:48:50.540Z"
    }
  ]
}

Token Metadata

curl 'https://tokens.stupidtech.net/v1/tokens/1/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'

Returns the metadata object shown above. An unlisted address on an imported chain is checked against its contract's ERC-20 metadata and stored on success; unresolved addresses return HTTP 404.

Bulk Prices

Tokens are comma-separated as chainId:address, and are sorted and deduplicated automatically. Non-canonical requests receive a 308 redirect to the canonical URL.

curl 'https://tokens.stupidtech.net/v1/prices?tokens=1:native,8453:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'

The response is sent with Cache-Control: public, max-age=N, where N is bounded by the next permitted refresh and any change from ok to stale across the batch. It is never longer than five minutes. Stale prices remain available and are cached until a refresh becomes possible, or served with no-store when a refresh is already allowed.

One result per requested token, in canonical order. A valid batch returns HTTP 200 even when individual tokens are unavailable. Each entry includes token metadata (name, symbol, decimals, imageUrl, metadataUpdatedAt) so a separate metadata request is not needed; these are null for a not_found token.

{
  "currency": "usd",
  "prices": [
    {
      "chainId": 1,
      "address": "native",
      "name": "Ether",
      "symbol": "ETH",
      "decimals": 18,
      "imageUrl": "https://coin-images.coingecko.com/coins/images/279/large/ethereum.png",
      "status": "ok",
      "priceUsd": "2629.256297515841",
      "priceUpdatedAt": "2026-09-20T18:53:00.000Z",
      "priceChange": { "h1": "0.42", "h24": "-1.35", "d7": "6.08" },
      "marketCapUsd": null,
      "marketCapUpdatedAt": null,
      "metadataUpdatedAt": "2026-09-20T18:48:50.540Z",
      "fetchedAt": "2026-09-20T18:53:02.000Z",
      "nextRefreshAt": "2026-09-20T18:58:00.000Z"
    }
  ]
}

priceChange holds percent changes over the last hour (h1), day (h24), and week (d7), or null for a window with no value. Changes come from DefiLlama's aggregation and are withheld whenever the entry is not ok.

Status Meaning
ok Price available, source timestamp within 5 minutes.
stale Source timestamp older than 5 minutes or missing; the known price is returned.
not_found Chain is not imported, or the contract could not be resolved on demand.
price_unavailable No usable price from the latest refresh; a previously known price is retained.
upstream_error The refresh failed or was interrupted; a previously known price is retained.
rate_limited A source or shared budget limited the refresh; a previously known price is retained.

Notes

Prices refresh on demand, at most once per token per 5 minutes, shared across callers. priceUsd returns the last known price even when stale or a refresh fails, and is null only when no price is known. Check priceUsd for availability, status for freshness or the latest refresh outcome, and priceUpdatedAt for the quote's source time. A retained price keeps its original priceUpdatedAt and fetchedAt; nextRefreshAt indicates when another attempt is allowed.

Metadata and market caps are stored locally and search never contacts an upstream provider. Exact unlisted contract addresses on imported chains can be discovered from onchain ERC-20 metadata when metadata or prices are requested. Failed lookups have a shared five-minute cooldown; unresolvable contracts return not_found.

Prices and percent price changes come from DefiLlama's aggregation. GeckoTerminal and DexScreener provide liquidity-gated price fallbacks and market caps; GeckoTerminal also supplies an image when the token list does not. Token metadata comes from CoinGecko token lists or, for unlisted contracts, directly from the contract; images use the largest available size (250×250). Native currencies have no list entry, so their logo is resolved from the chain's native coin, falling back to the chain image.

Limits

Up to 50 tokens per price request and 100 search results per request. The service is free and unauthenticated, so please cache responses and avoid tight polling.

github - twitter - stupidtech.net