Skip to main content
A token price alert monitor watches a list of tokens and fires when one crosses a level you care about, so you find out about a move while you can still act on it. The hard part is not reading a price. It is doing it cheaply across a whole watchlist, and firing on a real move rather than a momentary wick that reverts a second later.

TL;DR

  • Poll the whole watchlist in one cheap batch call
  • Drill into exact thresholds only for tokens near a level
  • Confirm the move on a closed candle before firing
Token price alert monitor pipeline showing three endpoints from a watchlist poll to a fired alert All requests share the base URL https://public-api.birdeye.so, authenticate with the X-API-KEY header, and select the network with the x-chain header, defaulting to solana.
This design runs entirely over REST polling. Birdeye Data offers a WebSocket price feed, but on the Premium tier it sits behind a Business upgrade, so tiered polling, a cheap batch scan plus targeted drill downs, keeps cost low without needing the socket.

The three stage loop

1

Poll the watchlist in one call

You do not want a separate request per token when a watchlist can run to dozens of names. One batch call keeps every loop cheap.Endpoint: GET /defi/multi_price
The price field is value, not price. Up to 100 addresses per call, so a longer watchlist splits into batches of 100. The response also carries priceChange24h, enough to drive a simple 24 hour alert on its own without a second request.
2

Check absolute and percent thresholds

When a token from the poll looks close to a level, drill in for the exact numbers that decide whether to fire.Endpoint: GET /defi/v3/price/stats/single
The casing flips here. The batch poll returns camelCase like priceChange24h, but this endpoint is snake_case, so the field is price_change_percent. Values sit one level deep, in a data array per address that itself holds a data array per timeframe.
3

Confirm the move on a closed candle

A threshold check on a live price fires on wicks, brief spikes that snap back within the same candle. Confirming on a closed candle removes them, and the same call doubles as a custom baseline.Endpoint: GET /defi/v3/ohlcv
The most recent item in the series is often the current, still forming candle, and its close is not final. Check unix_time against the interval to confirm a candle has actually closed before reading its c value.
For a custom baseline the fixed timeframes cannot answer, such as how far since you added a token yesterday afternoon, set time_from to that reference moment and read the close of the first candle in the series. No extra endpoint needed.

Choose your alert types

Three alert types cover almost every case, and each maps to one call above:
  • Absolute price alert: fires on a fixed price target. Read price from the stats call, or value from the batch poll. The cheapest alert, since the batch poll alone can drive it.
  • Percent move alert: fires on a relative change over a window. Read price_change_percent for that timeframe, precomputed so you never store a prior price yourself.
  • Custom baseline alert: fires on a move since a reference point the fixed windows do not cover. Point time_from on the candle call at that moment.
Debounce is what separates a usable monitor from an unusable one. A token sitting above a threshold trips it on every loop, so track an alert state per token, fire once on the crossing, and reset only when the price falls back through the level.

Watch your credit budget

A monitor runs forever, so its cost compounds. A watchlist of 100 tokens polled once a minute is 1,440 batch calls a day before any drill down calls stack on top. Endpoint: GET /utils/v1/credits
Log the balance every loop while tuning the polling interval, so a too tight interval shows up as a falling balance rather than a suspended key.

Survive the gaps in a polling loop

A monitor that only works when every request succeeds will not survive its first bad night.
  • Retry transient failures. One missed poll is normal, several in a row means a token could cross a threshold and cross back before you notice. Retry with a short backoff and log the gap rather than pretending the loop ran clean.
  • Guard against stale prices. The batch response carries updateUnixTime per token. A thinly traded token can hand back a price minutes old. Compare it against the current time and skip any token older than your alert window.
  • Persist debounce state. If the alert state only lives in memory, a restart wipes it, and every token already above threshold fires all over again. Persist state next to the watchlist and treat the first loop after a restart as a rebuild, not a normal pass.
  • Keep the host clock synced. Every candle boundary and custom baseline comes down to a Unix timestamp comparison, so a drifting clock asks for a candle that has not closed yet.

Before you ship

  • The batch poll reads value, not price, and splits watchlists longer than 100 into batches.
  • The stats call reads snake_case price_change_percent from the nested data array.
  • The candle confirmation reads the last closed candle, checked by unix_time, not the forming one.
  • Every alert is debounced by per token state so it fires once per crossing.
  • updateUnixTime is checked before trusting a price as fresh.
  • Debounce state is persisted so a restart does not refire every open alert.

FAQ

Birdeye Data offers a WebSocket price feed, but on the Premium tier it sits behind a Business upgrade. Tiered polling, a cheap batch scan plus targeted drill downs, keeps cost low enough that the socket is not needed for most watchlists.
Every threshold break is confirmed on a closed candle. A live price can spike and revert within a single candle, so the monitor reads the close of the last completed candle and fires only if that confirmed value clears the threshold.
Track an alert state per token. Fire once when the price crosses the level, mark the token alerted, and clear that state only when the price falls back through the level.
Three calls, tiered by cost, turn a watchlist into a monitor that fires on real moves and stays quiet on the rest.