Skip to content
Docs
Get API Access
Browse the Documentation

Build a Watchlist

Price up to 100 assets in one request, poll on the rate budget, and render changes correctly.

A watchlist is a set of asset IDs and one request that prices them all. The batch endpoints take up to 100 distinct IDs, so a list of any reasonable size costs one request a minute.

1. Keep a List of Asset IDs

Store asset IDs, not symbols. Resolve a symbol once with GET /v1/assets/map (see Track an asset), or let users pick from the ranked listing:

curl -s "https://api.cantoncap.cc/v1/assets/listings/latest?convert=USD&sort=fdv&limit=100" \
  -H "X-API-Key: $CANTONCAP_API_KEY"

Each listing row has the asset_id, name, symbol, its rank over the whole listing and the same quotes as the quote endpoints.

2. Price the Whole List in One Request

GET /v1/assets/quotes/latest takes the IDs comma-separated, and up to three conversion currencies. Ask for only the change windows you show with price_change_periods.

curl -s "https://api.cantoncap.cc/v1/assets/quotes/latest?ids=ast_515c3eaa72bd4a8b9403297879d78ef6,ast_2d9c41e0b7a64f1e9c3b5a8d7e6f1c20,ast_7a1f0c9e3d5b4e2a8c6f1b0d9e7a3c54&convert=USD&price_change_periods=24h,7d" \
  -H "X-API-Key: $CANTONCAP_API_KEY"
Distinct IDs
A batch with a repeated ID is refused with 400 invalid_request; de-duplicate first, as above. IDs the API cannot answer for (unknown, unpublished, or without a quote in that currency) are left out of data rather than failing the request.

3. Render It Correctly

  • Format prices from the decimal strings, without converting to floats. See Decimals and precision.
  • price_changes_pct values are percentage points: "2.31" is +2.31%. A null window has no data; show a dash.
  • Show each row's age from last_updated_at, and mark rows older than you accept rather than hiding the age.
  • An asset missing from the response is unpriced right now, not zero.

4. Refresh on a Budget

Prices are recalculated about once a minute. One batch request a minute keeps a watchlist of up to 100 assets current and uses a small part of even the Developer plan's budget. Serve your users from your own cache and refresh it on a timer, so a thousand viewers still cost one request a minute.

let cache = { quotes: new Map(), at: 0 };

async function refresh(ids) {
  cache = { quotes: await priceWatchlist(ids), at: Date.now() };
}

await refresh(WATCHLIST);
setInterval(() => refresh(WATCHLIST).catch(console.error), 60_000);

// Your own endpoint answers from the cache, never from the API directly.
export function watchlistHandler() {
  return Object.fromEntries(cache.quotes);
}

For second-by-second updates, subscribe to asset_quote:<asset_id> for each asset on one WebSocket connection instead of polling. See Streaming.

Esc
navigateopenEscclose