Solana Tracker LogoSolana Tracker
Swap
Developers
⌘K
Affiliate
All Resources
Solana Token Price API: Pools, Batches and History
Data APITypeScriptMay 30, 202611 min readUpdated October 7, 2026Solana Tracker

Solana Token Price API: Pools, Batches and History

Use the Solana token price API to get per-pool prices, batch up to 100 mints and read price history in TypeScript, with retries and production pitfalls.

  • prices,
  • data-api,
  • rest,
  • typescript,
  • tokens
Solana Data API›Raptor Swap API›

The Solana Tracker solana token price api gives you three REST views of a token's price: getPrice for one snapshot, getMultiplePrices for up to 100 mints in one call, and getTokenInfo for the price and liquidity of every pool the token trades in. Use them for watchlists, portfolio marks and token pages. When the number has to move on screen, use the price WebSocket. When you are about to trade, ask Raptor for a quote.

A price is an observation of a market, not a promise about execution. Most production bugs in this area come from treating it as one, so the rest of this guide covers which call to make, what comes back, and how the numbers mislead you.

Which Solana token price API call to use

Every call below runs against the Solana Data API with an x-api-key header. The SDK method names are from @solana-tracker/data-api 0.5.0.

NeedSDK methodEndpointReturns
Current price of one tokengetPrice(mint, priceChanges?)GET /priceOne snapshot: price, liquidity, market cap, lastUpdated
Prices for a watchlistgetMultiplePrices(mints, priceChanges?)GET /price/multiObject keyed by mint, at most 100 mints per call
Price and liquidity per poolgetTokenInfo(mint)GET /tokens/{token}Token metadata plus a pools array
Coarse history pointsgetPriceHistory(mint)GET /price/historycurrent plus 3d, 5d, 7d, 14d, 30d values
Price at a momentgetPriceAtTimestamp(mint, unixSeconds)GET /price/history/timestampPrice and the pool it came from
Low and high in a windowgetPriceRange(mint, from, to)GET /price/history/rangeLowest and highest price with times
Candles for a chartgetChartData(params)GET /chart/{token}OHLCV series (see the OHLCV guide)

postPrice and postMultiplePrices are POST variants of the same lookups. Use them when a long list of mints would make the query string unwieldy. The 100-mint limit still applies: the SDK throws a ValidationError before sending a larger batch.

Always identify tokens by mint address. Symbols are not unique, and anyone can launch a token called USDC.

REST snapshot, price WebSocket or swap quote

Pricing touches three different products, and each answers a different question.

REST price endpointsDatastream price roomsRaptor swap quote
Question it answersWhat is the price now?How is the price moving?What will I receive for this trade size?
DeliveryRequest and responsePush over WebSocketRequest and response
Accounts for trade size and routeNoNoYes
Typical useWatchlists, portfolio marks, token pages, startup stateLive tickers, charts, alertsSwap buttons, bots before sending a transaction
AccessData API key, any planPremium plan or higherSee the Raptor Swap API page

For a screen that stays open, start from a REST snapshot and then subscribe to a price room; the Solana price WebSocket guide shows how to combine the two around reconnects. Polling getPrice every second for a live ticker spends one request per call and still lags a push feed.

For anything that ends in a transaction, request a quote from Raptor with the input mint, output mint and amount in base units; the Solana swap API guide walks the quote, build, sign and send flow. A quote reflects the route, pool depth and your trade size; a spot price reflects none of them. A token showing $0.0042 on a $3,000 pool will not fill a $5,000 buy anywhere near that price.

Response shapes

These shapes are trimmed from the SDK 0.5.0 type definitions. Fields not shown exist but are not needed here.

getPrice(mint, true) returns a PriceData object. lastUpdated is in milliseconds. priceChanges is only present when you pass true.

{
  "price": 150.12,
  "priceQuote": 1,
  "liquidity": 29450616,
  "marketCap": 91000000000,
  "lastUpdated": 1791380000000,
  "priceChanges": {
    "1h": { "priceChangePercentage": 0.42 },
    "24h": { "priceChangePercentage": -2.31 }
  }
}

getMultiplePrices returns the same object per mint, keyed by mint address. A mint with no price can be missing from the response, so join by key and never by array position.

{
  "So11111111111111111111111111111111111111112": { "price": 150.12, "liquidity": 29450616, "marketCap": 91000000000, "lastUpdated": 1791380000000 },
  "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": { "price": 1.0, "liquidity": 12400000, "marketCap": 8900000000, "lastUpdated": 1791379995000 }
}

getTokenInfo returns token, pools, events, risk and transaction counts. Each pool carries its own price and liquidity in USD and in the quote token:

interface PoolInfo {
  poolId: string;
  market: string;            // e.g. "raydium-clmm", "orca", "pumpfun-amm"
  quoteToken: string;        // mint of the quote side
  price: { usd: number; quote: number };
  liquidity: { usd: number; quote: number };
  marketCap: { usd: number; quote: number };
  lastUpdated: number;       // ms
  txns?: { buys: number; sells: number; total: number; volume: number; volume24h: number };
}

getPriceHistory returns current plus optional 3d, 5d, 7d, 14d and 30d numbers. A young token simply lacks the older keys, so treat each one as optional.

Run the example

Create an empty directory and install the SDK and a TypeScript runner:

npm init -y && npm pkg set type=module
npm install @solana-tracker/data-api@^0.5.0
npm install --save-dev tsx typescript @types/node
node --env-file=.env --import tsx index.ts

Put your key in .env next to the script. Create the key in the Data API dashboard and never commit the file. TOKEN_MINT defaults to wrapped SOL, and WATCHLIST takes comma-separated mints (the script chunks lists longer than 100).

ST_API_KEY=
TOKEN_MINT=So11111111111111111111111111111111111111112
WATCHLIST=

The script prints every pool for one token, sorted by liquidity, then prices a watchlist in batches. The SDK has no request timeout and does not retry, so each call goes through a small wrapper that adds both and honors retryAfter on rate limits.

import { Client, DataApiError, RateLimitError, ValidationError } from "@solana-tracker/data-api";
import type { PriceData } from "@solana-tracker/data-api";

const apiKey = process.env.ST_API_KEY?.trim();
if (!apiKey) {
  console.error("Missing ST_API_KEY (create one at https://www.solanatracker.io/account/data-api)");
  process.exit(1);
}
const BASE58 = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
const mint = process.env.TOKEN_MINT?.trim() || "So11111111111111111111111111111111111111112";
const watchlist = [...new Set((process.env.WATCHLIST?.trim() ||
  "So11111111111111111111111111111111111111112,EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v,JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN"
).split(",").map((m) => m.trim()).filter(Boolean))];
for (const m of [mint, ...watchlist]) {
  if (!BASE58.test(m)) { console.error(`Not a valid mint address: ${m}`); process.exit(1); }
}

const client = new Client({ apiKey });
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));

async function withRetry<T>(label: string, fn: () => Promise<T>, attempts = 4, timeoutMs = 15_000): Promise<T> {
  for (let attempt = 1; ; attempt++) {
    let timer: NodeJS.Timeout | undefined;
    try {
      const timeout = new Promise<never>((_, reject) => {
        timer = setTimeout(() => reject(new Error(`${label} timed out`)), timeoutMs);
      });
      return await Promise.race([fn(), timeout]);
    } catch (error) {
      const retryable = !(error instanceof ValidationError) &&
        (!(error instanceof DataApiError) || error instanceof RateLimitError || (error.status ?? 500) >= 500);
      if (!retryable || attempt >= attempts) throw error;
      const retryAfterMs = error instanceof RateLimitError && error.retryAfter ? error.retryAfter * 1000 : 0;
      await sleep(Math.max(Math.min(8_000, 500 * 2 ** (attempt - 1)), retryAfterMs));
    } finally {
      clearTimeout(timer);
    }
  }
}

const usd = (n?: number) => (typeof n === "number" && Number.isFinite(n) ? `$${n < 0.01 ? n.toPrecision(3) : n.toFixed(2)}` : "n/a");
const short = (a: string) => `${a.slice(0, 4)}…${a.slice(-4)}`;

try {
  // 1. Every pool for one token, deepest first.
  const info = await withRetry("getTokenInfo", () => client.getTokenInfo(mint));
  const pools = [...(info.pools ?? [])].sort((a, b) => (b.liquidity?.usd ?? 0) - (a.liquidity?.usd ?? 0));
  console.log(`${info.token.symbol} (${short(mint)}): ${pools.length} pool(s)`);
  console.table(pools.slice(0, 10).map((p) => ({
    market: p.market,
    pool: short(p.poolId),
    priceUsd: usd(p.price?.usd),
    liquidityUsd: usd(p.liquidity?.usd),
    ageSec: Math.round((Date.now() - p.lastUpdated) / 1000),
  })));

  // 2. Watchlist prices, 100 mints per request, joined by mint key.
  const prices: Record<string, PriceData> = {};
  for (let i = 0; i < watchlist.length; i += 100) {
    const group = watchlist.slice(i, i + 100);
    Object.assign(prices, await withRetry("getMultiplePrices", () => client.getMultiplePrices(group, true)));
  }
  console.table(watchlist.map((m) => {
    const p = prices[m];
    if (!p || !Number.isFinite(p.price)) return { mint: short(m), priceUsd: "unavailable" };
    return {
      mint: short(m),
      priceUsd: usd(p.price),
      liquidityUsd: usd(p.liquidity),
      change24h: p.priceChanges?.["24h"]?.priceChangePercentage?.toFixed(2) ?? "n/a",
    };
  }));
} catch (error) {
  const status = error instanceof DataApiError ? ` (HTTP ${error.status})` : "";
  console.error(`Request failed${status}: ${error instanceof Error ? error.message : String(error)}`);
  process.exitCode = 1;
}

The companion project does the same with aligned tables, adds the getPrice snapshot with 1h and 24h change, the getPriceHistory points and the pool price spread.

Production pitfalls

There is no single price. A token with ten pools has ten prices. They usually agree within a fraction of a percent on liquid tokens and can disagree by a lot on new ones. Print the pool spread, as the example does, and decide which pool you trust instead of taking pools[0]. Show the pool when a number is pool-specific.

Thin pools produce plausible numbers. A pool with $800 of liquidity can report a price that looks fine and cannot absorb a real order. Set a liquidity floor before a pool's price is allowed to drive anything. For a trade, ask for a quote instead.

Missing is not zero. A mint can be absent from a batch response, or come back with a non-finite price. Replacing that with 0 makes an outage look like a total loss in a portfolio view. Render it as unavailable and keep the last known value with its timestamp.

Check freshness. lastUpdated tells you when the price was last observed. A token that has not traded for hours still returns a price. Display the age next to the number and treat old values differently from fresh ones.

Batch and cache on the server. Deduplicate mints before batching, chunk at 100, and cache shared results so many viewers of one token cause one upstream request. Each REST call counts against your plan's monthly request allowance; streaming does not.

Retry with limits. Invalid keys (401 or 403) and validation errors need a configuration fix, not a retry. Rate limits and 5xx responses get capped exponential backoff with jitter, honoring retryAfter. Keep the last good value on screen while you retry.

Keep the key on the backend. A key shipped in browser code is visible to anyone. Proxy price calls through your server and return only the fields the frontend needs.

Spot price is not risk-free. A clean price says nothing about mint authority, holder concentration or liquidity locks. Gate automated actions on a risk check; the rug check guide covers that.

FAQ

How many tokens can I price in one request?

Up to 100 with getMultiplePrices or postMultiplePrices. The SDK rejects larger arrays with a ValidationError before sending, so split longer lists into chunks of 100 and merge the results by mint.

Why does getPrice differ from the price shown for a specific pool?

getPrice returns one snapshot for the token, while getTokenInfo lists each pool's own price. Pools drift apart when liquidity is thin or a trade has just moved one of them. Use the per-pool data when the venue matters.

Can I get the price of a token at a past time?

Yes. getPriceAtTimestamp(mint, unixSeconds) returns the price near that moment and the pool it came from, and getPriceRange(mint, from, to) returns the lowest and highest price in a window. For a full series, use candles from the chart endpoint.

Is the API price what I will get in a swap?

No. A swap fills against specific pools at your trade size, with fees and slippage. Request a quote from the Raptor Swap API for an executable amount.

Should I poll for a live ticker?

Only for slow-changing screens. For tickers and alerts, subscribe to a Datastream price room on Premium or higher and use REST for the initial value and for recovery after a reconnect.

Does the API cover new pump.fun tokens?

Tokens are priced once their pools are indexed, including launchpad bonding curves and the AMM pools they migrate to. Expect the pool list and the main pool to change over a new token's first hours.

References

  • Get Solana token prices and OHLCV charts (guide)
  • Get token price
  • Get multiple token prices
  • Get historic price information
  • Get price at a specific timestamp
  • Get lowest and highest price in a time range
  • Get token information
  • Raptor: get swap quote
  • @solana-tracker/data-api on npm

Companion project

The companion project prints a per-pool price and liquidity table with the pool spread, a price snapshot with change percentages, coarse history points and a batch watchlist table. It reads ST_API_KEY, TOKEN_MINT and WATCHLIST from .env.

cp .env.example .env && npm install && npm start
View source on GitHub›Run in StackBlitz›

Runnable Node.js project — clone from GitHub, add keys to .env, then npm start. Use a private local environment for credentials. Check the companion package version before running.

Related Guides

Solana OHLCV API: Candles, Intervals and Gaps
Data API

Solana OHLCV API: Candles, Intervals and Gaps

Read more
Solana Liquidity Events API: LP History and Live Stream
Data API

Solana Liquidity Events API: LP History and Live Stream

Read more
Jupiter DCA API: Track Recurring Orders and Live Fills
Data API

Jupiter DCA API: Track Recurring Orders and Live Fills

Read more

Products

  • Data API
  • Pump.fun API
  • Solana RPC
  • Dedicated Nodes
  • Yellowstone gRPC
  • Raptor Swap API
  • Enterprise

Trading

  • Swap
  • Latest Tokens
  • Trending
  • Top Gainers
  • Memescope
  • Whale Watch
  • KOL Tracker

Tools

  • Wallet Tracker
  • Rugcheck
  • PnL Leaderboard
  • KOLScan
  • Axiom Leaderboard
  • Photon Leaderboard
  • Bloom Leaderboard
  • FOMO Leaderboard
  • GMGN Leaderboard
  • Pump.fun App Leaderboard
  • Terminal Leaderboard
  • Platform Compare
  • My Positions
  • Teams

Resources

  • Developer Guides
  • Blog
  • Documentation
  • API Reference
  • Status
  • Affiliate Program — 25% recurring, uncapped
Solana TrackerSolana Tracker© 2026
Terms of ServicePrivacy PolicyContact