Skip to content

API reference

CoinBeacon API

Free, read-only cryptocurrency market data. 47 JSON endpoints covering funding rates, liquidations, open interest, candles, market cap and the scored setup boards. These are the same endpoints coinbeacon.io reads from, so if a number is on the site it is in here. The API is in a free public beta: create a key on the API page in the app and start calling.

Free public beta

Every endpoint, free: 2,000 credits a day and 60 a minute for each account, with up to 2 keys. Limits may change while the beta runs, and we email key holders 30 days before any limit drops. Tell us what you build. API terms

Get an API key
Base URL
https://api.coinbeacon.io
Authentication
X-API-Key header
Free allowance
2,000 credits/day · 60/min
Endpoints
47 · all GET, JSON

Quickstart

Every request carries your key in the X-API-Key header. Nothing else is needed: no OAuth dance, no token to refresh, no signature to compute.

This one returns BTC’s current funding rate on every venue that lists it, the best venue to be short and the best to be long, 30 days of hourly history, and 7- and 30-day statistics.

Every rate is normalized to an 8-hour basis, so a venue settling hourly and a venue settling every eight hours can be compared directly. ratePercent is the venue’s own number for one of its funding intervals; normalizedRate8hPercent is the comparable one.

From there, the reference below is grouped by what the data is about. Press / or ⌘K to jump to an endpoint by name or route.

Request
curl -H "X-API-Key: $COINBEACON_API_KEY"   "https://api.coinbeacon.io/public/funding/coin/BTC"
Response200
{
  "base": "BTC",
  "venues": [
    {
      "exchange": "binance_futures",
      "symbol": "BTCUSDT",
      "ratePercent": 0.006313,
      "normalizedRate8hPercent": 0.006313,
      "fundingIntervalHours": 8,
      "nextFundingTime": 1790784000000
    }
  ],
  "spread": {
    "exchangeCount": 10,
    "shortExchange": "bitget_futures",
    "shortRate8hPercent": 0.01,
    "longExchange": "huobi_futures",
    "longRate8hPercent": -0.0048400985753915,
    "spread8hPercent": 0.0148400985753915,
    "spreadAprPercent": 16.249907940053692
  },
  "history": {
    "exchange": "binance_futures",
    "symbol": "BTCUSDT",
    "points": [
      { "timestamp": 1790765229573, "normalizedRate8hPercent": 0.002055 },
      { "timestamp": 1790768887820, "normalizedRate8hPercent": 0.00608 }
    ]
  },
  "stats": {
    "d7": { "avg": 0.0024541929824561395, "min": -0.002948, "max": 0.008362, "count": 171 },
    "d30": { "avg": 0.00527554803788903, "min": -0.00404, "max": 0.01, "count": 739 }
  },
  "dataAt": 1790768887820
}

venues[] truncated to 1 of 10; history.points[] to its last 2 of 739

Authentication

Every request needs an API key, sent as the X-API-Key header. Keys are free. If your client makes custom headers awkward, Authorization: Bearer cb_live_… is accepted too.

Create a key on the API page in the app: sign in with a verified email address, name the key, and copy it. The full key is shown once. An account can hold 2 keys, and they share one allowance.

A key is a secret. Keep it on your server, out of your source control and out of anything you ship to a browser. If one leaks, revoke it on the API page and create another. Revocation takes effect on the next request.

This is also why the API is server-side only. A request carrying an Origin header from a domain that is not ours is rejected, and that rejection currently surfaces as a 500 rather than as a CORS failure, so a browser fetch() from your own site fails in a way that looks like a fault on our side. It is not, and retrying will not help. Put the call behind your own backend, which is where the key belongs anyway, and cache the result there.

Authenticated request
# Keep the key in the environment, never in the command you paste around.
export COINBEACON_API_KEY="cb_live_..."

curl -H "X-API-Key: $COINBEACON_API_KEY"   "https://api.coinbeacon.io/public/market/globals"
Without a key
{
  "statusCode": 401,
  "message": "An API key is required. Send it as the X-API-Key header. Get a free key at https://app.coinbeacon.io/developer. See https://coinbeacon.io/docs/api#authentication",
  "error": "Unauthorized",
  "timestamp": "2026-09-30T12:04:06.883Z",
  "path": "/public/market/globals"
}

A revoked or unknown key returns the same status with a different message.

Credits and limits

Every call costs credits, priced by how much work it takes to answer rather than by how much comes back: 1 credit for one coin or a small cached answer, 5 for a whole board or list, 10 for a board that fans out across venues, and 25 for analytics that can take minutes of database work. What you need in order to use the API at all, such as your own usage, costs nothing. Each endpoint below shows its price.

Your account gets 2,000 credits a day and 60 a minute, shared by all its keys. The day resets at 00:00 UTC. A call refused for the limit (429) costs nothing, and so does a server error (5xx); any other error costs 1 credit. The heaviest calls also run one at a time per account, and one that cannot start right away gets a 429.

Every keyed response carries your balance in its headers, and /public/usage reports it for free, so you never have to guess what is left.

Underneath it, each route keeps its own per-IP limit, counted per route rather than per group. Two endpoints in the same section, even two handlers in the same file, often carry different limits, so the figure printed at the top right of each entry below is the one that applies to it, and nowhere else.

A few endpoints reach an upstream exchange on a cache miss, and each distinct symbol is its own cache entry. Sweeping those across every symbol is the one usage pattern that will get you blocked. Prefer the endpoints that already return a whole board in one call, and cache on your side.

If you need more than the allowance, write to support@coinbeacon.io rather than opening a second account, which we will find and close.

Credits per call
lookup
1 credit · one coin, or a small cached answer
board
5 credits · a whole board or list
heavy
10 credits · a board that fans out across venues or upstreams
analytics
25 credits · minutes of database work when uncached; 1 at a time per account
reference
0 credits · your usage, the plans, the changelog
Request
curl -sD- -o /dev/null -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/funding/index"
Response headers
X-Credits-Cost
what this call cost
X-Credits-Limit
your account's credits a day
X-Credits-Remaining
credits left today, until 00:00 UTC
X-Credits-Reset
when today's credits reset, as an ISO time
X-RateLimit-Limit-Minute
your account's credits a minute
X-RateLimit-Remaining-Minute
credits left this minute
x-ratelimit-limit-market-medium
the route's own per-IP ceiling
Retry-After
seconds to wait, sent with a 429 and with the 503 while API keys are paused

The X-Credits-* and X-RateLimit-*-Minute headers track your ACCOUNT across every key and endpoint. The lowercase x-ratelimit-limit-* headers track the ROUTE for your IP. The bucket name in them (market-medium, market-heavy) is shared across routes, but the counter is not.

Errors

A 200 means the request was understood. On this API it usually does not mean the thing you asked about was found.

Almost every endpoint answers an unknown symbol with a 200 and an empty result rather than a 404: an unrecognised coin comes back as found: false, an unrecognised perp as an empty points array, an unrecognised instrument as count: 0. A failed upstream does the same: nulls and empty arrays, not a 5xx.

Some parameters are clamped or silently replaced instead of rejected: an out-of-range hours is pulled back into range, an unrecognised period falls back to a default, and a few filters ignore a value they do not recognise and hand back the unfiltered board.

So read the values echoed back in the response and check the length of what you got. Do not branch on the status code alone. Every endpoint below states its own behaviour under status and edge cases.

Error body
{
  "statusCode": 404,
  "message": "No funding data for this coin",
  "error": "Not Found",
  "timestamp": "2026-09-30T11:59:24.930Z",
  "path": "/public/funding/coin/NOTFUNDED"
}

Every non-2xx uses this envelope. message is the useful field: on a 400 it names the parameter and, for an enum, lists the accepted values.

200
Understood. This does not always mean data was found; see above.
401
No API key, or a key that is unknown or revoked. The message says which, and points to the API page, where keys are created. Every /public/* route answers this way for third parties.
400
A parameter failed validation. The message names the parameter and, for an enum, lists the accepted values. Not every parameter validates: a few ignore an unrecognised value and return the unfiltered board, which is called out where it happens.
403
The route is not open to API keys: it serves the CoinBeacon site only, or it is closed to keys for now (the plan marks it closed). Or your account's API access is suspended. The message says which, and it costs nothing.
404
No such route, with one exception. /public/funding/coin/{base} returns 404 when no tracked venue funds the coin. That is a data answer, not a bad request. A coin funded on one venue, or on several at the same rate, is a 200 with a zero spread.
429
A limit was reached: your account's credits for the minute or the day, a heavy call that cannot start right away, or the route's per-IP limit. Retry-After says how long to wait, and the refused call costs nothing.
500
Either a genuine fault, or a cross-origin browser request being rejected. See Authentication.
503
Nothing to answer from, or an answer that took too long: /public/funding/coin/{base} when the API holds no funding data, and a heavy call that ran past its time limit. Also every keyed call while we have API keys paused to deal with a problem (Retry-After says when to try again). Retry with backoff; a 503 costs nothing.

Conventions

Four things vary across this API in ways you cannot infer from a route name. Each endpoint states which it uses; this is the map.

Symbols come in two key spaces

Some routes take a base asset (BTC) and some take a venue-native symbol, which is whatever that exchange calls the instrument: BTCUSDT on Binance, BTC_USDT on Gate.io, BTC-USDT-SWAP on OKX. Passing a base asset where a venue-native symbol is expected is the most common cause of an empty result. Never normalize between the two yourself: use the catalogue from the symbols endpoint for the venue you are calling.

Venue names are spelled two different ways

The movers and funding routes use underscores (binance_futures). The Smart Setups, Trend Scanner, detector, ATH/ATL, pumping, candle and quote routes use hyphens (binance-futures). Both are correct in their own place and neither accepts the other. The accepted values are listed in full on every parameter that takes one, so do not carry a venue list from one endpoint to another.

Timestamps are epoch milliseconds, except where they are not

Most timestamps on this API are milliseconds since the Unix epoch, as a number. Four routes return updatedAt as an ISO 8601 string instead: movers, all movers, funding rates and funding spreads. The two forms also mix inside a single response: on /public/funding/all the envelope’s updatedAt is an ISO string for when the snapshot was built, while each row’s updatedAt is epoch milliseconds for when that rate was ingested. Check the type before you parse, per field, not per endpoint.

Counts are what exists, not what you were sent

Most endpoints return a whole board at a server-side cap with no way past it. Three take a limit (market cap, candles and search), and only search has an offset; candles page backwards with to instead. Everywhere else there is no cursor, offset or page parameter, and the rows past the cap are not reachable. A returned count or total is the number of rows available, not the number you were given; read the array’s own length for that.

Data sources

Prices, candles, funding, liquidations and open interest come from each exchange’s own public API, and the boards are computed from them. Three providers supply the rest. If you show their data, show their credit next to it.

CoinGecko

Market totals and dominance, trending coins, and all-time high and low marks: globals and their history, trending and ATH/ATL. Show “Powered by CoinGecko” with a link to coingecko.com.

alternative.me

The Fear & Greed index in globals and their history. Credit alternative.me next to the value.

CoinMarketCap

Market cap, rank and coin details: the market cap endpoints and the screener. Credit CoinMarketCap.

01

Market

11 endpoints

The macro picture: what is moving, how the market is positioned, and how it feels.

GET/public/market/globals1 credit120/min

Market globals

One cached snapshot of the whole crypto market. Each figure comes from a different upstream (CoinGecko for dominance and totals, alternative.me for Fear and Greed, our own funding index for the average rate), and any source that fails degrades its own fields to null instead of failing the request. Treat every numeric field as nullable.

Parameters

None. Everything this endpoint returns is pinned server-side.

Status and edge cases

  • A failed upstream returns 200 with null in the affected fields, never a 5xx.

Notes

  • Cached 10 minutes server-side. Polling faster returns the same snapshot.
  • avgFunding8hPct is the funding-index APR divided by 1095 (365 x 3), so the sampled -0.0006643 is -0.0006643 percent per 8 hours, not a fraction and not an APR.
  • volumeChange24hPct and btcDominanceChange24hPct come from our own history series, not from CoinGecko, and are null unless a stored sample sits within 4 hours of the 24h-ago mark.
  • Zero is never returned for a level: a source that reports 0 for market cap, volume or dominance is mapped to null. A change of exactly 0 percent is kept.
  • fearGreed.updatedAt moves about once a day; the top-level updatedAt moves every 10 minutes.
  • The rate limit is keyed per IP and per route, so this 120/min is not shared with the other market endpoints.
▸Response fields(13)
fearGreedobject|null
Fear and Greed index block, null when alternative.me failed
fearGreed.valuenumber
Index value, 0 to 100
fearGreed.classificationstring
Publisher's label for that value, e.g. Greed
fearGreed.updatedAtnumber
When the index itself was published, epoch ms
btcDominancenumber|null
BTC share of total market cap, percent
ethDominancenumber|null
ETH share of total market cap, percent
totalMarketCapUsdnumber|null
Total crypto market cap, USD
totalVolume24hUsdnumber|null
Total 24h traded volume, USD
marketCapChange24hPctnumber|null
CoinGecko's own 24h market-cap change, percent
volumeChange24hPctnumber|null
24h volume change derived from our stored series, percent
btcDominanceChange24hPctnumber|null
24h dominance change derived from our stored series, percent
avgFunding8hPctnumber|null
Cross-venue average funding per 8 hours, percent; negative when the average leg pays shorts
updatedAtnumber
When this snapshot was computed, epoch ms
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/market/globals"
Response200
{
  "fearGreed": {
    "value": 63,
    "classification": "Greed",
    "updatedAt": 1789171200000
  },
  "btcDominance": 58.222305887273684,
  "ethDominance": 11.56055853699974,
  "totalMarketCapUsd": 2656372428005.7417,
  "totalVolume24hUsd": 51780741277.31647,
  "marketCapChange24hPct": -2.8521922577884546,
  "volumeChange24hPct": -52.13460893023909,
  "btcDominanceChange24hPct": 0.02048673920382909,
  "avgFunding8hPct": -0.0006643025512462472,
  "updatedAt": 1789243894106
}

Powered by CoinGecko · Fear & Greed index by alternative.me

GET/public/market/globals/history1 credit120/min

Market globals history

The stored history behind /public/market/globals, for sparklines and trend checks. Samples are written only when the globals snapshot is recomputed, so spacing is roughly 10 minutes but irregular. Read the returned coveredHours rather than assuming you got the window you asked for.

Query parameters

hoursintegeroptionaldefault 24
Window in hours, clamped server-side to 1-168; a non-numeric or non-positive value silently becomes 24

Status and edge cases

  • hours never returns 400. Verified live: hours=abc fell back to 24 and hours=9999 clamped to 168.
  • An empty or unreadable series returns 200 with points: [] and coveredHours: 0.

Notes

  • Retention is 8 days but hours clamps at 168, so 7 days is the deepest readable window. hours=9999 returned 551 points and coveredHours 167.9.
  • Spacing is not fixed. Do not compute a rate by assuming a constant interval between points.
  • mcap, vol and btcDom are scrubbed to null on read when a stored level was non-positive. Plot nulls as gaps, not as zeros.
  • A repeated ?hours=a&hours=b uses the first value. hours=1&hours=100 returned coveredHours 0.9.
  • This route reads Redis directly and is not cached, unlike /public/market/globals.
▸Response fields(7)
points[]array
Samples in ascending time order
points[].tnumber
Sample time, epoch ms
points[].mcapnumber|null
Total market cap at that sample, USD
points[].volnumber|null
Total 24h volume at that sample, USD
points[].btcDomnumber|null
BTC dominance at that sample, percent
points[].fginumber|null
Fear and Greed value at that sample, 0 to 100
coveredHoursnumber
Actual span between the first and last returned point, hours, one decimal
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/market/globals/history?hours=6"
Response200
{
  "points": [
    {
      "t": 1789221380236,
      "mcap": 2663249449090.5254,
      "vol": 84212996413.72554,
      "btcDom": 58.15897964363119,
      "fgi": 63
    },
    {
      "t": 1789222010373,
      "mcap": 2664709036583.373,
      "vol": 81198182647.43703,
      "btcDom": 58.16566302266675,
      "fgi": 63
    }
  ],
  "coveredHours": 5.7
}

points[] truncated to 2 of the 28 rows returned for hours=6

Powered by CoinGecko · Fear & Greed index by alternative.me

GET/public/market/sentiment1 credit120/min

Market sentiment

Aggregates the Trend Scanner's per-coin directional scores into three market segments: Binance spot USDT pairs, Binance spot BTC pairs, and Binance futures USDT perps. Each segment reports a score per timeframe, a headline score, a regime label and an average RSI.

Parameters

None. Everything this endpoint returns is pinned server-side.

Status and edge cases

  • A segment with no indexed coins returns score null and count 0 rather than an error.

Notes

  • Scores are unweighted means of per-coin trend scores in -100..+100. A large-cap and a microcap count the same.
  • regime is mixed whenever any timeframe is positive and any other is negative, whatever the headline score. Otherwise bull above +5, bear below -5, neutral in between.
  • perTf[].count falls on longer timeframes because fewer coins have enough history. Live: 444 coins at 15m against 280 at 1w for USDT.
  • avgRsi pools the 15m, 1h, 4h, 1d and 1w RSI indexes into one mean, so it is not the mean of per-coin RSI and coins covered on more timeframes weigh more.
  • avgRsi is null until the worker's RSI index has populated.
  • Cached 60 seconds.
▸Response fields(12)
segments[]array
Always three entries: USDT, BTC, PERP
segments[].keystring
Segment id: USDT (Binance spot USDT pairs), BTC (Binance spot BTC pairs), PERP (Binance futures USDT perps)
segments[].labelstring
Display label, currently identical to key
segments[].scorenumber|null
Mean of the non-null perTf scores, rounded, range -100 to 100
segments[].regimestring
One of bull, bear, neutral, mixed
segments[].perTf[]array
One entry per timeframe, in order 15m, 1h, 4h, 1d, 1w
segments[].perTf[].tfstring
Timeframe id
segments[].perTf[].scorenumber|null
Average trend score for that timeframe, rounded, -100 to 100, null when count is 0
segments[].perTf[].countnumber
Coins that had a score on that timeframe
segments[].avgRsinumber|null
Mean RSI over coin-and-timeframe samples, not over coins: all five timeframe indexes are pooled, so a coin present on five timeframes contributes five samples. Range 0 to 100, one decimal
segments[].coinCountnumber
Largest per-timeframe count in the segment
updatedAtnumber
When the aggregate was computed, epoch ms
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/market/sentiment"
Response200
{
  "segments": [
    {
      "key": "USDT",
      "label": "USDT",
      "score": -6,
      "regime": "mixed",
      "perTf": [
        {
          "tf": "15m",
          "score": -14,
          "count": 444
        },
        {
          "tf": "1h",
          "score": 21,
          "count": 443
        }
      ],
      "avgRsi": 49,
      "coinCount": 444
    }
  ],
  "updatedAt": 1789242610965
}

segments[] truncated to 1 of 3 (USDT, BTC, PERP) and perTf[] to 2 of 5 timeframes

GET/public/market/structure1 credit120/min

Market structure

Three unrelated structural reads in one payload: spot-versus-perp basis on Binance, how many top-50 alts beat BTC over 90 days, and aggregate USD-pegged stablecoin supply. The three blocks degrade independently, so altseason or stablecoins can be null inside an otherwise healthy 200.

Parameters

None. Everything this endpoint returns is pinned server-side.

Status and edge cases

  • altseason and stablecoins are independently nullable inside a 200; check for null before reading their fields.

Notes

  • The basis set is pinned to BTCUSDT, ETHUSDT and SOLUSDT. There is no parameter to change it.
  • Either basis leg older than 5 minutes yields null for that leg and a null basisPct, rather than a number computed off a dead quote.
  • altseason excludes BTC itself and every coin tagged stablecoin, then takes the top 50 by rank.
  • stablecoins counts only peggedUSD circulating supply, so EUR- and other-pegged coins are out of scope.
  • change24hUsd and change7dUsd cover different windows (1 day and 7 days) and normally differ; only change7dUsd matches change7dPct.
  • Cached 60 seconds; the stablecoin leg has its own 15-minute cache, so that block can be up to 15 minutes older than updatedAt.
▸Response fields(16)
basis[]array
Exactly three entries: BTCUSDT, ETHUSDT, SOLUSDT
basis[].symbolstring
Pair the basis was computed on
basis[].spotnumber|null
Latest Binance spot price, USD, null when the tick is over 5 minutes old
basis[].perpnumber|null
Latest Binance futures perp price, USD, same staleness rule
basis[].basisPctnumber|null
(perp - spot) / spot as a percent; positive means perps trade rich
altseasonobject|null
Breadth block, null when the market-cap cache is empty or BTC has no 90d change
altseason.totalnumber
Coins in the sample, at most 50
altseason.beatingBtcnumber
How many of them outperformed BTC over 90 days
altseason.pctnumber
beatingBtc / total as a percent, unrounded
altseason.btcChange90dnumber
BTC's own 90-day price change, percent
stablecoinsobject|null
DeFiLlama supply block, null when that call fails
stablecoins.totalUsdnumber
Circulating supply of USD-pegged stablecoins, USD
stablecoins.change24hUsdnumber|null
24h change in that supply, USD: totalUsd minus DeFiLlama's previous-day circulating sum. Null when that sum is not above 0
stablecoins.change7dUsdnumber|null
7-day change in that supply, USD: totalUsd minus the previous-week circulating sum. Null when that sum is not above 0
stablecoins.change7dPctnumber|null
The same 7-day change as a percent of the previous-week sum; the percent form of change7dUsd, not of change24hUsd
updatedAtnumber
When the snapshot was computed, epoch ms
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/market/structure"
Response200
{
  "basis": [
    {
      "symbol": "BTCUSDT",
      "spot": 77116.68,
      "perp": 77072.9,
      "basisPct": -0.0567711161839421
    },
    {
      "symbol": "ETHUSDT",
      "spot": 2517.8,
      "perp": 2516.33,
      "basisPct": -0.058384303757258504
    },
    {
      "symbol": "SOLUSDT",
      "spot": 101.34,
      "perp": 101.31,
      "basisPct": -0.02960331557134511
    }
  ],
  "altseason": {
    "total": 50,
    "beatingBtc": 19,
    "pct": 38,
    "btcChange90d": 20.94825933
  },
  "stablecoins": {
    "totalUsd": 312301181195.3321,
    "change24hUsd": 1337911109.8391113,
    "change7dUsd": 1105718795.1252441,
    "change7dPct": 0.35531327693437126
  },
  "updatedAt": 1789242626246
}
GET/public/market/positioning10 credits120/min

Futures positioning

The account positioning a perp venue publishes for one of its perps: the share of all accounts that are long, the same figure for top traders by position, the taker buy/sell ratio, and 24 hourly points of the all-accounts long share. Binance by default; venue picks Bybit, OKX, Gate or HTX instead, and each publishes a different subset (see the notes). Every symbol is cached for 5 minutes per venue here.

Query parameters

symbolstringoptionaldefault BTCUSDT
The perp symbol in the venue's own spelling: BTCUSDT on binance-futures and bybit-futures, BTC-USDT-SWAP on okx-futures, BTC_USDT on gateio-futures, BTC-USDT on htx-futures. Matched case-insensitively against ^[A-Z0-9_-]{2,24}$ then upper-cased server-side, otherwise 400
venueenumoptionaldefault binance-futures
Whose breakdown to read. Anything else returns 400 with the accepted list.
binance-futuresbybit-futuresokx-futuresgateio-futureshtx-futures

Status and edge cases

  • A symbol containing anything but letters, digits, underscore and hyphen, or shorter than 2 or longer than 24 characters, returns 400 "Invalid symbol".
  • An unrecognised venue returns 400 with the accepted list.
  • A repeated ?symbol=a&symbol=b returns 400 "Invalid symbol". Verified live.
  • A well-formed but unknown symbol returns 200 with every metric null and history: []. Verified: symbol=ZZZZUSDT.
  • When the venue cannot be asked (it is rate-limiting us, or our per-minute ceiling for its data is spent), the route returns 200 with the last good reading for that symbol from the past hour (check updatedAt), or every metric null if there is none.

Notes

  • Pass the venue's contract symbol, not a base asset: BTC is not a valid symbol here.
  • Each venue publishes a different subset, and a reading it does not publish is null: Bybit publishes the all-accounts share only (no top-trader or taker reading); HTX publishes its top traders' positions only, so globalLongPct, takerBuySellRatio and history stay null and []; Binance, OKX and Gate publish all three. OKX and Gate publish ratios, converted to shares here.
  • OKX does not cover its USDC-margined swaps: those return every metric null.
  • Case-insensitive: symbol=btcusdt returns the BTCUSDT response with symbol upper-cased.
  • globalLongPct and topLongPct are percents in 0-100; the two *Ratio fields are raw ratios, not percents.
  • The headline globalLongPct is the last element of history, so the two always agree.
  • Each source degrades independently: a single upstream endpoint failing nulls one field and leaves the rest populated.
  • A cache miss costs the venue one to three calls (three on Binance and OKX), and every distinct symbol is its own cache key per venue. Do not iterate symbols in a loop.
▸Response fields(11)
symbolstring
Upper-cased symbol the response was built for
venuestring
The venue whose published breakdown this is; never another venue's numbers
globalLongPctnumber|null
Share of all accounts holding a long, percent
globalLongShortRationumber|null
Long accounts divided by short accounts, ratio
topLongPctnumber|null
Share of top traders by position holding a long, percent
topLongShortRationumber|null
Same population as a long/short ratio
takerBuySellRationumber|null
Taker buy volume divided by taker sell volume over the last hour, ratio
history[]array
24 hourly global long-share points, oldest first
history[].tnumber
Point time, epoch ms
history[].longPctnumber
Global long share at that hour, percent
updatedAtnumber
When this response was built, epoch ms
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/market/positioning?symbol=BTCUSDT"
Response200
{
  "symbol": "BTCUSDT",
  "venue": "binance-futures",
  "globalLongPct": 62.01,
  "globalLongShortRatio": 1.6323,
  "topLongPct": 68.91000000000001,
  "topLongShortRatio": 2.2169,
  "takerBuySellRatio": 0.6833,
  "history": [
    {
      "t": 1789156800000,
      "longPct": 60.199999999999996
    },
    {
      "t": 1789160400000,
      "longPct": 60.11
    }
  ],
  "updatedAt": 1789242486212
}

history[] truncated to 2 of 24 hourly points

GET/public/market/volatility1 credit120/min

Volatility regime

Reduces 30 days of hourly Deribit DVOL candles into the current implied-volatility level, its 24h change, the 30-day low and high, and where the current level ranks inside that month. Deribit publishes DVOL for BTC and ETH only.

Query parameters

currencyenumoptionaldefault BTC
Underlying to read DVOL for; case-insensitive and upper-cased, anything else returns 400
BTCETH

Status and edge cases

  • Any currency other than BTC or ETH returns 400 "Invalid currency. Allowed: BTC, ETH". Verified: currency=SOL.
  • If Deribit is unreachable the response is 200 with dvol, change24hPct, percentile30d, low30d and high30d all null and history: [].

Notes

  • percentile30d is a rank, not a position in the low-high span: it answers how much of the last month was calmer than now.
  • change24hPct uses the close 25 hourly candles back because the last candle is the in-progress hour.
  • history is downsampled from roughly 720 hourly candles to about 60 points. Use it for shape, not for exact hourly values.
  • Cached 10 minutes per currency, matching Deribit's hourly print cadence.
  • dvol is annualised percent implied vol, not a daily move.
▸Response fields(10)
currencystring
Upper-cased currency the response was built for
dvolnumber|null
Latest DVOL close, annualised implied volatility in percent
change24hPctnumber|null
Change against the close 25 hourly candles back, percent
percentile30dnumber|null
Share of the last 30 days of hourly closes at or below the current level, percent
low30dnumber|null
Lowest hourly close in the last 30 days
high30dnumber|null
Highest hourly close in the last 30 days
history[]array
Downsampled DVOL series, oldest first, about 60 points
history[].tnumber
Candle open time, epoch ms
history[].vnumber
DVOL close for that candle
updatedAtnumber
When this response was built, epoch ms
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/market/volatility?currency=BTC"
Response200
{
  "currency": "BTC",
  "dvol": 36.84,
  "change24hPct": 0.7383100902379085,
  "percentile30d": 27.045769764216367,
  "low30d": 33.88,
  "high30d": 45.38,
  "history": [
    {
      "t": 1786647600000,
      "v": 35.09
    },
    {
      "t": 1786694400000,
      "v": 34.22
    }
  ],
  "updatedAt": 1789242485935
}

history[] truncated to 2 of 57 points

GET/public/market/movers5 credits120/min

Top movers

Ranks every symbol we ingest on one venue by percent change over the chosen window and returns the two ends of that ranking. Percent change is computed from our own stored price series, not from the exchange's 24h ticker, so coverageMinutes tells you how much history actually backed the calculation.

Query parameters

exchangeenumoptionaldefault binance_futures
Venue to rank, lower-cased server-side; an unlisted value returns 400 with the full allowlist in the message
binancebinance_futuresbitgetbybitbybit_futurescoinbasegateiohuobikrakenkraken_futureskucoinmexcokxokx_futures
windowenumoptionaldefault 15
Lookback in minutes; any other number, including 10, returns 400
151530602401440
sparksenumoptional
Set to 1 or true to add a trend line (spark) to every row and sparkSpanMinutes to the envelope. Any other value, including 0 and false, leaves both out.
1true

Status and edge cases

  • An unlisted exchange returns 400 with the 14 allowed values in the message. Verified: exchange=htx.
  • A window not on the allowlist returns 400 with the 7 allowed values. Verified: window=10.
  • A venue with no stored symbols returns 200 with empty gainers and losers, totalSymbols 0 and coverageMinutes 0.

Notes

  • updatedAt is an ISO 8601 string on this route and on /public/market/movers/all. Every other endpoint in this group returns epoch ms as a number.
  • Symbols with exactly 0 percent change are in neither list, but that does not shorten the response: each side is the top or bottom 20 of a ranking of hundreds, so 20 and 20 is normal. Live 20/20 at window=1, 15, 60 and 1440 on binance_futures, and at window=1440 on kraken_futures. Fewer rows come back only when the venue has under 20 symbols above (or below) 0 percent in the window.
  • totalSymbols counts the whole ranked set (760 live on binance_futures); only the 40 rows come back.
  • If coverageMinutes is below windowMinutes the percentages cover less time than you requested.
  • window=1 reads a roughly 10-second tick series retained for 60 minutes; every longer window reads a one-sample-per-minute series.
  • A symbol whose window holds one sample is scored 0 percent and therefore appears in neither list.
  • Symbols are venue-native and not always ASCII. binance_futures currently lists a CJK-named perp (U+9F99 U+867E followed by USDT).
  • Cached about 35 seconds per exchange and window combination.
  • sparks=1 costs one request like any other call. The lines are sampled from the same one-sample-a-minute price history the percent change is read from, so they exist on every venue in the allowlist, including those with no candle data. Points per line: 30 on the 1 and 5 minute windows (a 30-minute line), 15 on 15, 30 on 30, and 48 on 60, 240 and 1440.
  • A failed line read returns the rows without spark rather than failing the request, so check for the key rather than assuming it.
▸Response fields(16)
gainers[]array
Up to 20 rows with percentChange above 0, largest first
gainers[].symbolstring
Venue-native pair symbol
gainers[].baseAssetstring
Base asset of that pair
gainers[].currentPricenumber
Most recent stored price, in the pair's quote currency
gainers[].priceAtnumber | null
When currentPrice was true, epoch ms: the exchange's own timestamp for that price (its event time, or for a REST sample the time the price last changed). Use this, not updatedAt, to tell how fresh a price is. Null when the stored sample carries no readable time
gainers[].oldestPricenumber
First stored price inside the window, same currency
gainers[].percentChangenumber
Change across the window, percent, 4 decimal places
gainers[].dataPointsnumber
Stored samples used for this row
gainers[].sparknumber[]
Only with sparks=1: the price path across sparkSpanMinutes, oldest first, at most 48 points, in the pair's quote currency. The last point is currentPrice; when the line spans exactly the window the first point is oldestPrice, so the line and percentChange agree. Absent on a row with fewer than two samples
losers[]array
Up to 20 rows with percentChange below 0, most negative first; same fields as gainers[], spark included
windowMinutesnumber
Window that was applied, minutes
coverageMinutesnumber
History depth available for the venue's anchor symbol, minutes
exchangestring
Venue the ranking was built for
totalSymbolsnumber
Symbols that qualified for ranking, not the number of rows returned
updatedAtstring
When this response was sent, ISO 8601 string. Not the age of the prices: see priceAt
sparkSpanMinutesnumber
Only with sparks=1: minutes each spark covers. Equal to windowMinutes, except on the 1 and 5 minute windows, whose lines cover the last 30 minutes
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/market/movers?exchange=binance_futures&window=15"
Response200
{
  "gainers": [
    {
      "symbol": "UAIUSDT",
      "baseAsset": "UAI",
      "currentPrice": 0.5911,
      "oldestPrice": 0.5805,
      "percentChange": 1.826,
      "dataPoints": 29
    }
  ],
  "losers": [
    {
      "symbol": "PONSUSDT",
      "baseAsset": "PONS",
      "currentPrice": 0.5769,
      "oldestPrice": 0.5862,
      "percentChange": -1.5865,
      "dataPoints": 29
    }
  ],
  "windowMinutes": 15,
  "coverageMinutes": 1500,
  "exchange": "binance_futures",
  "totalSymbols": 761,
  "updatedAt": "2026-09-12T19:50:41.185Z"
}

gainers[] and losers[] each truncated to one representative row of 20

GET/public/market/movers/all10 credits60/min

All movers

The same ranking as /public/market/movers but returned whole rather than split into two ends, sorted by percent change descending. The public route hard-caps the payload at 250 rows and offers no paging, so anything past row 250 is unreachable here.

Query parameters

exchangeenumoptionaldefault binance_futures
Venue to rank; an unlisted value returns 400 with the full allowlist in the message
binancebinance_futuresbitgetbybitbybit_futurescoinbasegateiohuobikrakenkraken_futureskucoinmexcokxokx_futures
windowenumoptionaldefault 15
Lookback in minutes; any other number returns 400
151530602401440

Status and edge cases

  • An unlisted exchange or window returns 400 with the allowed values in the message.
  • A venue with no stored symbols returns 200 with movers: [], totalSymbols 0 and returnedCount 0.

Notes

  • The 250-row cap has no offset, cursor or page parameter. Rows past 250 cannot be read on this route, even though totalSymbols reports 761.
  • Unlike /movers, this shape includes symbols with no movement: one in-window sample reports 0 percent, and a symbol with none is still listed at its last stored price with 0 percent.
  • This route is 60/min, half the rest of the market group, and uses a separate market-heavy bucket.
  • Rows never carry spark here. To draw a trend line on a page of these rows, send their symbols to /public/market/movers/sparks, at most 50 per call.
  • A cold cache is slow: earlier measurement showed 4.79 s for exchange=binance&window=60, and one attempt returned no response before succeeding on retry.
  • updatedAt is an ISO 8601 string here, not epoch ms.
▸Response fields(14)
movers[]array
Ranked rows, highest percentChange first, at most 250
movers[].symbolstring
Venue-native pair symbol
movers[].baseAssetstring
Base asset of that pair
movers[].currentPricenumber
Most recent stored price, in the pair's quote currency
movers[].priceAtnumber | null
When currentPrice was true, epoch ms: the exchange's own timestamp for that price (its event time, or for a REST sample the time the price last changed). Use this, not updatedAt, to tell how fresh a price is. Null when the stored sample carries no readable time
movers[].oldestPricenumber
First stored price inside the window, same currency
movers[].percentChangenumber
Change across the window, percent; 0 when the window held fewer than two samples
movers[].dataPointsnumber
Stored samples used for this row
windowMinutesnumber
Window that was applied, minutes
coverageMinutesnumber
History depth available for the venue's anchor symbol, minutes
exchangestring
Venue the ranking was built for
totalSymbolsnumber
Symbols in the full ranking before the 250-row cap
returnedCountnumber
Rows actually present in movers[]
updatedAtstring
When this response was sent, ISO 8601 string. Not the age of the prices: see priceAt
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/market/movers/all?exchange=binance_futures&window=60"
Response200
{
  "movers": [
    {
      "symbol": "KOMAUSDT",
      "baseAsset": "KOMA",
      "currentPrice": 0.017505,
      "oldestPrice": 0.016683,
      "percentChange": 4.9272,
      "dataPoints": 115
    },
    {
      "symbol": "ILVUSDT",
      "baseAsset": "ILV",
      "currentPrice": 3.74,
      "oldestPrice": 3.607,
      "percentChange": 3.6873,
      "dataPoints": 112
    }
  ],
  "windowMinutes": 60,
  "coverageMinutes": 1500,
  "exchange": "binance_futures",
  "totalSymbols": 761,
  "updatedAt": "2026-09-12T19:50:53.153Z",
  "returnedCount": 250
}

movers[] truncated to 2 of the 250 rows returned

GET/public/market/movers/sparks5 credits120/min

Mover trend lines

The sampled price path behind the movers board, for a list of markets you name. Pair it with /public/market/movers/all to draw a line on each row of a page. The lines come from the same one-sample-a-minute price history the movers' percent change is computed from, so they exist on every movers venue, including the ones with no candle data.

Query parameters

symbolsstringrequired
Comma-separated venue-native symbols from that venue's movers list, at most 50. Upper-cased and de-duplicated server-side. A symbol the venue does not list is dropped silently rather than rejected.
exchangeenumoptionaldefault binance_futures
Venue the symbols belong to, lower-cased server-side; the same allowlist as /public/market/movers
binancebinance_futuresbitgetbybitbybit_futurescoinbasegateiohuobikrakenkraken_futureskucoinmexcokxokx_futures
windowenumoptionaldefault 15
Movers window in minutes; any other number returns 400
151530602401440

Status and edge cases

  • No symbols parameter, or an empty one, returns 400 "symbols is required (comma-separated)". A repeated symbols parameter is not an error: symbols=BTCUSDT&symbols=ETHUSDT returned both lines, like the comma form. Both verified live.
  • More than 50 symbols returns 400 "At most 50 symbols per request". Verified with 51.
  • A symbol containing whitespace, a control character or any of * ? [ ] \ returns 400 "Invalid symbol" and fails the whole request. Verified: BTC*USDT.
  • An unlisted exchange or window returns 400 with the allowed values in the message. Verified: window=10.

Notes

  • Membership is checked against the venue's own movers list, so an unknown, delisted or misspelled symbol simply has no key in sparks. Compare the keys you get back with the list you sent.
  • The line and the percentage agree by construction: the last point is pinned to the row's currentPrice and, when spanMinutes equals windowMinutes, the first point to its oldestPrice.
  • Points per line: 30 on the 1 and 5 minute windows, 15 on 15, 30 on 30, and 48 on 60, 240 and 1440. The history holds one sample a minute, so a line never has more points than its span has minutes.
  • Symbols are venue-native and not always ASCII: binance_futures lists perps whose names are Chinese characters followed by USDT. Percent-encode the list.
  • Venue keys here are the movers' underscore spellings (binance_futures), not the hyphenated ids of the board and candle routes.
  • Lines are memoised per venue, window and market for about 35 seconds, the lifetime of the movers ranking they belong to. There is no updatedAt; the lines describe the same snapshot as /public/market/movers/all.
▸Response fields(5)
exchangestring
Venue the lines were read for
windowMinutesnumber
Window that was applied, minutes
spanMinutesnumber
Minutes each line covers. Equal to windowMinutes, except on the 1 and 5 minute windows, whose lines cover the last 30 minutes
sparksobject
Map of symbol to line. Only symbols in the venue's movers list with at least two samples appear
sparks.<symbol>[]number
Price path, oldest first, at most 48 points, in the pair's quote currency. The last point is the market's currentPrice on /public/market/movers/all for the same exchange and window
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/market/movers/sparks?exchange=binance_futures&window=60&symbols=BTCUSDT,ETHUSDT,NOTAMARKET"
Response200
{
  "exchange": "binance_futures",
  "windowMinutes": 60,
  "spanMinutes": 60,
  "sparks": {
    "BTCUSDT": [83883.6, 83883.6, 83870.6, 83733.4],
    "ETHUSDT": [2694.29, 2694.27, 2693.14, 2687.89]
  }
}

sparks.BTCUSDT and sparks.ETHUSDT each truncated to 4 of 48 points. NOTAMARKET has no key because binance_futures lists no such market.

GET/public/market/compare/{symbol}5 credits300/min

Cross-exchange price

Reads the last cached price for one trading pair on every venue in the ingest set and returns them sorted cheapest first, with the spread between the cheapest and most expensive comparable quotes. Every price is also scored against the cross-venue median: one that disagrees with the other venues is flagged as an outlier, and one that has stood at the same price for 15 minutes or more while the other venues moved is flagged as unchanged; both are left out of the spread rather than dropped, and every checked venue with no usable price is named with the reason. This route serves cached prices only and never triggers an on-demand exchange fetch.

Path parameters

symbolstringrequired
Full trading pair such as BTCUSDT; upper-cased then matched against ^[A-Z0-9]{2,30}$, otherwise 400

Status and edge cases

  • A symbol under 2 characters, over 30, or containing anything but A-Z and 0-9 returns 400 "Malformed symbol".
  • An unknown symbol returns 200 with prices: [], spreadPercent: null and exchangesWithPrice: 0, not a 404. Verified: /compare/NOTACOINXYZ and /compare/BT.
  • Lowercase input is accepted and normalised: /compare/btcusdt returned the BTCUSDT comparison.

Notes

  • symbol is a full pair, not a base asset. Comparing BTC rather than BTCUSDT returns an empty prices array.
  • Aliases are canonicalised before the lookup, so the response symbol can differ from what you sent: /compare/XBTUSD returned symbol BTCUSD, meta.requestedSymbol XBTUSD and 18 rows. Match on meta.requestedSymbol if you need your own input back.
  • Only prices 15 seconds old or newer enter spreadPercent. Prices between 15 and 60 seconds are still returned and counted in delayedShown. Older ones are dropped and counted in staleFiltered.
  • A price is an outlier when it sits more than max(0.5 percent, 5 x the median absolute deviation) from the median of the comparable prices; both constants are deployment settings, so treat them as the defaults. The test needs at least 4 comparable venues. Below that nothing is flagged, meta.medianPrice is null and every medianDeviationPercent is null.
  • A price is unchanged when its venue's one-a-minute price history shows the same value for at least 15 minutes while the median of the other venues' price ranges over that span is at least 0.2 percent, and at least 3 of that venue's own price steps. It needs 3 other venues with history. Durations are read from up to 30 samples, so a longer stand reads about 30 minutes. These constants are deployment settings; treat them as the defaults.
  • meta.unavailable names every checked venue missing from prices[], so exchangesChecked equals prices.length plus unavailable.length (45 + 10 = 55 for BTCUSDT on 2026-09-30). A venue whose quote aged past maxAgeMs is listed there as too_old and is also counted in staleFiltered.
  • sort (asc), maxAgeMs (60000), limit and offset are pinned server-side and cannot be set from the query.
  • liveFetched is always 0 on this route: cachedOnly is pinned so an anonymous call can never trigger an outbound exchange fetch.
  • The venue set here is the full ingest list (55 checked for BTCUSDT on 2026-09-30) and is not the same as the 14-venue movers allowlist.
  • This route is 300/min on the market-heavy bucket: each call is one cached read per venue, never an exchange fetch.
▸Response fields(32)
symbolstring
Canonical symbol the comparison was built on: the upper-cased input with asset aliases mapped, so /compare/XBTUSD returns BTCUSD. The raw upper-cased input is echoed as meta.requestedSymbol
updatedAtnumber
Newest prices[].updatedAt across the returned rows, epoch ms: when our cache last wrote one of these prices, not when the request ran. Falls back to request time only when prices[] is empty
spreadPercentnumber|null
(highest - lowest) / lowest across comparable prices (15 seconds old or newer, and flagged neither outlier nor unchanged), percent; null with fewer than 2
prices[]array
One row per venue holding a price, sorted by price ascending
prices[].exchangestring
Venue key
prices[].nativeSymbolstring
The venue's own spelling of the market the price came from, e.g. XBTUSDTM on kucoin_futures or btcusdt on bitstamp. Absent when the cache holds no spelling
prices[].pricenumber
Last cached price on that venue, in the pair's quote currency
prices[].timestampnumber
Exchange's own tick time, epoch ms
prices[].updatedAtnumber
When our cache wrote that venue's price, epoch ms; distinct from timestamp, and the top-level updatedAt is the max of these
prices[].sourcestring
websocket or rest-api
prices[].ageMsnumber
Age of the tick at response time, milliseconds
prices[].freshnessStatusstring
live under 3s, fresh under 15s, stale under 60s, offline beyond
prices[].qualitystring
ok; outlier when the price sits too far from the median of the comparable prices to be the same market; unchanged when it has stood at one exact price for 15 minutes or more while the other venues moved. Both are still returned, but are excluded from spreadPercent
prices[].medianDeviationPercentnumber|null
Signed distance from meta.medianPrice, percent; null when too few venues were comparable to compute a median
prices[].unchangedForMsnumber|null
How long this exact price has stood, from the venue's one-a-minute price history, milliseconds. A lower bound: no change in at least this long. null when no history was written for this market in the last few minutes
prices[].peerMovePercentnumber|null
For a price unchanged 15 minutes or more: the median price range of the other venues over that same span, percent. null for every other price
meta.requestedSymbolstring
Upper-cased input before alias canonicalisation
meta.sortstring
Price sort applied, always asc on this route
meta.maxAgeMsnumber
Staleness cutoff applied, milliseconds, always 60000 on this route
meta.exchangesCheckednumber
Venues inspected for this symbol
meta.exchangesWithPricenumber
Venues that had a usable cached price, before the staleness cutoff
meta.staleFilterednumber
Venues whose cached price was older than maxAgeMs and were dropped from prices[]
meta.spreadBasisCountnumber
Prices fresh enough (15s or newer) to count toward spreadPercent
meta.delayedShownnumber
Prices returned but excluded from the spread because they are 15-60s old
meta.liveFetchednumber
Venues refreshed by an on-demand fetch, always 0 on this route
meta.outlierExcludednumber
Comparable prices left out of spreadPercent for disagreeing with the other venues
meta.unchangedExcludednumber
Comparable prices left out of spreadPercent for standing at one price while the other venues moved
meta.medianPricenumber|null
Median of the comparable prices the outlier test ran against, unchanged prices left out; null with fewer than 4 comparable venues
meta.unavailable[]array
Every checked venue that returned no usable price for this pair
meta.unavailable[].exchangestring
Venue key
meta.unavailable[].reasonstring
no_price when nothing is cached for this pair on that venue (it may not list it); too_old when a quote exists but is older than maxAgeMs
meta.unavailable[].ageMsnumber
Age of the filtered quote, milliseconds; present only when reason is too_old
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/market/compare/BTCUSDT"
Response200
{
  "symbol": "BTCUSDT",
  "updatedAt": 1790769063572,
  "spreadPercent": 0.32278940490263186,
  "prices": [
    {
      "exchange": "bitstamp",
      "nativeSymbol": "btcusdt",
      "price": 83735.71,
      "timestamp": 1790769053000,
      "updatedAt": 1790769054673,
      "source": "rest-api",
      "ageMs": 10743,
      "freshnessStatus": "fresh",
      "quality": "ok",
      "medianDeviationPercent": -0.1577359660418677,
      "unchangedForMs": 0,
      "peerMovePercent": null
    },
    {
      "exchange": "kucoin_futures",
      "nativeSymbol": "XBTUSDTM",
      "price": 83815.2,
      "timestamp": 1790769057171,
      "updatedAt": 1790769057656,
      "source": "rest-api",
      "ageMs": 6572,
      "freshnessStatus": "fresh",
      "quality": "ok",
      "medianDeviationPercent": -0.06295607383030824,
      "unchangedForMs": 0,
      "peerMovePercent": null
    }
  ],
  "meta": {
    "requestedSymbol": "BTCUSDT",
    "sort": "asc",
    "maxAgeMs": 60000,
    "exchangesChecked": 55,
    "exchangesWithPrice": 45,
    "staleFiltered": 0,
    "spreadBasisCount": 42,
    "delayedShown": 3,
    "liveFetched": 0,
    "outlierExcluded": 0,
    "unchangedExcluded": 0,
    "medianPrice": 83868,
    "unavailable": [
      {
        "exchange": "bitbank",
        "reason": "no_price"
      },
      {
        "exchange": "bitflyer",
        "reason": "no_price"
      }
    ]
  }
}

prices[] truncated to 2 of 45 rows and meta.unavailable[] to 2 of 10

02

Market cap

3 endpoints

The CoinMarketCap-sourced snapshot the site's own boards read from.

GET/public/market-cap5 credits120/min

Coins by market cap

Returns the cached CoinMarketCap snapshot the site enriches its boards from, one row per base asset, sorted by market-cap rank. Prices are live wherever an exchange we ingest quotes the coin (priceSource says which rows); every other field comes from an hourly CoinMarketCap poll, so read meta.updatedAt for that clock. Always send a limit: the default is the 1500-row server cap, which returns the whole snapshot (664 rows, 645 KB on 2026-09-30).

Query parameters

limitintegeroptionaldefault 1500
Maximum rows to return, clamped to 1500. Fractions floor (2.7 returns 2 rows). Values that are not a finite number greater than 0 (0, -5, abc) are not errors: they fall through to the 1500 cap.

Status and edge cases

  • limit has no 4xx path: 0, -5, abc and 99999 all return 200 with the capped list.
  • Over 120 requests per minute returns 429; the 429 body and Retry-After were not exercised.
  • A browser fetch from a non-allowlisted Origin returns 500 {"statusCode":500,"message":"An unexpected error occurred","error":"Internal Server Error","timestamp":"2026-09-12T20:15:43.175Z","path":"/public/market-cap?limit=1"} instead of a CORS rejection. Verified live with Origin: https://example.com.

Notes

  • count and meta.count are the total rows in the snapshot, not the rows returned: ?limit=5 returns count 664 with coins.length 5.
  • Always pass limit. With no limit the response is the full 664-row snapshot, 645 KB on 2026-09-30.
  • base is the join key; symbol is not unique. 664 distinct bases map to 652 distinct symbols.
  • Twelve rows duplicate another row: each pair shares one cmcId and repeats marketCap and rank verbatim (price can differ, because the two rows can take it from different sources): SHIB/1000SHIB, PEPE/1000PEPE, LUNC/1000LUNC, BONK/1000BONK, FLOKI/1000FLOKI, XEC/1000XEC, CHEEMS/1000CHEEMS, MOG/1000000MOG, SATS/1000SATS, BEAM/BEAMX, RON/RONIN, LUNA/LUNA2. Deduplicate by cmcId before summing market cap or counting coins; filtering on a "1000" prefix still double counts BEAM, RON and LUNA. 1MBABYDOGE is an alias base key with no parent row, so it is not a duplicate.
  • Five base keys are non-ASCII (Chinese-character meme tickers). They appear here but cannot be fetched from /public/market-cap/{symbol}.
  • Percent-change fields are percent, not ratios. Money fields are USD.
  • price is the only field with a live clock. On 2026-09-30, 639 of 664 rows had priceSource venue and 25 had cmc, among them the 1000-prefixed alias rows such as 1000SHIB and 1000PEPE. marketCap, volume24h and every percent change stay on the hourly CoinMarketCap poll, so on a venue-priced row price and percentChange24h come from different clocks.
  • dateAdded and lastUpdated are ISO 8601 strings; meta.updatedAt is epoch ms.
  • Three of the 664 rows carried rank null on 2026-09-30 (CROSS, STAMP, STANDARD), each with marketCap 0. Null-rank rows sort last.
  • meta is nullable. With an unwritten or empty cache the route returns meta null, count 0 and coins [] at 200 (read from source; every live call returned a populated meta).
  • The guarded route's search parameter is not exposed here. Unknown query params are ignored.
  • Server-side only: a browser request carrying an Origin outside the site allowlist is rejected with 500, not a CORS error.
  • The 120/min market-medium budget is counted per handler, not shared across the three market-cap routes. Measured in one 60s window, x-ratelimit-remaining-market-medium read 112 on /public/market-cap, 118 on /public/market-cap/narratives and 115 on /public/market-cap/BTC, each with its own reset.
▸Response fields(16)
metaobject|null
Snapshot header. null when the cache is empty, which also gives count 0 and coins []
meta.updatedAtnumber
When the snapshot was written, epoch ms
meta.countnumber
Total coins in the snapshot, not the number of rows returned
meta.sourcestring
Upstream provider, "coinmarketcap" on every observed call
countnumber
Total coins available; equals meta.count, not coins.length
coins[]array
Rows sorted by rank ascending, truncated to limit. Each row carries 29 fields
coins[].basestring
Uppercase join key, unique across the list; the key the single-coin route takes
coins[].symbolstring
CoinMarketCap ticker; not unique and may differ in case from base (USDe, XAUt)
coins[].pricenumber
Per-unit USD: a live exchange price when priceSource is venue, otherwise CoinMarketCap's hourly quote
coins[].priceSourcestring
venue when price is a live exchange tick for this coin, seconds to a minute old; cmc when it is CoinMarketCap's quote from the hourly poll, either because no exchange we ingest quotes the coin or because the exchange price disagreed with CoinMarketCap's by too much to be the same asset
coins[].marketCapnumber
Circulating market cap, USD
coins[].volume24hnumber|null
Rolling 24h traded value, USD
coins[].percentChange24hnumber|null
24h price change in percent (-0.082 means -0.082%)
coins[].ranknumber|null
CoinMarketCap market-cap rank; not unique because of duplicate rows, and null on 3 of 664 rows
coins[].tagsarray
CoinMarketCap tag names in Title Case, or null (2 of 664 rows)
coins[].logostring|null
CDN logo URL; null on the 1 of 664 rows (CARDS on 2026-09-30) that has no CMC info record
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/market-cap?limit=25"
Response200
{
  "meta": {
    "updatedAt": 1790765797100,
    "count": 664,
    "source": "coinmarketcap"
  },
  "count": 664,
  "coins": [
    {
      "base": "BTC",
      "symbol": "BTC",
      "name": "Bitcoin",
      "cmcId": 1,
      "price": 83899.68,
      "marketCap": 1686009304342.6064,
      "fdv": 1762299326087.97,
      "circulatingSupply": 20090909,
      "totalSupply": 20090909,
      "maxSupply": 21000000,
      "rank": 1,
      "volume24h": 26600868954.0199,
      "volumeChange24h": -20.9901,
      "percentChange1h": 0.38848125,
      "percentChange24h": -0.12943136,
      "percentChange7d": -2.23314476,
      "percentChange30d": 6.71413111,
      "percentChange60d": 33.21891835,
      "percentChange90d": 37.1767655,
      "marketCapDominance": 58.6572,
      "tvl": null,
      "numMarketPairs": 12753,
      "dateAdded": "2010-07-13T00:00:00.000Z",
      "tags": ["Mineable", "PoW"],
      "infiniteSupply": false,
      "platform": null,
      "lastUpdated": "2026-09-30T10:54:59.000Z",
      "priceSource": "venue",
      "logo": "https://s2.coinmarketcap.com/static/img/coins/64x64/1.png"
    }
  ]
}

coins[] truncated to 1 of the 25 rows returned; that row's tags[] truncated to 2 of 37

Data from CoinMarketCap

GET/public/market-cap/{symbol}1 credit120/min

Market cap for a coin

Returns one coin's snapshot row together with its CoinMarketCap profile: logo, description, category and project links. An unknown coin is a 200 with found:false, not a 404, so branch on the body. The path segment is the base key from /public/market-cap, not necessarily the display ticker.

Path parameters

symbolstringrequired
Base asset key, case-insensitive and upper-cased server-side (eth resolves to ETH). Must match ^[A-Za-z0-9]{1,20}$; anything else, including BTC-USD and the non-ASCII base keys, returns 400 "Invalid symbol".

Status and edge cases

  • A symbol outside ^[A-Za-z0-9]{1,20}$ returns 400 {"statusCode":400,"message":"Invalid symbol","error":"Bad Request","timestamp":"2026-09-12T20:15:42.593Z","path":"/public/market-cap/BTC-USD"}. Verified on BTC-USD and on a non-ASCII base.
  • An unknown but well-formed symbol returns 200 with found:false, entry null and info null, never 404. Verified on ZZZNOTACOIN.
  • Over 120 requests per minute returns 429; the 429 body was not exercised.
  • A browser fetch from a non-allowlisted Origin returns 500, not a CORS rejection.

Notes

  • An unknown coin is 200 with found:false and entry/info null. Branch on found, never on the status code.
  • The path segment is the base key from /public/market-cap, not the CMC ticker. 1000SHIB resolves and returns symbol SHIB; the five non-ASCII base keys in the list are unreachable here because of the charset guard.
  • found:true does not imply info. A coin with no CoinMarketCap profile record returns a populated entry with info null; 1 of 664 coins was in that state on 2026-09-30 (CARDS).
  • entry carries neither base nor logo: /public/market-cap adds both to its rows and this route returns the raw 27-field entry. Join back onto the list with the envelope's base, and read the image from info.logo.
  • entry.lastUpdated is an ISO 8601 string while the envelope's updatedAt is epoch ms.
  • narratives is routed ahead of this parameter, so /public/market-cap/narratives is always the sector board and can never be a coin lookup. Do not use it as a symbol example.
  • Server-side only: a browser request carrying an Origin outside the site allowlist is rejected with 500, not a CORS error.
▸Response fields(15)
basestring
The upper-cased key that was looked up, echoed back
foundboolean
Whether the snapshot holds this base; false leaves entry and info null
entryobject
The snapshot row, 27 fields: the same fields as coins[] on /public/market-cap minus base and logo, which that route adds to its rows. null when found is false
entry.pricenumber
Per-unit USD: a live exchange price when entry.priceSource is venue, otherwise CoinMarketCap's hourly quote
entry.priceSourcestring
venue or cmc, with the same meaning as on /public/market-cap
entry.marketCapnumber
Circulating market cap, USD
entry.ranknumber|null
CoinMarketCap market-cap rank
entry.percentChange24hnumber|null
24h price change in percent
entry.tagsarray
CoinMarketCap tag names in Title Case, or null
entry.lastUpdatedstring|null
Provider quote timestamp, ISO 8601 string
infoobject
CoinMarketCap profile record; null for coins with no profile even when found is true
info.logostring|null
CDN logo URL; the only place a logo appears on this route
info.descriptionstring|null
Provider-written project blurb, several hundred characters
info.websitestring|null
Project homepage URL; twitter, reddit, explorer, sourceCode and technicalDoc follow the same string-or-null shape
updatedAtnumber|null
Snapshot write time, epoch ms; stays populated when found is false
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/market-cap/BTC"
Response200
{
  "base": "BTC",
  "found": true,
  "entry": {
    "symbol": "BTC",
    "name": "Bitcoin",
    "cmcId": 1,
    "price": 83899.68,
    "priceSource": "venue",
    "marketCap": 1686009304342.6064,
    "fdv": 1762299326087.97,
    "circulatingSupply": 20090909,
    "maxSupply": 21000000,
    "rank": 1,
    "volume24h": 26600868954.0199,
    "percentChange24h": -0.12943136,
    "percentChange7d": -2.23314476,
    "marketCapDominance": 58.6572,
    "tags": ["Mineable", "PoW"],
    "lastUpdated": "2026-09-30T10:54:59.000Z"
  },
  "info": {
    "cmcId": 1,
    "logo": "https://s2.coinmarketcap.com/static/img/coins/64x64/1.png",
    "description": "Bitcoin (BTC) is a cryptocurrency launched in 2010.",
    "category": "coin",
    "website": "https://bitcoin.org/",
    "twitter": null,
    "reddit": "https://reddit.com/r/bitcoin",
    "explorer": "https://blockchain.info/",
    "sourceCode": "https://github.com/bitcoin/bitcoin",
    "technicalDoc": "https://bitcoin.org/bitcoin.pdf"
  },
  "updatedAt": 1790765797100
}

entry shown with 16 of its 27 fields (the omitted ones are volumeChange24h, percentChange1h/30d/60d/90d, totalSupply, tvl, numMarketPairs, dateAdded, infiniteSupply, platform); entry.tags truncated to 2 of 37; info.description truncated to its first sentence

Data from CoinMarketCap

GET/public/market-cap/narratives1 credit120/min

Narratives board

Groups the cached market-cap snapshot by a curated allowlist of 54 CoinMarketCap tags under 45 sector names and rolls up each sector's 24h moves, best average first. The average is equal-weighted across member coins, so a microcap moves a sector as much as a megacap. coins[] holds only the top 12 members; coinCount is the full membership.

Parameters

None. Everything this endpoint returns is pinned server-side.

Status and edge cases

  • No parameters and no 4xx path; every observed call returned 200.
  • meta and updatedAt are typed nullable and would be null with an empty cache, leaving narratives empty at 200. Not observed live, so treat it as unverified rather than expected.
  • Over 120 requests per minute returns 429; the 429 body was not exercised.
  • A browser fetch from a non-allowlisted Origin returns 500, not a CORS rejection.

Notes

  • coins[] is capped at 12 members per sector. Use coinCount for membership, never coins.length: the largest sector on 2026-09-30 had coinCount 200 with 12 rows.
  • 54 allowlisted tags collapse to 45 labels, and tags that share a label form one sector. CoinMarketCap's "DEX" and "Decentralized Exchange (DEX) Token" tags are one DEX sector under tag decentralized-exchange-dex-token, and a coin carrying both counts once. Key by tag.
  • Sectors with fewer than 3 qualifying members are dropped; coins with no tags or no 24h change are skipped entirely.
  • A coin lands in every allowlisted sector its tags match, so sectors overlap and totalMarketCap double counts across the board.
  • A coin listed under two exchange tickers (SHIB and 1000SHIB, RON and RONIN) is one CoinMarketCap entry and counts once in each sector, under CoinMarketCap's own symbol.
  • The average is equal-weighted, not market-cap weighted.
  • avgPct24h and medianPct24h are rounded to 2 decimals; the per-coin percentChange24h values are not rounded.
  • Only curated tags are surfaced. Ecosystem tags (ethereum-ecosystem and similar) and portfolio tags are excluded by design, so this is not a full CMC tag dump.
  • Takes no parameters: the 3-member floor and the 12-coin cap are fixed server-side.
  • Server-side only: a browser request carrying an Origin outside the site allowlist is rejected with 500, not a CORS error.
▸Response fields(15)
meta.updatedAtnumber
When the underlying coin snapshot was written, epoch ms
meta.countnumber
Coins in the underlying snapshot (664 on 2026-09-30), not the number of narratives
meta.sourcestring
Upstream provider, "coinmarketcap"
updatedAtnumber|null
Copy of meta.updatedAt, epoch ms
countnumber
Number of narratives returned (41 on 2026-09-30)
narratives[]array
Sectors sorted by avgPct24h descending
narratives[].tagstring
Canonical tag slug; the unique key for a sector. A sector that joins near-identical tags keeps one of their slugs
narratives[].labelstring
Display name, unique: tags that share a label form one sector
narratives[].coinCountnumber
Members with a 24h value, i.e. what the average is over; up to 200 on 2026-09-30
narratives[].avgPct24hnumber
Equal-weighted mean of member 24h changes, percent, rounded to 2 decimals
narratives[].medianPct24hnumber
Median member 24h change, percent, rounded to 2 decimals
narratives[].upCountnumber
Members with a 24h change above 0; downCount is the count below 0, and the two need not sum to coinCount
narratives[].totalMarketCapnumber
Sum of member market caps, USD
narratives[].topMoverobject
Biggest 24h gainer in the sector: base, name, percentChange24h, marketCap
narratives[].coins[]array
Up to 12 members sorted by 24h change descending, each with base, name, percentChange24h (percent), marketCap (USD)
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/market-cap/narratives"
Response200
{
  "meta": {
    "updatedAt": 1789241152122,
    "count": 774,
    "source": "coinmarketcap"
  },
  "updatedAt": 1789241152122,
  "count": 44,
  "narratives": [
    {
      "tag": "defai",
      "label": "DeFAI",
      "coinCount": 8,
      "avgPct24h": 6.14,
      "medianPct24h": 1.31,
      "upCount": 7,
      "downCount": 1,
      "totalMarketCap": 134344171.24894056,
      "topMover": {
        "base": "GRIFFAIN",
        "name": "GRIFFAIN",
        "percentChange24h": 47.0494076,
        "marketCap": 16156912.99652149
      },
      "coins": [
        {
          "base": "GRIFFAIN",
          "name": "GRIFFAIN",
          "percentChange24h": 47.0494076,
          "marketCap": 16156912.99652149
        }
      ]
    }
  ]
}

narratives[] truncated to 1 of 44; that narrative's coins[] truncated to 1 of 8

Data from CoinMarketCap

03

Funding

5 endpoints

Perpetual funding across eight venues, every rate normalized to a common 8-hour basis so venues settling at 1h, 4h and 8h are directly comparable.

GET/public/funding/all5 credits300/min

All funding rates

Returns one row per perpetual contract on a single futures venue, carrying the venue's native rate and the same rate normalized to an 8-hour basis. Venues settle on different intervals (1h, 4h and 8h all appear on binance_futures), so rank and compare on normalizedRate8hPercent, never on ratePercent.

Query parameters

exchangeenumoptionaldefault binance_futures
Futures venue to read. Case-sensitive and exact; an unknown value, a mis-cased value, an empty value or a repeated parameter all return 400.
binance_futuresbybit_futuresokx_futuresbitget_futuresgateio_futureskucoin_futureshuobi_futuresbingx_futures

Status and edge cases

  • Unknown, mis-cased, empty or repeated exchange returns 400 {"statusCode":400,"message":"Unknown funding exchange","error":"Bad Request","timestamp":"2026-09-12T20:15:56.129Z","path":"/public/funding/all?exchange=nope"}. Every 4xx and 5xx in this group carries that same five-key envelope, with path echoing the request path and query string.
  • A browser request from an origin outside the CORS allowlist returns 500, not a CORS error. Verified with Origin: https://example.com. Call this server-side.
  • A venue with nothing cached returns 200 with rates: [] and totalSymbols: 0, not a 404 (read from source; not reproduced live).

Notes

  • Rows are sorted by the NATIVE rate, which mixes 1h, 4h and 8h settlement. Re-sort on normalizedRate8hPercent before ranking.
  • exchange is case-sensitive: exchange=BINANCE_FUTURES returns 400 while exchange=binance_futures returns 200.
  • Sending the parameter twice returns 400: the handler receives an array, which is not on the allowlist.
  • bitmex_futures was REMOVED from the allowlist on 2026-09-19: BitMEX shut down entirely on 2026-09-23 04:00 UTC. It had already thinned to 2 symbols (BTCUSDT, ETHUSDT) when measured 2026-09-12 while the other eight carried 341-981 (binance 863, bybit 765, okx 464, bitget 787, gateio 981, kucoin 677, huobi 341, bingx 968).
  • Top-level updatedAt is an ISO 8601 string for the snapshot build; per-row updatedAt is epoch ms for ingestion. Do not treat them as the same clock.
  • Responses come from a short server-side cache (35s default, env-tunable): three consecutive calls returned an identical updatedAt.
  • No pagination and no limit parameter. binance_futures returned 245 KB.
▸Response fields(16)
rates[]array
One entry per perpetual contract, sorted by the native rate descending
rates[].symbolstring
Venue contract symbol, e.g. BNCUSDT
rates[].baseAssetstring
Base asset parsed from the symbol by stripping a known quote suffix
rates[].canonicalstring|null
One display name for the contract across venues, e.g. BINANCE:PHAROSUSDT.P, in the format documented on /public/fast-search/markets. Display only: the other funding routes take symbol. null where the venue publishes no instrument catalogue (bitget_futures, kucoin_futures, bingx_futures) or the contract is missing from it, mostly tokenised equities, commodities and index products (219 of 779 binance_futures rows on 2026-09-30)
rates[].ratenumber
Native funding rate as a ratio for one funding interval
rates[].ratePercentnumber
Native rate in percent for one funding interval
rates[].fundingIntervalHoursnumber
Settlement interval in hours; 1, 4 and 8 all appear
rates[].normalizedRateHourlynumber
Rate per hour as a ratio
rates[].normalizedRateHourlyPercentnumber
Rate per hour in percent (normalizedRateHourly x 100)
rates[].normalizedRate8hnumber
Rate per 8 hours as a ratio
rates[].normalizedRate8hPercentnumber
Rate per 8 hours in percent; the only cross-venue comparable figure
rates[].nextFundingTimenumber
Next settlement, epoch ms
rates[].updatedAtnumber
When this rate was ingested, epoch ms
exchangestring
Venue key echoed back
totalSymbolsnumber
Number of rows in rates[]
updatedAtstring
When the server built this snapshot, ISO 8601 string (not the venue's publish time)
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/funding/all?exchange=binance_futures"
Response200
{
  "rates": [
    {
      "symbol": "PHAROSUSDT",
      "baseAsset": "PHAROS",
      "canonical": "BINANCE:PHAROSUSDT.P",
      "rate": 0.00064758,
      "ratePercent": 0.06475800000000001,
      "fundingIntervalHours": 4,
      "normalizedRateHourly": 0.000161895,
      "normalizedRateHourlyPercent": 0.016189500000000002,
      "normalizedRate8h": 0.00129516,
      "normalizedRate8hPercent": 0.12951600000000002,
      "nextFundingTime": 1790769600000,
      "updatedAt": 1790769060012
    }
  ],
  "exchange": "binance_futures",
  "totalSymbols": 779,
  "updatedAt": "2026-09-30T11:51:03.783Z"
}

rates[] truncated to 1 representative row of 779

GET/public/funding/coin/{base}1 credit300/min

Funding for a coin

Returns the current funding rate on every venue leg for one base asset, the best short/long venue pair, a 30-day hourly series for a single primary venue, and 7d/30d stats over that series. A coin funded on one venue, or on several that all read the same rate, is answered like any other with a zero spread; the route returns 404 only when no tracked venue funds the coin. A size-multiplier contract counts toward the coin it expresses, so PEPE's legs include Binance's and Bybit's 1000PEPEUSDT, and asking for 1000PEPE returns the same legs.

Path parameters

basestringrequired
Base asset, e.g. BTC. Upper-cased before validation, so btc works; after upper-casing it must be 1–24 letters or digits in any script (币安人生 works), and anything else (BTC-USD, a 25-character string) returns 400.

Status and edge cases

  • A base that is not 1–24 letters or digits after upper-casing returns 400 "Malformed base asset" (BTC-USD, a base with a space, or a 25-character base). Until 2026-10-01 the rule was /^[A-Z0-9]{1,15}$/, which rejected funded bases such as 币安人生 and 龙虾.
  • 404 "No funding data for this coin" means no tracked venue funds the coin right now (a leg a venue lists but does not fund does not count). Until 2026-10-01 it also covered coins whose legs all read the same rate: DOGE, DOT and XMR returned 404 on 2026-09-30 at exactly 0.01% per 8h on every venue; those now return 200 with a zero spread.
  • 503 "Funding data is temporarily unavailable" means the API holds no funding data at all: an outage, not an answer about the coin. Retry it; do not treat it as a 404.
  • Both error bodies use the five-key envelope described on /public/funding/all: statusCode, message, error, timestamp, path.
  • A browser request from an origin outside the CORS allowlist returns 500, not a CORS error. Call this server-side.

Notes

  • spread.exchangeCount counts venue legs, not distinct exchanges. BTC returned 10 legs across 8 venues on 2026-09-30 because binance_futures and bingx_futures each list a USDT and a USDC perp.
  • history covers ONE venue: the first of binance_futures, bybit_futures, okx_futures, bitget_futures, gateio_futures, kucoin_futures, huobi_futures, bingx_futures that lists the coin, and on it the USDT perp when it lists more than one. It is chosen by venue, never by rate, so it does not move between reads, and it is not a blend across venues.
  • history.points are roughly hourly and capped at 30 days; BTC returned 743 points.
  • A size-multiplier contract is filed under the coin it expresses: 1000PEPE under PEPE, 10000SATS under SATS, and Bybit's suffix form SHIB1000 under SHIB. Compare their rates 1:1, since funding is a percentage of the position, but never their prices: a 1000PEPE contract trades at about 1000 times PEPE.
  • The merge is skipped when one venue lists two of the contracts side by side. binance_futures and bitget_futures list both CATUSDT and 1000CATUSDT, which are different coins sharing a ticker, so CAT and 1000CAT each return only their own legs.
  • /public/funding/spread does not merge: 1000PEPE and PEPE are separate rows there, the way funding-spread alerts pair contracts, so a coin's spread here can differ from its row there.
  • stats.d7 and stats.d30 are computed only from history.points, so they describe that one venue and are null when the window is empty.
  • dataAt is epoch ms and is the timestamp of the LAST history point, not the freshness of venues[]; read ratesAt for that. dataAt is null when the history series is empty, which happens for a coin that is funded but has no cached series, and also when the Redis history read fails, so parse it as number|null.
  • The response is cached per coin for 60s, and the set of funded legs behind it is re-read about every 35s.
  • This 30-day series is the only funding history on the public surface. GET /public/funding/history is a 404 and is deliberately not exposed.
▸Response fields(25)
basestring
Upper-cased base asset echoed back
venues[]array
One entry per venue leg, sorted by normalizedRate8hPercent descending; equal rates keep a fixed venue order
venues[].exchangestring
Venue key, e.g. okx_futures
venues[].symbolstring
Contract symbol on that venue. A multiplier contract keeps its own, so PEPE's Binance leg reads 1000PEPEUSDT
venues[].ratePercentnumber
Native rate in percent for one interval of THAT venue; not comparable across legs with different fundingIntervalHours
venues[].normalizedRate8hPercentnumber
Current rate per 8 hours in percent
venues[].fundingIntervalHoursnumber
That venue's settlement interval in hours
venues[].nextFundingTimenumber
Next settlement on that venue, epoch ms
spreadobject
Best short/long venue pair for this coin right now. When every leg reads the same rate, or there is only one leg, spread8hPercent and spreadAprPercent are 0 and shortExchange and longExchange name the same venue
spread.exchangeCountnumber
Number of venue LEGS in venues[], which can exceed the 8 venues
spread.shortExchangestring
Venue with the highest rate (short there to receive funding)
spread.shortRate8hPercentnumber
That venue's rate per 8 hours, percent
spread.longExchangestring
Venue with the lowest rate (long there to receive funding)
spread.longRate8hPercentnumber
That venue's rate per 8 hours, percent
spread.spread8hPercentnumber
Short leg minus long leg, percent per 8 hours
spread.spreadAprPercentnumber
The same gap annualized, percent
history.exchangestring
The single venue the series was read from
history.symbolstring
Contract symbol on history.exchange that the series belongs to
history.points[]array
Roughly hourly samples over the last 30 days, oldest first; empty when no cached series exists
history.points[].timestampnumber
Sample time, epoch ms
history.points[].normalizedRate8hPercentnumber
Rate per 8 hours in percent at that sample
stats.d7object|null
avg/min/max of normalizedRate8hPercent in percent plus count over 7d; null when the window holds no points
stats.d30object|null
avg/min/max of normalizedRate8hPercent in percent plus count over 30d; null when the window holds no points
dataAtnumber|null
Timestamp of the LAST history point, epoch ms; null when history.points[] is empty
ratesAtnumber|null
Freshest ingestion time across venues[], epoch ms: how old the current rates are; null when no leg carries one
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/funding/coin/BTC"
Response200
{
  "base": "BTC",
  "venues": [
    {
      "exchange": "okx_futures",
      "symbol": "BTCUSDT",
      "ratePercent": 0.01,
      "normalizedRate8hPercent": 0.01,
      "fundingIntervalHours": 8,
      "nextFundingTime": 1789286400000
    }
  ],
  "spread": {
    "exchangeCount": 11,
    "shortExchange": "okx_futures",
    "shortRate8hPercent": 0.01,
    "longExchange": "kucoin_futures",
    "longRate8hPercent": 0.0015,
    "spread8hPercent": 0.0085,
    "spreadAprPercent": 9.307500000000001
  },
  "history": {
    "exchange": "binance_futures",
    "symbol": "BTCUSDT",
    "points": [
      {
        "timestamp": 1786650723390,
        "normalizedRate8hPercent": 0.009647000000000001
      }
    ]
  },
  "stats": {
    "d7": { "avg": 0.00538602906976744, "min": 0.000862, "max": 0.01, "count": 172 },
    "d30": { "avg": 0.006796608344549101, "min": -0.00039999999999999996, "max": 0.01, "count": 743 }
  },
  "dataAt": 1789239549453,
  "ratesAt": 1789242600007
}

venues[] truncated to 1 of 11 and history.points[] to 1 of 743

GET/public/funding/board5 credits120/min

Funding board

A pre-shaped leaderboard for an overview panel. Everything is pinned in the controller: the venue is binance_futures, each side is 25 rows, and the spread list is the 12 widest cross-venue gaps. Rows are ranked on the 8-hour normalized rate, so contracts that settle every 1h or 4h are comparable with 8h ones.

Parameters

None. Everything this endpoint returns is pinned server-side.

Status and edge cases

  • A browser request from an origin outside the CORS allowlist returns 500, not a CORS error. Call this server-side.
  • No 4xx input path exists: the endpoint takes no parameters.

Notes

  • No parameters. The venue (binance_futures), both side limits (25) and the spread limit (12) are constants in the controller.
  • Ranking uses normalizedRate8hPercent, unlike /public/funding/all which sorts on the native rate. The same data in the two endpoints will therefore be in a different order.
  • aprPercent appears only on this endpoint; /public/funding/all does not carry it.
  • negative[] is ordered most negative first.
  • stale is always false. Judge freshness from dataAt instead.
  • dataAt is epoch ms here, while /public/funding/all.updatedAt is an ISO 8601 string. The names are near-identical across this group; check the type before parsing.
  • spreads[] carries the same phantom-leg risk as /public/funding/spread: 1 of the 12 rows measured on 2026-09-12 (CSOPSKHYNIX2L, a tokenized-equity perp) rested on a leg at exactly 0.
▸Response fields(17)
positive[]array
25 highest normalizedRate8hPercent rows on binance_futures, highest first
positive[].symbolstring
Contract symbol on binance_futures
positive[].baseAssetstring
Base asset parsed from the symbol
positive[].exchangestring
Always "binance_futures"; both leaderboards are single-venue
positive[].ratePercentnumber
Native rate in percent for one funding interval; not comparable across rows with different fundingIntervalHours (a 4h row's ratePercent is half its normalizedRate8hPercent)
positive[].normalizedRate8hPercentnumber
Rate per 8 hours in percent; the ranking key
positive[].aprPercentnumber
Annualized rate in percent (hourly rate x 8760 x 100)
positive[].fundingIntervalHoursnumber
Settlement interval in hours
positive[].nextFundingTimenumber
Next settlement, epoch ms
positive[].updatedAtnumber
Ingestion time for that row, epoch ms
negative[]array
25 lowest rows, most negative first; same object shape as positive[]
spreads[]array
12 widest cross-venue spreads; same shape as /public/funding/spread rows without venues[]
spreads[].spreadAprPercentnumber
Short leg minus long leg, annualized, percent
exchanges[]array
The 8 venue keys the spread scan reads; the leaderboards themselves are binance_futures only
totalSymbolsnumber
Symbols on binance_futures behind the ranking (863 measured)
dataAtnumber|null
Freshest per-row ingestion time, epoch ms; null when no row carries one
staleboolean
Hardcoded false; reserved and structurally incapable of being true
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/funding/board"
Response200
{
  "positive": [
    {
      "symbol": "ESPORTSUSDT",
      "baseAsset": "ESPORTS",
      "exchange": "binance_futures",
      "ratePercent": 0.088011,
      "normalizedRate8hPercent": 0.176022,
      "aprPercent": 192.74409,
      "fundingIntervalHours": 4,
      "nextFundingTime": 1789243200000,
      "updatedAt": 1789242600007
    }
  ],
  "negative": [
    {
      "symbol": "MTLUSDT",
      "baseAsset": "MTL",
      "exchange": "binance_futures",
      "ratePercent": -1.6237709999999999,
      "normalizedRate8hPercent": -1.6237709999999999,
      "aprPercent": -1778.0292449999997,
      "fundingIntervalHours": 8,
      "nextFundingTime": 1789257600000,
      "updatedAt": 1789242600007
    }
  ],
  "spreads": [
    { "baseAsset": "STORJ", "exchangeCount": 2, "shortExchange": "gateio_futures", "shortRate8hPercent": -2.0928, "longExchange": "bybit_futures", "longRate8hPercent": -4.371624000000001, "spread8hPercent": 2.2788240000000006, "spreadAprPercent": 2495.3122800000006 }
  ],
  "exchanges": ["binance_futures", "bybit_futures", "okx_futures", "bitget_futures", "gateio_futures", "kucoin_futures", "huobi_futures", "bingx_futures"],
  "totalSymbols": 863,
  "dataAt": 1789242600007,
  "stale": false
}

positive[] and negative[] truncated to 1 of 25 each, spreads[] to 1 of 12, and that spread row printed on one line

GET/public/funding/index1 credit300/min

Market funding index

A market-wide funding gauge sampled about every 15 minutes over a fixed trailing 24-hour window. The median APR is the robust headline; the average is dragged around by a handful of extreme perps and crosses zero in both directions. The window is hardcoded and cannot be changed by the caller.

Parameters

None. Everything this endpoint returns is pinned server-side.

Status and edge cases

  • A browser request from an origin outside the CORS allowlist returns 500, not a CORS error. Call this server-side.
  • An empty window returns 200 with points: [] and current: null, not a 404 (read from source; not reproduced live).
  • No 4xx input path exists: the endpoint takes no parameters.

Notes

  • There are no parameters. The 1440-minute window is hardcoded and any query string is ignored; the authenticated twin of this route accepts a window, this one does not.
  • Samples arrived every 15-16 minutes: 93 points covering 23.9 hours when measured 2026-09-12.
  • medianAprPercent pins to 10.95 whenever most perps sit at the 0.01% per 8h baseline (0.01 x 3 x 365); it held that value for all 93 samples. Read avgAprPercent for movement in the tail.
  • avgAprPercent swings through zero. Across those 93 samples it ranged -5.145 to +3.782 percent, with 47 of 93 negative, and current was -1.203. Do not assume a positive floor or chart it on a zero-based axis.
  • current is literally points[points.length - 1], not a fresh computation, so it carries that point's timestamp.
  • sampleCount moved between 5842 and 5902 across the window, so a shift in the index can be a change of constituents rather than repricing.
  • Served from a short server-side cache (35s default, env-tunable).
▸Response fields(11)
points[]array
Samples over the window, oldest first
points[].medianAprPercentnumber
Median annualized funding across the sampled perps, percent
points[].avgAprPercentnumber
Mean annualized funding across the same perps, percent; signed, frequently negative
points[].sampleCountnumber
Number of perp contracts in that sample
points[].timestampnumber
Sample time, epoch ms
currentobject|null
The last element of points[]; null when the window is empty
current.medianAprPercentnumber
Latest median annualized funding, percent
current.avgAprPercentnumber
Latest mean annualized funding, percent; signed, frequently negative
current.sampleCountnumber
Perp contracts in the latest sample
current.timestampnumber
Latest sample time, epoch ms
windowMinutesnumber
Always 1440; the window is pinned in the controller
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/funding/index"
Response200
{
  "points": [
    {
      "medianAprPercent": 10.950000000000001,
      "avgAprPercent": 3.6050514117289385,
      "sampleCount": 5902,
      "timestamp": 1789158069587
    },
    {
      "medianAprPercent": 10.950000000000001,
      "avgAprPercent": 2.7621903877142713,
      "sampleCount": 5902,
      "timestamp": 1789159030521
    }
  ],
  "current": {
    "medianAprPercent": 10.950000000000001,
    "avgAprPercent": -1.2034878978697647,
    "sampleCount": 5848,
    "timestamp": 1789243989343
  },
  "windowMinutes": 1440
}

points[] truncated to 2 of 93 samples

GET/public/funding/spread10 credits150/min

Cross-venue funding spreads

For each base asset with at least two venue legs whose rates are not all equal, this returns the most positive venue, the most negative venue, the gap between them on a common 8-hour basis, its annualized form, and every leg that was considered. The full response is about 600 KB with no pagination and no limit parameter.

Parameters

None. Everything this endpoint returns is pinned server-side.

Status and edge cases

  • A browser request from an origin outside the CORS allowlist returns 500, not a CORS error. Call this server-side.
  • No 4xx input path exists: the endpoint takes no parameters.
  • Transport-level drops were seen on repeated large pulls from one client; retry once before treating a failure as an outage.

Notes

  • About 600 KB per call (619,524 bytes measured), with no pagination and no limit parameter. Warm calls took 1.2-1.3 s; a cold cache has been measured at 8-10 s.
  • Do not read spreadAprPercent as an arbitrage return. 153 of 542 rows carried a leg at exactly 0 - a book the venue lists but does not actually fund - and the gap on those rows is manufactured by that zero. Filter out rows where shortRate8hPercent or longRate8hPercent is exactly 0.
  • A deny list of known frozen-zero legs already removes some of them, and it fails open: if that list is missing or expired, more zero legs reappear at the top of the ranking.
  • Not every row is a cryptocurrency. Tokenized equity perps (CSOPSKHYNIX2L, SAMSUNG, SKHYNIX, TENCENTHKD, MRVL) rank high and mostly sit on a zero leg.
  • baseAsset is derived by stripping a quote suffix (USDT, USDC, BUSD, FDUSD, EUR, USD, GBP, TRY, KRW, JPY, AUD, BRL, BTC, ETH, BNB) from the venue symbol, so BTCUSDT and BTCUSDC both fold into BTC and count as two legs.
  • Rows whose gap is zero are dropped entirely, not returned with a 0: on 2026-09-30 DOGE was absent because all eight venues priced it at exactly the 0.01% per 8h baseline.
  • The 2-venue-leg minimum is pinned in the controller and is not a query parameter.
  • Legs settle on different intervals (1h, 4h, 8h). Only the normalizedRate8hPercent and the spread figures are comparable; ratePercent is per that venue's own interval. In a live pull of 541 rows, 0 were out of descending order on normalizedRate8hPercent while 58 were out of order on ratePercent.
▸Response fields(19)
spreads[]array
One row per qualifying base asset, sorted by spreadAprPercent descending
spreads[].baseAssetstring
Base asset, parsed by stripping a quote suffix from each venue symbol
spreads[].exchangeCountnumber
Number of venue LEGS in venues[]; can exceed 9 when a venue lists both a USDT and a USDC perp
spreads[].shortExchangestring
Venue with the highest rate (short there to receive funding)
spreads[].shortRate8hPercentnumber
That venue's rate per 8 hours, percent
spreads[].longExchangestring
Venue with the lowest rate (long there to receive funding)
spreads[].longRate8hPercentnumber
That venue's rate per 8 hours, percent
spreads[].spread8hPercentnumber
Short leg minus long leg, percent per 8 hours
spreads[].spreadAprPercentnumber
The same gap annualized (x3 x365), percent; gross funding only, before fees, slippage and margin
spreads[].venues[]array
Every leg considered for the row, sorted by normalizedRate8hPercent descending (the normalized hourly rate), NOT by the native ratePercent
spreads[].venues[].exchangestring
Venue key for that leg, e.g. gateio_futures
spreads[].venues[].symbolstring
Contract symbol on that venue
spreads[].venues[].ratePercentnumber
Native rate in percent for one interval of THAT venue; not comparable across legs
spreads[].venues[].normalizedRate8hPercentnumber
Rate per 8 hours in percent; the sort key and the only cross-venue comparable figure
spreads[].venues[].fundingIntervalHoursnumber
That venue's settlement interval in hours; 1, 4 and 8 all appear
spreads[].venues[].nextFundingTimenumber
Next settlement on that venue, epoch ms
exchanges[]array
The 8 venue keys scanned
totalCoinsnumber
Number of rows in spreads[] (542 measured)
updatedAtstring
When the server built this snapshot, ISO 8601 string
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/funding/spread"
Response200
{
  "spreads": [
    {
      "baseAsset": "STORJ",
      "exchangeCount": 2,
      "shortExchange": "gateio_futures",
      "shortRate8hPercent": -2.0928,
      "longExchange": "bybit_futures",
      "longRate8hPercent": -4.371624000000001,
      "spread8hPercent": 2.2788240000000006,
      "spreadAprPercent": 2495.3122800000006,
      "venues": [
        {
          "exchange": "gateio_futures",
          "symbol": "STORJUSDT",
          "ratePercent": -0.2616,
          "normalizedRate8hPercent": -2.0928,
          "fundingIntervalHours": 1,
          "nextFundingTime": 1789243200000
        },
        {
          "exchange": "bybit_futures",
          "symbol": "STORJUSDT",
          "ratePercent": -0.5464530000000001,
          "normalizedRate8hPercent": -4.371624000000001,
          "fundingIntervalHours": 1,
          "nextFundingTime": 1789243200000
        }
      ]
    }
  ],
  "totalCoins": 542,
  "exchanges": ["binance_futures", "bybit_futures", "okx_futures", "bitget_futures", "gateio_futures", "kucoin_futures", "huobi_futures", "bingx_futures"],
  "updatedAt": "2026-09-12T19:50:57.531Z"
}

spreads[] truncated to 1 of 542 rows; that row's venues[] is complete (2 legs), and exchanges[] is printed on one line

04

Liquidations

5 endpoints

Forced closes as they print, aggregated, and clustered into cascades. Binance futures.

GET/public/liquidations/board1 credit120/min

Liquidation board

Combines the 24h aggregates, the tape, the cascades and an ingest heartbeat into a single snapshot sized for a dashboard. Every knob is a server constant: 20 rekt rows, 25 tape rows, a $25,000 tape preference and a 24h window. Use the stale flag rather than comparing timestamps yourself. Dollar figures are copied verbatim from the aggregates and tape, in USD.

Parameters

None. Everything this endpoint returns is pinned server-side.

Status and edge cases

  • Never 404s. If the ingest is down the response is 200 with stale: true and empty arrays.
  • market and largestPrint are null, not absent, when there is no data to summarise.

Notes

  • largestPrint is the largest among the 200 prints currently held, not the largest of the day. Nothing stores a daily maximum.
  • The $25,000 tape floor is a preference, not a filter: if fewer than 10 prints clear it the server falls back to the unfiltered tape. A live call returned a $15.65 print in tape[].
  • Every dollar figure is USD. Coin-margined contracts (ETHUSD_PERP, BTCUSD_PERP), whose quantities are contract counts and which once took the top rows at 250-800x their real notional, have not been collected since 2026-10-04.
  • baseAsset is a suffix strip, not a lookup. A contract whose name does not end in a quote currency keeps its full name, so a dated future such as BTCUSDT_251226 has baseAsset "BTCUSDT_251226". Do not key a coin lookup on it without handling that.
  • This route costs 120 requests per minute, not the 300 the other liquidation routes allow, and the buckets are per route so the budgets do not pool.
  • Check stale before rendering. A frozen snapshot otherwise looks identical to a live one.
  • rekt rows are the same aggregate rows as /aggregates?window=24h, minus lastTs. totalSymbols is that endpoint's count.
▸Response fields(14)
marketobject|null
Venue-wide totals: long5m, short5m, long1h, short1h, long24h, short24h (USD, same units as rekt[].total), count1h, updatedAt (epoch ms)
rekt[]array
The 20 most-liquidated symbols over 24h, largest total first; each has symbol, baseAsset, count, long, short, total, total24h, ratio1h
rekt[].symbolstring
Binance-futures contract symbol
rekt[].baseAssetstring
symbol with a trailing USDT, USDC, USD, BUSD, FDUSD or TUSD removed
rekt[].totalnumber
24h long + short liquidations for the symbol in USD; the sort key
rekt[].ratio1hnumber
Long share of the symbol's 1h liquidations, ratio 0 to 1; 0.5 when the symbol has no 1h data
tape[]array
Up to 25 recent prints, newest first; each has symbol, baseAsset, side, price, notionalUsd, ts
tape[].notionalUsdnumber
qty x price for the print, in USD
largestPrintobject|null
Print with the highest notionalUsd among the 200 held in memory, with symbol, baseAsset, side, notionalUsd and ts; null when the tape is empty
cascadesobject
active[] and recent[], identical to the /cascades response arrays
totalSymbolsnumber
Symbols with 24h liquidations above $1,000, before the 20-row cut
windowstring
Always the string "24h" on this endpoint
dataAtnumber|null
Epoch ms the market summary was last written; null when no summary exists
staleboolean
true when the ingest heartbeat or dataAt is missing or more than 120 seconds old
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/liquidations/board"
Response200
{
  "market": {
    "long5m": 127740,
    "short5m": 215603,
    "long1h": 446550,
    "short1h": 3820587,
    "long24h": 401271419,
    "short24h": 72571398,
    "count1h": 1295,
    "updatedAt": 1792094473790
  },
  "rekt": [
    {
      "symbol": "ETHUSDT",
      "baseAsset": "ETH",
      "count": 1700,
      "long": 120343494,
      "short": 16345938,
      "total": 136689432,
      "total24h": 136689431,
      "ratio1h": 0.03636161521717208
    }
  ],
  "tape": [],
  "largestPrint": {
    "symbol": "BTCUSDT",
    "baseAsset": "BTC",
    "side": "short",
    "notionalUsd": 25118.122499999998,
    "ts": 1792094257161
  },
  "cascades": {
    "active": [],
    "recent": []
  },
  "totalSymbols": 767,
  "window": "24h",
  "dataAt": 1792094473790,
  "stale": false
}

rekt[] truncated to 1 of 20 rows; tape[] emptied from 25 rows and cascades.active[] (1 row) and cascades.recent[] (8 rows) emptied to fit the length limit (their fields are in the table below)

GET/public/liquidations/tape1 credit300/min

Liquidation tape

Returns the raw force-close prints from the Binance USD-M futures liquidation stream, newest first; coin-margined contracts are not collected. The 200-row cap and the venue are fixed server-side, so the endpoint takes no parameters. There is no minimum notional: a live call's smallest row was $4.72. Filter by side or by dollar size on your end.

Parameters

None. Everything this endpoint returns is pinned server-side.

Status and edge cases

  • No 404 path. If the ingest feed is down the response is 200 with items: [] and count: 0.

Notes

  • side "long" means long positions were liquidated (a forced sell), so price was falling. Binance's raw forceOrder side is the opposite of this and is already inverted for you.
  • Venue is pinned to binance-futures here and is not a parameter. /public/liquidations/{symbol}/prints is the one liquidation route that takes a venue.
  • Do not judge freshness from updatedAt: it is the server clock at the moment the 5s cache entry was built, so it is byte-identical across every call inside the TTL and can be 5s old. Four back-to-back calls returned 1789244215744. Compare items[0].ts to now instead.
  • The payload is cached for 5 seconds, so polling faster than that returns the same rows.
  • Binance throttles its liquidation stream to at most one event per symbol per second, so prints under-report during fast moves. Treat counts as observed, not complete.
  • Only linear contracts appear: USD-M (BTCUSDT), USDC (BTCUSDC) and dated USDT futures. Coin-margined contracts (BTCUSD_PERP), whose qty is a contract count, have not been collected since 2026-10-04, so every notionalUsd is on one USD scale.
  • Rows are in ingest-receive order, which is only approximately ts-descending. A 200-row sample held 7 adjacent pairs where the next row's ts was higher, by up to 851 ms. Sort by ts yourself if exact ordering matters.
  • symbol is not guaranteed ASCII: a live tape carried a Binance meme pair whose base is CJK text. That symbol is unreachable from the /{symbol}/prints route, which strips every character outside A-Z, 0-9, underscore and hyphen.
▸Response fields(9)
items[]array
Liquidation prints in ingest-receive order, newest first, capped at 200
items[].symbolstring
Binance-futures contract symbol, e.g. BTCUSDT, BTCUSDC or a dated BTCUSDT_251226
items[].sidestring
Which side was force-closed: "long" or "short"
items[].pricenumber
Average fill price of the liquidation, in the contract's quote currency
items[].notionalUsdnumber
qty x price, in USD
items[].qtynumber
Base-asset units
items[].tsnumber
Exchange event time, epoch ms
countnumber
Number of rows in items[]; equals items.length on this endpoint
updatedAtnumber
Epoch ms the cached payload was built, not the age of the data; frozen for the 5s TTL
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/liquidations/tape"
Response200
{
  "items": [
    {
      "symbol": "ILVUSDT",
      "side": "long",
      "price": 3.74584,
      "notionalUsd": 29.592136,
      "qty": 7.9,
      "ts": 1789242625092
    },
    {
      "symbol": "VTHOUSDT",
      "side": "short",
      "price": 0.0006718,
      "notionalUsd": 3429.77413,
      "qty": 5105350,
      "ts": 1789242607225
    }
  ],
  "count": 200,
  "updatedAt": 1789242633787
}

items[] truncated to 2 of 200 rows

GET/public/liquidations/aggregates1 credit300/min

Liquidation aggregates

Rolls the liquidation tape up per symbol for a 5m, 1h or 24h window, sorted by total USD descending, alongside a market object holding venue-wide totals for all three windows. The row limit (100) and the $1,000 minimum total are server constants and cannot be changed by the caller. count is the number of symbols that matched, which is larger than items.length whenever more than 100 symbols qualify. Every dollar figure is USD.

Query parameters

windowenumoptionaldefault 1h
Rollup window for long, short, total and count. An unrecognised value falls back to 1h with a 200 and the echoed window says so.
5m1h24h

Status and edge cases

  • An unrecognised window silently falls back to 1h with a 200; there is no 400.
  • No 404 path. A quiet market returns 200 with items: [] and count: 0.

Notes

  • count is the pre-cap match total. At window=24h a live call returned count 416 with 100 rows; only read items.length for the rows you have.
  • Omitting window gives 1h, not 24h. Send it explicitly if you want a different window.
  • A symbol is excluded when its window total is under $1,000. That floor is fixed and ignoring it is not possible from the query string.
  • market.updatedAt is the worker's last write; the top-level updatedAt is when this response body was generated. Use market.updatedAt for staleness.
  • Every dollar figure is USD. Coin-margined contracts (ETHUSD_PERP, BTCUSD_PERP), which once reported contracts x price at 250-800x their real notional and took the top of this table, have not been collected since 2026-10-04.
  • Cached server-side, 20 seconds by default (the TTL is a deployment setting, so treat 20s as the documented floor rather than a guarantee).
▸Response fields(14)
items[]array
Per-symbol rows sorted by total USD descending, capped at 100
items[].symbolstring
Binance-futures contract symbol
items[].countnumber
Number of liquidation prints in the selected window
items[].longnumber
Long liquidations in the window, USD
items[].shortnumber
Short liquidations in the window, USD
items[].totalnumber
long + short for the window in USD; the sort key
items[].total24hnumber
24h total for the symbol, same units as total, regardless of the selected window
items[].ratio1hnumber
Long share of 1h liquidations, ratio 0 to 1; defaults to 0.5 when the symbol has no 1h data
items[].lastTsnumber
Epoch ms of the symbol's most recent liquidation
countnumber
Symbols that matched before the 100-row cap, not items.length
windowstring
The window actually applied, after fallback
marketobject|null
Venue-wide totals: long5m, short5m, long1h, short1h, long24h, short24h (USD, summed like items[].total), count1h, updatedAt (epoch ms). null when no summary has been written
market.count1hnumber
Venue-wide liquidation print count over the last hour
updatedAtnumber
Epoch ms when the cached payload was built; market.updatedAt is the data's own write time
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/liquidations/aggregates?window=1h"
Response200
{
  "items": [
    {
      "symbol": "ETHUSDT",
      "count": 35,
      "long": 32510,
      "short": 861563,
      "total": 894073,
      "total24h": 136689431,
      "ratio1h": 0.03636161521717208,
      "lastTs": 1792094462099
    },
    {
      "symbol": "NEARUSDT",
      "count": 41,
      "long": 12740,
      "short": 354757,
      "total": 367497,
      "total24h": 5917180,
      "ratio1h": 0.03466746669376661,
      "lastTs": 1792094470192
    }
  ],
  "count": 114,
  "window": "1h",
  "market": {
    "long5m": 127740,
    "short5m": 215603,
    "long1h": 446550,
    "short1h": 3820587,
    "long24h": 401271419,
    "short24h": 72571398,
    "count1h": 1295,
    "updatedAt": 1792094473790
  },
  "updatedAt": 1792094477244
}

items[] truncated to 2 of 100 rows

GET/public/liquidations/cascades1 credit300/min

Liquidation cascades

A cascade is one symbol being force-liquidated continuously: enough prints and enough notional inside a sliding window, with the threshold scaled by the symbol's 24h quote volume. active[] holds cascades running now, biggest first by totalUsd; recent[] holds the last 8 that ended. Both arrays are empty in a calm market, which is normal and not an error.

Parameters

None. Everything this endpoint returns is pinned server-side.

Status and edge cases

  • Both arrays empty is a normal calm-market response, not a fault. A live call returned active: [] with 8 rows in recent[].

Notes

  • recent[] rows carry three keys active[] rows do not: type, spottedAt and durationMs. Do not reuse one row type for both arrays. Every other key is shared: a live recent[0] held symbol, side, startedAt, lastEventAt, count, longUsd, shortUsd, totalUsd, baselineUsd, tier, windowUsd, windowCount, peakWindowUsd, thresholdUsd, q24, lastPrice, hotUntil, updatedAt.
  • recent[] is pinned to 8 rows and contains only type "end". There is no way to ask for more.
  • side "long" means longs were being liquidated, so price was falling.
  • A row leaves active[] under either of two rules: untouched for 90 seconds (an orphan from a restarted ingest worker), OR now past hotUntil + 30 seconds regardless of how recently it was touched. The second fires more often. Either way active[] can shrink without an end event appearing in recent[].
  • thresholdUsd is per-symbol, derived from q24, so a $10k cascade on a thin altcoin and a $10m one on BTC can both be tier 1. Compare totalUsd to baselineUsd, not across symbols.
  • Cached for 5 seconds.
▸Response fields(24)
active[]array
Cascades running now, sorted by totalUsd descending; empty in a calm market
active[].symbolstring
Binance-futures contract symbol
active[].sidestring
Dominant side since start: "long", "short" or "mixed"
active[].startedAtnumber
Epoch ms the cascade triggered
active[].lastEventAtnumber
Epoch ms of the most recent liquidation print folded into the cascade
active[].countnumber
Liquidation prints in the cascade so far
active[].longUsdnumber
Long liquidations in the cascade, USD
active[].shortUsdnumber
Short liquidations in the cascade, USD
active[].totalUsdnumber
Cascade total in USD; longUsd + shortUsd
active[].baselineUsdnumber
totalUsd at the moment it triggered, same units as totalUsd; escalation tiers are multiples of it
active[].tiernumber
1 at start, then the highest crossed escalation tier (2, 5 or 10)
active[].windowUsdnumber
Current sliding-window notional, same units as totalUsd; peakWindowUsd is its high-water mark
active[].windowCountnumber
Liquidation prints inside the current sliding window
active[].peakWindowUsdnumber
Highest windowUsd seen during the cascade, same units as totalUsd
active[].thresholdUsdnumber
Volume-scaled notional that armed this cascade, USD; q24 is the 24h quote volume used
active[].q24number
The symbol's 24h quote volume, USD, that thresholdUsd was scaled from
active[].lastPricenumber
Price of the most recent print in the cascade, in the contract's quote currency
active[].hotUntilnumber
Epoch ms the cascade ends unless the window keeps qualifying
active[].updatedAtnumber
Epoch ms the worker last touched this row; both drop rules below read it and hotUntil
recent[]array
The last 8 ended cascades, same fields as active[] plus three more
recent[].typestring
Always "end" on this route; start and escalate events are not exposed
recent[].spottedAtnumber
Epoch ms the end event was written to the feed
recent[].durationMsnumber
How long the cascade ran, milliseconds; present on ended rows only
updatedAtnumber
Epoch ms the cached payload was built; frozen for the 5s TTL
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/liquidations/cascades"
Response200
{
  "active": [],
  "recent": [
    {
      "symbol": "PONSUSDT",
      "side": "long",
      "startedAt": 1789242431478,
      "lastEventAt": 1789242547530,
      "count": 7,
      "longUsd": 13448.2100423,
      "shortUsd": 0,
      "totalUsd": 13448.2100423,
      "baselineUsd": 13448.2100423,
      "tier": 1,
      "windowUsd": 836.795,
      "windowCount": 1,
      "peakWindowUsd": 13448.2100423,
      "thresholdUsd": 10000,
      "q24": 100157028.8675,
      "lastPrice": 0.5771,
      "hotUntil": 1789242607530,
      "updatedAt": 1789242610124,
      "type": "end",
      "spottedAt": 1789242610124,
      "durationMs": 178646
    }
  ],
  "updatedAt": 1789242635164
}

active[] was genuinely empty at capture time; recent[] truncated to 1 of 8 rows

GET/public/liquidations/{symbol}/prints1 credit300/min

Prints for one symbol

The raw per-symbol ticks behind the liquidation bubbles on a chart, returned oldest first over a fixed 24-hour window with a fixed $1,000 minimum notional. The path segment is a contract symbol in the venue's own spelling, such as BTCUSDT, not a base asset, and venue picks which of the five perp venues to read (binance-futures when omitted). The symbol is sanitised rather than validated, so a malformed value comes back as an empty result instead of an error.

Path parameters

symbolstringrequired
The contract symbol as the venue spells it: BTCUSDT on binance-futures and bybit-futures, BTC-USDT-SWAP on okx-futures, BTC_USDT on gateio-futures, BTC-USDT on htx-futures. Case-insensitive. Anything outside A-Z, 0-9, underscore and hyphen is stripped and the result is cut to 24 characters, so a malformed symbol silently becomes a different one and returns no rows.

Query parameters

venueenumoptionaldefault binance-futures
Which venue's liquidations to read. Anything else returns 400 with the accepted list. The other liquidation routes do not take it.
binance-futuresbybit-futuresokx-futuresgateio-futureshtx-futures

Status and edge cases

  • An unrecognised venue returns 400 with the accepted list. HTX is htx-futures here; huobi-futures is rejected.
  • An unknown symbol returns 200 with items: [] and count: 0, not a 404. A live call to /NOTACOIN/prints returned an empty result with symbol echoed as "NOTACOIN".
  • A symbol containing stripped characters is silently rewritten: /btc.usdt/prints answered with symbol "BTCUSDT" and that symbol's 127 rows.
  • A symbol that sanitises to nothing short-circuits: /%24%24%24/prints returned HTTP 200 {"symbol":"","items":[],"count":0,"windowMs":0,"updatedAt":...}: the one case where windowMs is not 86400000.

Notes

  • Pass a contract symbol, not a base asset. BTCUSDT returned 127 rows in the same minute BTC returned 0.
  • Rows here have no symbol key; the symbol is top-level. The /tape rows carry it per item. The two shapes are not interchangeable.
  • items[] is oldest first. /tape is newest first.
  • Only prints of $1,000 or more are included, and the window is always the last 24 hours. Neither is a parameter.
  • At most the 4000 most recent prints are read from storage. If more than 2000 survive the $1,000 floor, the response keeps the largest by notional, not the most recent, then re-sorts by time.
  • Case is folded for you: /btcusdt/prints and /BTCUSDT/prints returned the same 127 rows.
  • The symbol must match the venue: /BTC-USDT-SWAP/prints?venue=okx-futures reads OKX's Bitcoin perpetual, while /BTCUSDT/prints?venue=okx-futures returns no rows.
  • Only linear contracts are collected. Coin-margined ones (BTCUSD_PERP on binance-futures, inverse swaps elsewhere) and OKX's USDC swaps return an empty result, exactly like a quiet symbol.
  • Cached for 8 seconds per symbol and venue.
▸Response fields(10)
symbolstring
The sanitised, upper-cased symbol the server actually queried; compare it to what you sent. Empty string when sanitising removed every character
items[]array
Prints in chronological order, oldest first, capped at 2000
items[].tsnumber
Exchange event time, epoch ms
items[].pricenumber
Average fill price of the liquidation, in the contract's quote currency
items[].notionalUsdnumber
qty x price in USD, and the value the $1,000 floor is applied to. Only linear USDT- and USDC-margined contracts are collected, so this is the real notional on every venue: on 2026-10-15 the newest BTC prints on all five matched qty x price exactly
items[].qtynumber
Base-asset units on every venue. Where a venue reports contract counts, each is converted with that contract's size before the print is stored
items[].sidestring
Which side was force-closed: "long" or "short"
countnumber
Rows in items[]; equals items.length on this endpoint
windowMsnumber
Window covered, milliseconds; 86400000 on every real symbol, and 0 on the empty-symbol short-circuit
updatedAtnumber
Epoch ms the cached payload was built, not the age of the data; frozen for the 8s TTL
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/liquidations/BTCUSDT/prints"
Response200
{
  "symbol": "BTCUSDT",
  "items": [
    {
      "ts": 1789156310431,
      "price": 77333.3,
      "notionalUsd": 4407.998100000001,
      "qty": 0.057,
      "side": "short"
    },
    {
      "ts": 1789156965535,
      "price": 77400.1,
      "notionalUsd": 26935.2348,
      "qty": 0.348,
      "side": "short"
    }
  ],
  "count": 127,
  "windowMs": 86400000,
  "updatedAt": 1789242635726
}

items[] truncated to 2 of 127 rows

05

Open interest

1 endpoint

Positioning behind the tape, in contracts and USD notional.

GET/public/open-interest/{symbol}/history10 credits120/min

Open interest history

Returns up to 500 open-interest samples for one Binance USD-M perpetual, each with the contract count and the USD notional at that time. The symbol must be a full pair such as BTCUSDT. Binance itself only keeps about 30 days of this data, so a long period returns far fewer than 500 points.

Path parameters

symbolstringrequired
Binance USD-M perpetual pair, e.g. BTCUSDT. Matched against /^[A-Z0-9]{2,20}$/i and upper-cased; anything with a hyphen or underscore is rejected with 400.

Query parameters

periodenumoptionaldefault 15m
Sampling interval. An unrecognised value falls back to 15m with a 200, and the echoed period shows which one was used.
5m15m30m1h2h4h6h12h1d

Status and edge cases

  • A symbol failing /^[A-Z0-9]{2,20}$/i returns 400 with a five-key body: {"statusCode":400,"message":"Invalid symbol","error":"Bad Request","timestamp":"2026-09-12T20:17:27.586Z","path":"/public/open-interest/BTC-USDT/history"}. timestamp is an ISO 8601 string and path echoes the request path. Verified with BTC-USDT and BTCUSD_PERP.
  • A well-formed but unknown symbol returns 200 with points: [], not a 404. Verified with NOTAREALSYM.
  • An unrecognised period silently falls back to 15m with a 200. Verified with period=3m.
  • An upstream Binance failure also returns 200: with the last good history for that symbol and period if one was fetched in the past hour (check updatedAt), otherwise with points: []. That answer is cached for 15 seconds, so retry after that.

Notes

  • points[].time is epoch seconds while updatedAt is epoch milliseconds. Mixing them is the easiest mistake here.
  • The row limit is pinned to 500 and is not a parameter. Binance caps history at roughly 30 days, so the span you get depends on period: period=5m returned 500 points covering 41.6 hours, period=4h returned 186, period=1d returned 31.
  • Coin-margined contracts are unreachable: BTCUSD_PERP fails the symbol regex with a 400 because of the underscore.
  • Binance-futures only. There is no venue parameter and no other exchange behind this route.
  • Responses are cached for 60 seconds per symbol and period, and concurrent cold requests collapse into one upstream call. Polling faster than 60s gains nothing.
  • Read back the echoed symbol and period and check points.length before charting; bad input does not raise.
▸Response fields(7)
symbolstring
The upper-cased symbol actually queried
periodstring
The interval actually applied, after fallback
points[]array
Samples in ascending time order, at most 500
points[].timenumber
Sample time in epoch SECONDS, not milliseconds
points[].oinumber
Open interest in contracts (base-asset units on USD-M)
points[].oiUsdnumber
Open interest in USD notional; rows where this is zero or non-numeric are dropped
updatedAtnumber
Epoch ms the payload was fetched from Binance
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/open-interest/BTCUSDT/history?period=1h"
Response200
{
  "symbol": "BTCUSDT",
  "period": "1h",
  "points": [
    {
      "time": 1787443200,
      "oi": 105815.023,
      "oiUsd": 8156646450.519016
    },
    {
      "time": 1787446800,
      "oi": 105884.316,
      "oiUsd": 8186256838.163368
    }
  ],
  "updatedAt": 1789242617467
}

points[] truncated to 2 of 500 rows

06

Screener

3 endpoints

Sixteen ready-made whole-market screens, and the vocabulary behind them.

GET/public/screener/presets0 credits120/min

Screener presets

Lists every screen a caller may run, with its id, display label and a one-sentence description of what it finds. The id vocabulary here is the complete allowlist for the preset query parameter on /public/screener. The list is static and compiled into the API, so it only changes on a deploy.

Parameters

None. Everything this endpoint returns is pinned server-side.

Status and edge cases

  • No parameters are read, so unknown query strings are ignored and still return 200.
  • A request from an Origin outside the configured allowlist returns 500 with {"statusCode":500,"message":"An unexpected error occurred"}, not 403.

Notes

  • Read this before calling /public/screener. Any id not in this list is a 400.
  • The list is a frozen server-side constant, not derived from live data. Cache it; it cannot change between deploys.
  • No cache is applied to this handler, but the payload is static. Do not poll it.
  • The filters and thresholds behind each preset are not exposed. Only id, label and description are returned.
  • Server-to-server only. A browser fetch from a third-party origin returns 500, not a CORS error, because the API's CORS origin callback throws for unknown origins.
▸Response fields(5)
presetsarray
All 16 screens, in a fixed order that matches the product's menu.
presets[]object
One screen definition.
presets[].idstring
Kebab-case id to send as ?preset= on /public/screener.
presets[].labelstring
Display name, e.g. "Oversold (4h)".
presets[].descriptionstring
One sentence saying what the screen finds, not which filters it sets.
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/screener/presets"
Response200
{
  "presets": [
    {
      "id": "oversold-4h",
      "label": "Oversold (4h)",
      "description": "RSI below 30 on the 4-hour chart, above $10M market cap."
    },
    {
      "id": "deeply-oversold-4h",
      "label": "Deeply oversold (4h)",
      "description": "RSI under 20 on the 4-hour chart."
    }
  ]
}

presets[] truncated to 2 of 15 rows

GET/public/screener5 credits120/min

Run a screen

Runs the named preset against the market board the worker assembles every 60 seconds, and returns the coins that pass plus the metric columns that screen selects on. Page size and offset are pinned server-side at 100 and 0; a caller-supplied limit or offset is accepted by the HTTP layer and then discarded. Callers cannot build their own filters on the public API, by design.

Query parameters

presetenumrequired
Which built-in screen to run. Missing, unknown, or repeated (?preset=a&preset=b) all return 400 listing the 16 allowed ids.
▸16 accepted values
oversold-4hdeeply-oversold-4hoverbought-4hvolume-surgevolume-10xcapitulationnear-athdeep-drawdownfunding-expensive-longsfunding-negativefresh-momentumsqueezenew-listingsgolden-cross-1dichimoku-cross-1dhigh-turnover

Status and edge cases

  • Missing preset returns 400: "preset is required. Allowed: oversold-4h, deeply-oversold-4h, ...".
  • An unknown preset returns 400: "Unknown preset \"nope\". Allowed: ...".
  • A repeated ?preset=a&preset=b arrives comma-joined and returns 400 as an unknown preset, not a 200 for the first value.
  • An empty result is a 200 with matched 0, count 0 and rows []. It is not an outage; near-ath has returned 0 rows.
  • If the worker's board is missing the response is still 200 with universe 0, rows [] and meta.stale true, never a 500.
  • A request from an Origin outside the configured allowlist returns 500, not 403.

Notes

  • Call /public/screener/presets first. preset is required and the 15 ids are the only accepted values.
  • limit and offset are ignored. Sending ?limit=3&offset=50 still returns meta.limit 100, meta.offset 0 and the full first page; verified live.
  • Rows are capped at 100 with no pagination. When meta.matched exceeds 100 the tail is unreachable (deep-drawdown returned matched 244, count 100).
  • The metric columns after marketCap differ per preset. Read the keys off rows[0] rather than assuming a fixed schema, skipping closedBar, which is a flag and not a column.
  • Technical columns such as rsi@4h read the candle that is still forming, the one a chart draws, so they move within the candle. trendScore, sqs, trendline breaks, divergences, relative volume and the green-day streak read the last closed candle.
  • A timeframe-scoped column is suffixed with its timeframe, e.g. "rsi@4h", "bbBandwidth@1d". A column whose preset names no timeframe falls back to 4h.
  • Identity fields are always base, name, logo, rank, venue, symbol, quote, price, priceSource, marketCap. A preset column that repeats one of those is deduplicated, so some presets show 4 extra columns rather than 5.
  • Responses are memoised in-process for 75 seconds per preset, on top of the worker's 60-second board rebuild. The payload therefore changes at most once per 75 seconds. Two polls less than a minute apart can still straddle a cache expiry and return different bytes, so polling faster than once per 75 seconds gains nothing.
  • null means unknown, never zero. A coin with no perp has null funding and is dropped from a numeric filter rather than treated as 0.
  • Stablecoins are excluded from every preset. Wrapped assets are included.
  • marketCap can legitimately be 0 on very new listings; the futures presets set no market-cap floor.
  • Server-to-server only. A browser fetch from a third-party origin returns 500, not a CORS error.
▸Response fields(21)
presetobject
The screen that ran: id, label and description, identical to the /public/screener/presets row.
meta.updatedAtnumber
When the worker last assembled the board, epoch ms. 0 means it never has.
meta.universenumber
Coins on the board before this screen's filters were applied.
meta.matchednumber
Coins that passed the filters, before the 100-row cap.
meta.countnumber
Rows actually returned in rows[]. Equals min(matched, 100).
meta.limitnumber
Server-pinned page size. Always 100 on this route.
meta.offsetnumber
Server-pinned page start. Always 0 on this route.
meta.snapshotDaysnumber
Days of daily-snapshot history accumulated so far. Metrics needing a longer window are null.
meta.staleboolean
true when the board is missing or older than 5 minutes.
rows[]array
Matching coins: 10 fixed identity fields plus that preset's metric columns.
rows[].basestring
Base asset ticker, e.g. "RVN".
rows[].namestring|null
Coin name as CoinMarketCap spells it, e.g. "Ravencoin".
rows[].logostring|null
CoinMarketCap 64x64 PNG URL. null when no logo is on file; 9 of 569 rows across all 15 presets were null.
rows[].ranknumber|null
CoinMarketCap market-cap rank, 1 = largest.
rows[].venuestring|null
The coin's primary market: the single market chosen to speak for it, which also fixes rows[].symbol, rows[].quote and every technical column. One of binance, binance-futures, bybit-futures, okx-futures, gateio-futures, htx-futures. Set even when all of the row's technical columns are null.
rows[].symbolstring|null
Symbol on rows[].venue, in that venue's native spelling: RVNUSDT (binance), PI-USDT-SWAP (okx-futures), LAPTOP_USDT (gateio-futures). Not derivable from base + quote.
rows[].quotestring|null
Quote asset of that market, e.g. "USDT".
rows[].pricenumber|null
Last price per unit, in USD. A primary market quoted in something other than a dollar stablecoin is never used for this column; priceSource is "cmc" instead.
rows[].priceSourcestring|null
Where price came from: "venue" or "cmc".
rows[].marketCapnumber|null
Market cap in USD.
rows[].closedBarstring[]
Present only when some of the row's technical columns had to be read on the last closed candle because that market's live candle was behind; lists those column keys, e.g. ["rsi@4h"]. Absent when every technical reads the forming candle.
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/screener?preset=oversold-4h"
Response200
{
  "preset": {
    "id": "oversold-4h",
    "label": "Oversold (4h)",
    "description": "RSI below 30 on the 4-hour chart, above $10M market cap."
  },
  "meta": {
    "updatedAt": 1789244297365,
    "universe": 762,
    "matched": 6,
    "count": 6,
    "offset": 0,
    "limit": 100,
    "snapshotDays": 15,
    "stale": false
  },
  "rows": [
    {
      "base": "RVN",
      "name": "Ravencoin",
      "logo": "https://s2.coinmarketcap.com/static/img/coins/64x64/2577.png",
      "rank": 457,
      "venue": "binance",
      "symbol": "RVNUSDT",
      "quote": "USDT",
      "price": 0.00221,
      "priceSource": "venue",
      "marketCap": 36519883.6370978,
      "rsi@4h": 22,
      "pctChange.h24": -1.39156737,
      "pctChange.d7": -27.53314004,
      "volume24h": 5896921.80149907,
      "trendScore@4h": -75
    }
  ]
}

rows[] truncated to 1 of 6 rows

Data from CoinMarketCap

GET/public/screener/metrics0 credits120/min

Screener metric vocabulary

Returns the definition of every metric the screener engine knows about, plus the timeframes a timeframe-scoped metric can be computed on. This is the column vocabulary the presets are built from and the key for interpreting the metric fields in a /public/screener row. The public API does not accept caller-built filters, sorts or column lists, so these keys cannot be used to compose a query.

Parameters

None. Everything this endpoint returns is pinned server-side.

Status and edge cases

  • No parameters are read, so unknown query strings are ignored and still return 200.
  • A request from an Origin outside the configured allowlist returns 500 with {"statusCode":500,"message":"An unexpected error occurred"}, not 403.

Notes

  • This is a vocabulary, not a query interface. No public route accepts a caller-built filter, sort or column list; the screener is presets-only and the source states that is a cache-key security boundary, not a temporary gap.
  • Use it to interpret the metric columns in a /public/screener row, including the key@tf suffix on the 55 timeframe-scoped metrics.
  • availability tells you why a value is null: futures metrics are null for roughly half the universe because those coins have no perp, and snapshot metrics stay null until enough daily history has accumulated (see meta.snapshotDays on /public/screener).
  • The response is a compiled-in constant with no live data and no cache layer. Fetch it once per deploy, not per request.
  • The internal accessor function on each definition is stripped before serialising; only the 6 to 9 declared fields are returned.
  • Server-to-server only. A browser fetch from a third-party origin returns 500, not a CORS error.
▸Response fields(12)
timeframesarray
The 5 timeframes a tfScoped metric can be read on: 15m, 1h, 4h, 1d, 1w.
metricsarray
All 114 metric definitions, in registry order.
metrics[].keystring
Stable metric id, e.g. "rsi", "volMcapRatio", "pctChange.d30".
metrics[].labelstring
Display name, e.g. "RSI(14)".
metrics[].groupstring
One of overview, performance, technicals, volume, derivatives, athatl.
metrics[].typestring
One of number, percent, usd, price, integer, enum, boolean, tags. percent is already scaled to percent, not a ratio.
metrics[].tfScopedboolean
true when the value only exists per timeframe; 55 of 114 metrics are. Its screener column is then named key@tf.
metrics[].availabilitystring
What a coin needs to have the value: universe (27), venue (75), futures (7) or snapshot (5).
metrics[].enumValuesarray
The exact allowed values. Present only on the 22 metrics of type enum; absent otherwise.
metrics[].barstring
forming or closed, on candle-derived metrics only (72 of 114): forming values read the candle that is still open, as a chart draws it, and move within the bar; closed values read the last closed candle. Absent on metrics that are not read from a candle
metrics[].hintstring
One-line explanation of what the number means. Present on 70 of 114 metrics, absent on the rest.
metrics[].blockTfstring
On the 6 anchored-VWAP metrics only (the distance in percent and in standard deviations, for each anchor): the timeframe whose candles the value is read on, which is fixed whatever timeframe a screen uses (15m for the daily VWAP, 1h for the weekly, 4h for the monthly). Absent otherwise.
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/screener/metrics"
Response200
{
  "timeframes": ["15m", "1h", "4h", "1d", "1w"],
  "metrics": [
    {
      "key": "rsi",
      "label": "RSI(14)",
      "group": "technicals",
      "type": "number",
      "tfScoped": true,
      "availability": "venue",
      "bar": "forming"
    },
    {
      "key": "venue",
      "label": "Primary venue",
      "group": "overview",
      "type": "enum",
      "tfScoped": false,
      "availability": "venue",
      "enumValues": [
        "binance",
        "binance-futures",
        "bybit-futures",
        "okx-futures",
        "gateio-futures",
        "htx-futures"
      ]
    }
  ]
}

metrics[] truncated to 2 of 114 entries, chosen to show both the plain shape and the enum shape

07

Indicator Edge

3 endpoints

Whether an indicator signal actually preceded a move, measured against each coin's own baseline drift rather than against zero.

GET/public/indicator-performance/meta1 credit120/min

Indicator Edge vocabulary

Returns the timeframe, forward-window and lookback vocabulary the other two Indicator Edge routes validate against, plus an all-time firing count per condition so a rare signal is visible before it is selected. Read this first and build your timeframe, window and lookback selectors from it, because the valid windows and lookbacks differ per timeframe. It does not carry the /board sort and dir allowlists, and venues is informational: no public route accepts a venue parameter. The firedWithin array is scoped to the tf you asked for, while firedWithinByTf carries every timeframe's list.

Query parameters

tfenumoptionaldefault 4h
Timeframe whose firing counts and firedWithin list are returned; any other value returns 400.
15m1h4h1d

Status and edge cases

  • An unsupported timeframe returns 400 with message "Unsupported timeframe: 2h". Verified with tf=2h; 5m and 1w behave the same.
  • No authentication is required and no 401 or 403 exists on this route.

Notes

  • Build selectors from firedWithinByTf, not firedWithin. firedWithin only answers for the tf you sent.
  • conditions[].seedSensitive is omitted when false. It is present on exactly four conditions: price_cross_above_ema200, price_cross_below_ema200, supertrend_flip_up and supertrend_flip_down. Treat a missing key as false.
  • conditions[].n counts every stored row for that timeframe: no lookback, no completed-window filter and no status filter, so it also counts pending events that /overview and /board exclude. It is never smaller than the n /overview reports for the same condition; /board's comparable figures are meta.eventsInRange and meta.eventsWithCompletedWindow, not its per-coin rows[].n.
  • venues is in resolution priority order. The board picks one venue per coin by walking this list.
  • Responses are cached 75 seconds at the route and 300 seconds in the service, so a value can lag the evaluator by about 6 minutes.
  • windows and thresholds are static config and do not vary with tf; only firedWithin and the conditions[].n counts do.
▸Response fields(14)
timeframes[]string
The four timeframe ids the board supports.
windowsobject
Map of timeframe id to the forward windows recorded for it.
windows.<tf>[].barsnumber
Forward window length in bars, the value to send as window.
windows.<tf>[].labelstring
Human duration of that window, for example 42 bars on 4h is 7d.
thresholds[]number
Excursion thresholds recorded on both sides of every event, in percent.
firedWithin[]string
Lookbacks valid for the requested tf only, as day strings such as 180d.
firedWithinByTfobject
Map of timeframe id to its full list of valid lookbacks.
venues[]string
Exchange ids the board draws from, in the priority order it resolves them.
conditions[].idstring
Condition id, the value to send as condition on /board.
conditions[].indicatorstring
Indicator family: rsi, macd, sma, ema, supertrend, bollinger or volume.
conditions[].labelstring
Human description of the firing rule.
conditions[].expectedstring
Direction the signal is meant to precede: up, down or neutral.
conditions[].seedSensitiveboolean
Present only when true; the indicator carries state, so a backfilled and a live event can disagree on the same bar.
conditions[].nnumber
Firings recorded for this condition on the requested timeframe, all history, unfiltered.
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/indicator-performance/meta?tf=4h"
Response200
{
  "timeframes": ["15m", "1h", "4h", "1d"],
  "windows": {
    "4h": [
      { "bars": 6, "label": "1d" },
      { "bars": 42, "label": "7d" }
    ]
  },
  "thresholds": [1, 2, 3, 5, 10, 15, 20, 30, 50],
  "firedWithin": ["30d", "90d", "180d"],
  "firedWithinByTf": {
    "15m": ["7d", "14d"],
    "4h": ["30d", "90d", "180d"]
  },
  "venues": ["binance", "binance-futures", "bybit-futures", "okx-futures", "gateio-futures"],
  "conditions": [
    {
      "id": "rsi_cross_below_30",
      "indicator": "rsi",
      "label": "RSI crossed below 30",
      "expected": "up",
      "n": 20581
    },
    {
      "id": "supertrend_flip_up",
      "indicator": "supertrend",
      "label": "Supertrend flipped bullish",
      "expected": "up",
      "seedSensitive": true,
      "n": 29235
    }
  ]
}

windows truncated to the 4h key with 2 of its 5 entries, firedWithinByTf truncated to 2 of 4 keys, conditions[] truncated to 2 of 19

GET/public/indicator-performance/overview25 credits120/min

All conditions scored

Scores every condition on one timeframe and forward window, so you can compare signals before drilling into one. Each row's median and posShare are computed over individual firings, not over coins, so a coin with 900 firings weighs 180x a coin with 5; /board's meta.reference.median is the coin-level equivalent of the same number. Each row also carries the single strongest coin for that condition. Rows are computed only over events whose forward window has completed.

Query parameters

tfenumoptionaldefault 4h
Timeframe the conditions are scored on; any other value returns 400.
15m1h4h1d
windowintegeroptionaldefault the middle window for the timeframe: 48 on 15m, 24 on 1h, 42 on 4h, 7 on 1d
Forward window in bars, and only a window recorded for that timeframe: 15m accepts 4, 16, 48, 96, 288; 1h accepts 4, 12, 24, 72, 168; 4h accepts 6, 18, 42, 90, 180; 1d accepts 1, 3, 7, 14, 30. Anything else returns 400.
firedWithinenumoptionaldefault the longest lookback for the timeframe: 180d on 1h, 4h and 1d, 14d on 15m
How far back a firing may have occurred; 15m accepts only 7d and 14d, while 1h, 4h and 1d accept only 30d, 90d and 180d, and the lookback must also be at least 1.25x the window in days or the request returns 400.
7d14d30d90d180d

Status and edge cases

  • A window not recorded for the timeframe returns 400: "Window 7 is not recorded for 4h".
  • A lookback the timeframe does not keep returns 400: "The 15m board only keeps 7d or 14d of history."
  • A lookback too short for the window returns 400: "A 30-bar window on 1d needs a longer lookback than 30d; most events would still be running." The rule is days >= window in days x 1.25.
  • An unsupported timeframe returns 400: "Unsupported timeframe: 2h".
  • A condition with data on the timeframe but no qualifying coin returns 200 with top:null rather than omitting the row.

Notes

  • rows always contains all 19 conditions in a fixed order, even where a condition has no data on this timeframe. A condition with no data returns n:0, coins:0, median:null, posShare:null, top:null.
  • n counts only firings whose forward window has completed, so it is smaller than the same condition's n in /meta.
  • top is computed through the board pipeline with a minimum of 3 independent observations, below the board's own minimum of 5, so a coin shown on this route can be absent from /board with the same filters.
  • For a condition whose expected is down, top is the coin with the most negative excess, not the most positive.
  • posShare is a ratio from 0 to 1, not a percent. median and excess are percents.
  • An uncached combination is slow because it runs one board query per condition: a cold tf=1h&window=72&firedWithin=90d call took 10.1 s, and the same call 0.52 s once cached. Responses are cached 75 s at the route and 300 s in the service.
▸Response fields(15)
meta.tfstring
Timeframe the rows were computed on.
meta.windowBarsnumber
Forward window in bars that was applied.
meta.windowLabelstring
That window as a duration, for example 7d.
meta.firedWithinstring
Lookback applied, as a day string such as 180d.
rows[].conditionstring
Condition id, matching an id from /meta.
rows[].labelstring
Human description of the firing rule, the same text as /meta conditions[].label.
rows[].indicatorstring
Indicator family: rsi, macd, sma, ema, supertrend, bollinger or volume.
rows[].expectedstring
Direction the signal is meant to precede: up, down or neutral.
rows[].seedSensitiveboolean
Always present here, unlike in /meta. True for the EMA200 and Supertrend conditions.
rows[].nnumber
Firings in the lookback whose forward window has completed.
rows[].coinsnumber
Distinct base assets with at least one firing in the lookback whose forward window has completed, the same filter as n. No minimum-observations gate is applied, so it exceeds /board's total: at tf=4h, window=42, firedWithin=180d, rsi_cross_below_30 reports coins 668 against board total 492 plus hiddenByMinEvents 176.
rows[].mediannumber|null
Median forward return across all those firings, event-weighted, in percent; null when n is 0.
rows[].posSharenumber|null
Share of firings that closed positive over the window, a ratio from 0 to 1; null when n is 0.
rows[].topobject|null
The single strongest coin for this condition, with keys base, exchange, excess, median, nClusters and posShare; null when no coin qualifies.
rows[].top.excessnumber|null
That coin's median minus its own unconditional baseline, in percent.
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/indicator-performance/overview?tf=4h&window=42&firedWithin=180d"
Response200
{
  "meta": {
    "tf": "4h",
    "windowBars": 42,
    "windowLabel": "7d",
    "firedWithin": "180d"
  },
  "rows": [
    {
      "condition": "rsi_cross_below_30",
      "label": "RSI crossed below 30",
      "indicator": "rsi",
      "expected": "up",
      "seedSensitive": false,
      "n": 14528,
      "coins": 668,
      "median": -1.82,
      "posShare": 0.4123761013215859,
      "top": {
        "base": "BR",
        "exchange": "binance-futures",
        "excess": 80.75,
        "median": 80.5397,
        "nClusters": 3,
        "posShare": 1
      }
    }
  ]
}

rows[] truncated to 1 of 19 conditions

GET/public/indicator-performance/board10 credits120/min

Condition leaderboard

Ranks coins by how much one indicator condition beat that coin's own unconditional drift over the same forward window. The public route is pinned to the top 20 rows at a minimum of 5 independent observations per coin, and meta.reference gives the whole field's numbers so a top row can be read against its comparand. Sorting is honoured; paging, coin search and venue pinning are not.

Query parameters

conditionenumoptionaldefault rsi_cross_below_30
The indicator condition to rank; an unknown id returns 400 "Unknown condition: X".
▸19 accepted values
rsi_cross_below_30rsi_cross_below_25rsi_cross_below_20rsi_cross_below_15rsi_cross_above_70rsi_cross_above_75rsi_cross_above_80rsi_cross_above_85macd_bull_crossmacd_bear_crosssma_golden_crosssma_death_crossprice_cross_above_ema200price_cross_below_ema200supertrend_flip_upsupertrend_flip_downbb_touch_lowerbb_touch_uppervol_spike_3x
tfenumoptionaldefault 4h
Timeframe the events were detected on; any other value returns 400.
15m1h4h1d
windowintegeroptionaldefault the middle window for the timeframe: 48 on 15m, 24 on 1h, 42 on 4h, 7 on 1d
Forward window in bars, and only a window recorded for that timeframe: 15m accepts 4, 16, 48, 96, 288; 1h accepts 4, 12, 24, 72, 168; 4h accepts 6, 18, 42, 90, 180; 1d accepts 1, 3, 7, 14, 30. Anything else returns 400.
firedWithinenumoptionaldefault the longest lookback for the timeframe: 180d on 1h, 4h and 1d, 14d on 15m
How far back a firing may have occurred; 15m accepts only 7d and 14d, while 1h, 4h and 1d accept only 30d, 90d and 180d, and the lookback must also be at least 1.25x the window in days or the request returns 400.
7d14d30d90d180d
sortenumoptionaldefault excess
Column to rank by; n sorts on nClusters and maxUp on avgMaxUp, and an unrecognised value is silently ignored and falls back to excess rather than returning 400.
excessmediannposSharemaxUpbaselinebestlastAt
direnumoptionaldefault desc
Sort direction; only the exact lowercase string asc flips the order, and everything else including ASC silently becomes desc.
ascdesc

Status and edge cases

  • An unknown condition returns 400: "Unknown condition: nope".
  • A window not recorded for the timeframe returns 400: "Window 7 is not recorded for 4h".
  • A lookback the timeframe does not keep returns 400: "The 4h board only keeps 30d or 90d or 180d of history."
  • A lookback too short for the window returns 400: "A 30-bar window on 1d needs a longer lookback than 30d; most events would still be running."
  • An unrecognised sort does not error; it silently falls back to excess. Any dir other than the exact string asc silently becomes desc.
  • A 200 does not mean rows. Verified: ?tf=1d&window=7&firedWithin=90d&condition=supertrend_flip_up returned total:0, count:0, rows:[], meta.reference:null with hiddenByMinEvents:486. Handle the empty array as data, not as an outage.

Notes

  • base, exchange, limit, offset and minEvents are not read by this route. Verified live: a call passing base=BTC&exchange=binance&limit=100&offset=5&minEvents=1 returned a body byte-identical to the bare call. Coin search, venue pinning and paging need an account.
  • There is no events route under /public/indicator-performance. The per-firing ledger is not exposed anonymously.
  • total counts every coin that cleared the minimum while rows stops at 20, so total greater than rows.length is normal, not a paging bug.
  • Each coin appears once. Among venues where the coin has at least 5 independent observations, the first in the /meta venues order wins; if none qualifies, the venue with the largest sample is used.
  • n is raw firings and nClusters is the de-overlapped count. Rank and filter on nClusters; the two differ whenever firings overlap inside one window.
  • reached is keyed by percent threshold, only "5" and "10", and each value is the ratio of events that hit plus that percent before minus that percent inside the window.
  • baseline, baselineMaxUp and excess are null together when the coin has no baseline row for that timeframe and window.
  • All timestamps (firstAt, lastAt, bestAt, worstAt) are epoch milliseconds. posShare is a ratio from 0 to 1; every other percentage field is a percent.
  • mixedParams true means the indicator definition changed inside the sample, so the rows mix two parameter sets.
  • Responses are cached 75 seconds at the route and 300 seconds in the service.
▸Response fields(14)
meta.conditionstring
The condition that was ranked, echoed back.
meta.eventsInRangenumber
Firings of this condition inside the lookback, before the completed-window filter.
meta.eventsWithCompletedWindownumber
Of those, how many have a completed forward window and therefore count.
meta.hiddenByMinEventsnumber
Coins dropped for having fewer than 5 independent observations.
meta.referenceobject|null
The whole field's stats to read a row against. median, p25 and p75 are percentiles of the per-coin medians, one draw per qualifying coin, in percent; posShare is event-weighted, sum(coin.posShare x coin.n) / sum(coin.n), a ratio from 0 to 1, so it is not the same measurement as the median; coins, n and nClusters are plain counts and sums. Null when no coin clears the minimum.
totalnumber
Coins that cleared the minimum, before the 20-row cap.
countnumber
Rows actually returned, never more than 20.
guestboolean
Always true on this route; marks the response as the capped public cut.
limitnumber
The server-pinned row cap, always 20.
rows[].basestring
Base asset, with any 1000 or 1M multiplier prefix stripped, so 1000PEPE is stored as PEPE.
rows[].exchangestring
The one venue this coin resolved to for the ranking.
rows[].nClustersnumber
Independent observations after de-overlapping windows; this is what the minimum of 5 filters on.
rows[].mediannumber
Median forward return over the window for this coin, in percent.
rows[].excessnumber|null
median minus the coin's own unconditional baseline, in percent; null when no baseline row exists.
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/indicator-performance/board?condition=rsi_cross_below_30&tf=4h&window=42&firedWithin=180d&sort=excess&dir=desc"
Response200
{
  "meta": {
    "condition": "rsi_cross_below_30",
    "conditionLabel": "RSI crossed below 30",
    "expected": "up",
    "seedSensitive": false,
    "tf": "4h",
    "windowBars": 42,
    "windowLabel": "7d",
    "firedWithin": "180d",
    "eventsInRange": 15561,
    "eventsWithCompletedWindow": 14528,
    "hiddenByMinEvents": 176,
    "base": null,
    "exchange": null,
    "belowMinEvents": false,
    "minEvents": 5,
    "reference": { "coins": 492, "n": 4057, "nClusters": 3184, "median": -1.5, "p25": -4.22, "p75": 0.81, "posShare": 0.413606112891299 },
    "mixedParams": false
  },
  "total": 492,
  "count": 20,
  "rows": [
    {
      "base": "RIF",
      "exchange": "binance",
      "n": 5,
      "nClusters": 5,
      "median": 28.988,
      "posShare": 0.8,
      "avgMaxUp": 48.05428,
      "lastAt": 1788047999999,
      "reached": { "5": 0.2, "10": 0.2 },
      "baseline": 2.09,
      "excess": 26.9
    }
  ],
  "guest": true,
  "limit": 20
}

rows[] truncated to 1 of 20; that row keeps 11 of its 22 keys (p25, p75, avg, avgMaxDown, best, bestAt, worst, worstAt, firstAt, mixedParams and baselineMaxUp omitted)

08

Smart Setups

2 endpoints

The scored pattern-and-structure board, with a checklist and a written read per market.

GET/public/setups5 credits120/min

Smart Setups board

The ranked Smart Setups board for a single venue and timeframe. Each row carries the 0-100 SQS score and its component breakdown, the trade archetype and its pass/fail checklist, the market regime, participation stats and a one-line English narrative. Entry, stop and target are removed from every public setup, so the board reports what was detected, not what to trade.

Query parameters

exchangeenumoptionaldefault binance
Venue to read the board from. Anything else returns 400 with the accepted list.
binancebinance-futuresbybit-futuresokx-futuresgateio-futureshtx-futures
timeframeenumoptionaldefault 15m
Candle timeframe. all collapses each symbol to its highest-scoring timeframe, so setups[].tf then varies per row. Anything else returns 400.
15m1h4h1d1wall
sortenumoptionaldefault score
Ranking: score = SQS, fresh = fewest bars since trigger, rr = trade-plan risk/reward, rvol = relative volume. An unknown value silently falls back to score.
scorefreshrrrvol
minScoreintegeroptional
Minimum SQS, 0-100. Rounded to an integer and clamped into range; a non-numeric value is ignored rather than rejected.
minConfidenceintegeroptional
Legacy minimum confidence, 0-10, applied as confidence x 10 on the same 0-100 scale. Ignored when minScore is also sent.
archetypestringoptional
Comma-separated archetype keys to keep. Unknown entries are dropped; if none survive, no archetype filter is applied at all.
pattern_breakouttrendline_breakbreakout_retestbreakout_watchlevel_bouncereversalcontinuationnone
biasenumoptional
Keep only setups with this directional bias. An unrecognised value applies no filter and does not error.
bullishbearishneutral
multiTfbooleanoptionaldefault false
Keep only setups confirmed on a higher timeframe. Only the exact strings true and 1 switch it on; every other value means off.
quoteenumoptional
Keep only markets quoted in this asset, read from the venue's instrument catalogue rather than from the spelling of the symbol, so BTC-USDT-SWAP on okx-futures and BTC_USDT on gateio-futures both match USDT. Case-insensitive. A value outside the allowlist applies no filter.
▸24 accepted values
USDTUSDCFDUSDTUSDUSDPDAIBTCETHBNBEURGBPTRYBRLARSJPYAUDMXNZARUSDXRPSOLDOGETRXDOT

Status and edge cases

  • An unknown exchange returns 400 listing the six accepted values.
  • An unknown timeframe returns 400. all is the only non-candle value accepted.
  • A repeated ?exchange= (two values) returns 400 "exchange must be a single value".
  • Unrecognised sort, bias and quote values are ignored, not rejected: sort falls back to score, bias and quote apply no filter.
  • archetype entries outside the allowlist are dropped, so ?archetype=bogus returns the unfiltered board byte for byte.
  • Over 120 requests a minute returns 429 with a body whose error field reads "Internal Server Error", and a retry-after-market-medium header rather than a standard Retry-After.

Notes

  • limit and offset are not parameters. The row cap is a server constant of 150.
  • total is not a census. At most 800 index candidates are hydrated, and total counts the survivors of the filters inside that slice.
  • truncated:true means the index held more than 800 candidates, so read total as a floor.
  • Entry, stop and target are never served: tradePlan, keyLevels and archetype.triggerPrice are removed, and the narrative's "R:R x to y" clause is stripped. Structural levels are available on /public/detectors/{kind}; bare /public/detectors is a 404.
  • quote reads each market's quote asset from the venue catalogue. On 2026-09-30 exchange=okx-futures&timeframe=4h&quote=USDT returned total 282, the same as the call without quote, because every okx-futures market on the board is a USDT perp; the suffix match this replaced on 2026-09-15 returned 0 there. A venue whose catalogue is unavailable falls back to matching the end of the symbol.
  • htx-futures is on the accept-list but has no data: it returns total 0 on every timeframe.
  • sort=rr ranks by the trade plan's risk/reward ratio, which is not present in the response body.
  • Responses are cached 45 seconds per parameter combination.
  • A cache-miss call measured 1.1 to 2.7 seconds, including transfer of a ~580 KB binance body; a cache hit measured 1.3 seconds. Allow a client timeout of at least 10 seconds.
  • An unfiltered 150-row binance body is about 580 KB. Narrow it with minScore, archetype or bias.
  • The rate limit is counted per route per IP, not shared across the API.
▸Response fields(18)
exchangestring
Venue the board was read from, echoing the request.
totalnumber
Rows that passed the filters inside the hydrated slice. Not a venue census.
countnumber
Rows actually returned in setups[]. Never above 150.
truncatedboolean
true when more than 800 index candidates existed, so total is a floor.
setups[]array
Ranked setups, best first under the chosen sort.
setups[].symbolstring
Venue-native symbol, for example BTCUSDT, BTC_USDT or BTC-USDT-SWAP.
setups[].tfstring
Timeframe this setup was computed on. Varies per row when timeframe=all.
setups[].sqsnumber
Setup quality score, 0-100. A fired setup (breakout, trendline break, retest) is ranked by its type and participation; any other setup by a blend of context, event, participation, risk and alignment.
setups[].biasstring
Direction of the setup: bullish, bearish or neutral.
setups[].pricenumber
Last price, in the symbol's quote asset.
setups[].archetypeobject
key, label, direction, eventKind, barsSinceTrigger, and checklist[] of pass/fail items.
setups[].participation.rvolnumber
The latest closed candle's quote volume over the plain average of the candles before it (24 on 1h, 20 on 15m, 42 on 4h, 30 on 1d), as a ratio (4.04 = 4x): the same figure /public/detectors/volume carries as rvol. null across a missing candle or too little history.
setups[].narrativestring
One-line English summary. The risk/reward clause is stripped out.
setups[].computedAtnumber
Epoch ms of the close of the closed bar the setup was computed on.
setups[].canonicalstring|null
One display name for the instrument across venues, e.g. BINANCE:MOVRUSDT, in the format documented on /public/fast-search/markets. Display only: every other route takes symbol. null when the market is missing from the venue's instrument catalogue, and then so are the three fields below
setups[].instrumentKindstring|null
spot, perp, dated, expired, leveraged or rwa
setups[].quotestring|null
The market's quote asset from the venue catalogue, e.g. USDT. This is the value the quote filter matches
setups[].basestring|null
The venue's own base asset, upper-cased, with any multiplier kept (1000PEPE stays 1000PEPE). Read this rather than parsing symbol or canonical
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/setups?exchange=binance&timeframe=4h&minScore=80"
Response200
{
  "exchange": "binance",
  "timeframe": "4h",
  "total": 10,
  "count": 10,
  "setups": [
    {
      "confidence": 9.1,
      "bias": "bullish",
      "directionScore": 71,
      "regime": {
        "label": "STRONG TREND UP",
        "direction": "bullish"
      },
      "sqs": 90.5,
      "archetype": {
        "key": "pattern_breakout",
        "label": "Breakout: Ascending Broadening Wedge",
        "direction": "long",
        "eventKind": "pattern_breakout",
        "barsSinceTrigger": 3
      },
      "participation": {
        "rvol": 13.28,
        "takerFlowPct": 3,
        "liquidityUsd24h": 18402881
      },
      "symbol": "MOVRUSDT",
      "exchange": "binance",
      "tf": "4h",
      "price": 1.666,
      "trendDirection": "bullish",
      "multiTfConfirmed": true,
      "narrative": "Breakout: Ascending Broadening Wedge on 4h. Broke 3 bars ago. 13.3× volume. 5/6 checks pass. STRONG TREND UP.",
      "computedAt": 1790755199999,
      "canonical": "BINANCE:MOVRUSDT",
      "instrumentKind": "spot",
      "quote": "USDT",
      "base": "MOVR"
    }
  ],
  "truncated": false
}

setups[] truncated to 1 of 10 rows, and that row's categories, reasons, components, checklist, trendAlignment and remaining scoring fields removed to fit

GET/public/setups/by-base10 credits120/min

Best setup per coin

One compact row per base asset: the single best live setup score found for that coin anywhere on the five board venues, with the venue and timeframe it came from. Built to fill a score column on a board whose rows are coins rather than one venue's symbol list. It carries no setup body, so fetch /public/setups for the analysis behind a score.

Parameters

None. Everything this endpoint returns is pinned server-side.

Status and edge cases

  • The route accepts no input, so there is no 400 path.
  • Over 120 requests a minute returns 429 with a body whose error field reads "Internal Server Error", and a retry-after-market-medium header rather than a standard Retry-After.

Notes

  • Takes no parameters. The venue set, timeframe coverage and row count are all fixed server-side.
  • The venue set is pinned to binance, binance-futures, bybit-futures, okx-futures and gateio-futures. htx-futures is never searched.
  • One row per base asset: the best score anywhere wins, except that a dollar-quoted pair outranks a higher score on a BTC-quoted pair.
  • Never use base to call another endpoint. It is a join key with a leading 1000-style multiplier removed, and abbreviated multipliers such as 1M survive; pass symbol instead.
  • items[] is ordered alphabetically by base, not by score.
  • Rows carry no setup body: no levels, narrative, archetype or checklist. Fetch /public/setups for those.
  • Cached 30 seconds. The full body is about 60 KB for 733 rows.
  • symbol shape differs by venue: 0GUSDT on bybit-futures, 1INCH-USDT-SWAP on okx-futures, 4STOCK_USDT on gateio-futures.
  • The rate limit is counted per route per IP, not shared across the API.
▸Response fields(8)
exchanges[]array
Venues searched, in priority order. Fixed server-side to five.
countnumber
Number of base assets in items[]. No cap is applied.
items[]array
One row per base asset, ordered alphabetically by base.
items[].basestring
Join key: the venue's base asset with a leading 1 followed by three or more zeros removed (1000PEPE becomes PEPE, 10000SATS becomes SATS). No other multiplier is stripped, so 1MBABYDOGE stays 1MBABYDOGE and sits in items[] alongside BABYDOGE from 1000000BABYDOGEUSDT.
items[].symbolstring
Venue-native symbol the winning setup was found on.
items[].exchangestring
Venue that supplied the winning setup.
items[].tfstring
Timeframe of the winning setup: 15m, 1h, 4h, 1d or 1w.
items[].sqsnumber
Setup quality score of that winning setup, 0-100.
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/setups/by-base"
Response200
{
  "exchanges": [
    "binance",
    "binance-futures",
    "bybit-futures",
    "okx-futures",
    "gateio-futures"
  ],
  "count": 733,
  "items": [
    {
      "base": "0G",
      "symbol": "0GUSDT",
      "exchange": "binance-futures",
      "tf": "15m",
      "sqs": 89.1
    },
    {
      "base": "1INCH",
      "symbol": "1INCHUSDT",
      "exchange": "binance",
      "tf": "15m",
      "sqs": 73.7
    }
  ]
}

items[] truncated to 2 of 733 rows

09

Trend Scanner

3 endpoints

Directional trend scores per timeframe, across a venue or per base asset.

GET/public/trend-scanner5 credits120/min

Trend scanner matrix

A matrix of directional trend scores for one venue: one row per symbol, one score per timeframe, ranked by the timeframe you choose. Scores run -100 to 100 and are computed only on closed candles. The per-timeframe map is partial, so check that a timeframe key exists before reading it.

Query parameters

exchangeenumoptionaldefault binance
Venue to scan. Anything else returns 400 with the accepted list.
binancebinance-futuresbybit-futuresokx-futuresgateio-futureshtx-futures
sortenumoptionaldefault 1h
Timeframe to rank by. Rows missing that timeframe are still returned and sort last. An unknown value silently falls back to 1h.
15m1h4h1d1w
direnumoptionaldefault desc
desc puts the most bullish first, asc the most bearish. Only the exact lowercase string asc flips it; dir=ASC is treated as desc.
descasc
quoteenumoptional
Keep only markets quoted in this asset, read from the venue's instrument catalogue rather than from the spelling of the symbol, so BTC-USDT-SWAP on okx-futures and BTC_USDT on gateio-futures both match USDT. Case-insensitive. A value outside the allowlist applies no filter.
▸24 accepted values
USDTUSDCFDUSDTUSDUSDPDAIBTCETHBNBEURGBPTRYBRLARSJPYAUDMXNZARUSDXRPSOLDOGETRXDOT

Status and edge cases

  • An unknown exchange returns 400 listing the six accepted values.
  • A repeated ?exchange= (two values) returns 400 "exchange must be a single value".
  • An unknown sort silently falls back to 1h and an unknown quote applies no filter. Neither returns 400, so check the echoed sort in the body.
  • Over 120 requests a minute returns 429 with a body whose error field reads "Internal Server Error", and a retry-after-market-medium header rather than a standard Retry-After.

Notes

  • limit, offset and watchlistId are not parameters. The cap is a server constant of 300 rows.
  • scores is a partial map. A timeframe is dropped when its last computation is older than two timeframe lengths plus ten minutes. Measured on one 300-row binance response: 1w missing on 100 rows, 1d on 25, and 15m, 1h and 4h missing on none. Guard every key before reading it.
  • rsi is never present here. Only GET /public/trend-scanner/{exchange}/{symbol} carries it.
  • Candidates are the sort timeframe's index unioned with the 15m index, so coins scored only on shorter timeframes still appear and sort last.
  • quote reads each market's quote asset from the venue catalogue, so exchange=okx-futures&quote=USDT returns the full USDT board (284 rows on 2026-09-30, the same as without quote); the suffix match this replaced on 2026-09-15 returned 0 there. A venue whose catalogue is unavailable falls back to matching the end of the symbol.
  • htx-futures is on the accept-list but returns total 0.
  • Cached 45 seconds per parameter combination. A cache-miss call measured 0.65 to 2.0 seconds for a 20 to 165 KB body; allow a client timeout of at least 10 seconds.
  • Scores are recomputed only on closed candles, roughly every 5 minutes.
  • The rate limit is counted per route per IP, not shared across the API.
▸Response fields(20)
exchangestring
Venue scanned, echoing the request.
sortstring
Timeframe actually used for ranking, after the fallback to 1h.
dirstring
Sort direction applied, desc or asc
totalnumber
Fresh rows hydrated for this venue and filter. Not the venue's listing count.
countnumber
Rows returned in items[]. Never above 300.
items[]array
One row per symbol, ordered by the sort timeframe's score.
items[].symbolstring
Venue-native symbol, uppercase.
items[].exchangestring
Venue scanned, the same on every row
items[].pricenumber|null
Price from the freshest surviving timeframe, in the quote asset.
items[].computedAtnumber
Epoch ms of the close of the last closed candle on the freshest surviving timeframe, always a bar boundary minus 1 ms. Not a wall-clock computation time, so a row whose freshest timeframe is 1d or 1w is legitimately hours or days behind while still being current.
items[].scoresobject
Partial map keyed by timeframe (15m, 1h, 4h, 1d, 1w). Stale keys are absent.
items[].scores.<tf>.scorenumber
Signed trend score, -100 to 100. Negative is a downtrend.
items[].scores.<tf>.directionstring
bull, bear or neutral.
items[].scores.<tf>.persistencenumber
How steadily the trend has held, -1 to 1.
items[].scores.<tf>.contributorsnumber
Count of indicators that fed this score.
items[].scores.<tf>.basisstring
full when every input was available, reduced when some were missing.
items[].canonicalstring|null
One display name for the instrument across venues, e.g. BINANCE:TWTUSDT, in the format documented on /public/fast-search/markets. Display only: every other route takes symbol. null when the market is missing from the venue's instrument catalogue, and then so are the three fields below
items[].instrumentKindstring|null
spot, perp, dated, expired, leveraged or rwa
items[].quotestring|null
The market's quote asset from the venue catalogue, e.g. USDT. This is the value the quote filter matches
items[].basestring|null
The venue's own base asset, upper-cased, with any multiplier kept (1000PEPE stays 1000PEPE). Read this rather than parsing symbol or canonical
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/trend-scanner?exchange=binance&sort=4h&dir=desc&quote=USDT"
Response200
{
  "exchange": "binance",
  "sort": "4h",
  "dir": "desc",
  "total": 408,
  "count": 300,
  "items": [
    {
      "symbol": "TWTUSDT",
      "exchange": "binance",
      "price": 0.5987,
      "computedAt": 1790768699999,
      "scores": {
        "4h": {
          "score": 94,
          "basis": "full",
          "direction": "bull",
          "persistence": 0.7,
          "contributors": 10
        },
        "1h": {
          "score": 66,
          "basis": "full",
          "direction": "bull",
          "persistence": 0.9,
          "contributors": 10
        },
        "15m": {
          "score": -26,
          "basis": "full",
          "direction": "bear",
          "persistence": 0.5,
          "contributors": 9
        }
      },
      "canonical": "BINANCE:TWTUSDT",
      "instrumentKind": "spot",
      "quote": "USDT",
      "base": "TWT"
    }
  ]
}

items[] truncated to 1 of 300 rows, and that row's scores map trimmed to 3 of the 5 timeframes it returned (1d and 1w dropped)

GET/public/trend-scanner/by-base10 credits120/min

Trend by base asset

The trend matrix inverted: one row per base asset instead of one per venue symbol, so it joins onto a coin list without gaps. For each coin it picks a single pair from the first of five priority-ordered venues that has a live score. There is no ranking and no row cap.

Parameters

None. Everything this endpoint returns is pinned server-side.

Status and edge cases

  • The route accepts no input, so there is no 400 path.
  • Over 120 requests a minute returns 429 with a body whose error field reads "Internal Server Error", and a retry-after-market-medium header rather than a standard Retry-After.

Notes

  • Takes no parameters. The venue list and row count are fixed server-side.
  • Venues are searched in priority order and the first one with a live score for a coin wins the row: binance, binance-futures, bybit-futures, okx-futures, gateio-futures. htx-futures is never searched.
  • One pair per coin, not four. A dollar-quoted pair is preferred over a BTC-quoted one even on a lower-priority venue.
  • Never use base to call another endpoint. It is a join key with a leading 1000-style multiplier removed, and abbreviated multipliers such as 1M survive; pass symbol instead.
  • items[] is ordered alphabetically by base, not by score.
  • scores is a partial map: a timeframe is dropped when its last computation is older than two timeframe lengths plus ten minutes. Guard every key.
  • rsi is never present here. Only GET /public/trend-scanner/{exchange}/{symbol} carries it.
  • Cached 30 seconds. The full body is about 365 KB for 721 rows.
  • The rate limit is counted per route per IP, not shared across the API.
▸Response fields(15)
exchanges[]array
Venues searched, in the priority order used to pick each row.
countnumber
Number of base assets in items[]. No cap is applied.
items[]array
One row per base asset, ordered alphabetically by base.
items[].basestring
Join key: the venue's base asset with a leading 1 followed by three or more zeros removed (1000PEPE becomes PEPE, 10000SATS becomes SATS). No other multiplier is stripped, so 1MBABYDOGE stays 1MBABYDOGE and sits in items[] alongside BABYDOGE from 1000000BABYDOGEUSDT.
items[].symbolstring
Venue-native symbol the scores were read from. Use this, not base, for other calls.
items[].exchangestring
Venue that supplied this row.
items[].quotestring
Quote asset of the chosen pair, for example USDT.
items[].pricenumber|null
Price from the freshest surviving timeframe, in the quote asset.
items[].computedAtnumber
Epoch ms of the close of the last closed candle on the freshest surviving timeframe, always a bar boundary minus 1 ms. Not a wall-clock computation time.
items[].scoresobject
Partial map keyed by timeframe (15m, 1h, 4h, 1d, 1w). Stale keys are absent.
items[].scores.<tf>.scorenumber
Signed trend score, -100 to 100. Negative is a downtrend.
items[].scores.<tf>.directionstring
bull, bear or neutral.
items[].scores.<tf>.persistencenumber
How steadily the trend has held, -1 to 1.
items[].scores.<tf>.contributorsnumber
Count of indicators that fed this score.
items[].scores.<tf>.basisstring
full when every input was available, reduced when some were missing.
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/trend-scanner/by-base"
Response200
{
  "exchanges": [
    "binance",
    "binance-futures",
    "bybit-futures",
    "okx-futures",
    "gateio-futures"
  ],
  "count": 720,
  "items": [
    {
      "base": "0G",
      "symbol": "0GUSDT",
      "exchange": "binance",
      "quote": "USDT",
      "price": 0.1968,
      "computedAt": 1789244099999,
      "scores": {
        "1h": {
          "score": 60,
          "basis": "full",
          "direction": "bull",
          "persistence": 0.6,
          "contributors": 9
        },
        "15m": {
          "score": 60,
          "basis": "full",
          "direction": "bull",
          "persistence": 1,
          "contributors": 11
        }
      }
    }
  ]
}

items[] truncated to 1 of 720 rows, and that row's scores map trimmed to 2 of the 4 timeframes it returned (4h and 1d dropped)

GET/public/trend-scanner/{exchange}/{symbol}1 credit120/min

Trend for one symbol

Trend scores for a single venue-native symbol, one entry per timeframe. This is the only trend route that returns RSI. A symbol with no live score returns HTTP 200 with found:false, so branch on the body rather than on the status code.

Path parameters

exchangeenumrequired
Venue the symbol belongs to. Lower-cased server-side; anything else returns 400 with the accepted list.
binancebinance-futuresbybit-futuresokx-futuresgateio-futureshtx-futures
symbolstringrequired
Venue-native symbol, for example BTCUSDT, BTC-USDT-SWAP or BTC_USDT. Upper-cased server-side, then required to match ^[A-Z0-9._-]{2,30}$; a shorter or longer value returns 400 "Malformed symbol".

Status and edge cases

  • An unknown coin returns 200 with found:false and item:null, not a 404. /public/trend-scanner/binance/NOTACOIN123 is the verified case.
  • An unknown exchange returns 400 listing the six accepted values.
  • A symbol that fails ^[A-Z0-9._-]{2,30}$ returns 400 "Malformed symbol"; a single character such as /binance/B is rejected.
  • Over 120 requests a minute returns 429 with a body whose error field reads "Internal Server Error", and a retry-after-market-medium header rather than a standard Retry-After.

Notes

  • This is the only trend route that returns rsi. The matrix routes omit it entirely.
  • rsi can be null on a young listing, or on 1w for a coin without roughly 15 weeks of candles. Render it as a dash; never substitute 50 or 0.
  • The symbol is upper-cased before the lookup, so /binance/btcusdt works.
  • Symbols are venue-native and differ in shape: BTCUSDT on binance, BTC-USDT-SWAP on okx-futures, BTC_USDT on gateio-futures. Get valid symbols from /public/trend-scanner or /public/trend-scanner/by-base.
  • scores is a partial map, dropping any timeframe whose last computation is older than two timeframe lengths plus ten minutes. Guard every key.
  • No result cache sits in front of this route; it reads current state on every call.
  • The rate limit is counted per route per IP, not shared across the API.
▸Response fields(15)
exchangestring
Venue, lower-cased, echoing the request.
symbolstring
Symbol, upper-cased, echoing the request.
foundboolean
false when the symbol has no live trend score on that venue.
itemobject
The trend row, or null when found is false.
item.symbolstring
Symbol, upper-cased, as stored
item.exchangestring
Venue, lower-cased
item.pricenumber|null
Price from the freshest surviving timeframe, in the quote asset.
item.computedAtnumber
Epoch ms of the close of the last closed candle on the freshest surviving timeframe, always a bar boundary minus 1 ms. Not a wall-clock computation time.
item.scoresobject
Partial map keyed by timeframe (15m, 1h, 4h, 1d, 1w). Stale keys are absent.
item.scores.<tf>.scorenumber
Signed trend score, -100 to 100. Negative is a downtrend.
item.scores.<tf>.directionstring
bull, bear or neutral.
item.scores.<tf>.persistencenumber
How steadily the trend has held, -1 to 1.
item.scores.<tf>.contributorsnumber
Count of indicators that fed this score.
item.scores.<tf>.basisstring
full when every input was available, reduced when some were missing.
item.scores.<tf>.rsinumber|null
RSI-14 on that timeframe including the candle still forming, as a chart draws it, 0-100; at most one 5-minute cycle old, and on the last closed candle when the market's live feed is behind. null when there is not enough history. The trend score beside it is computed on closed candles.
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/trend-scanner/binance/BTCUSDT"
Response200
{
  "exchange": "binance",
  "symbol": "BTCUSDT",
  "found": true,
  "item": {
    "symbol": "BTCUSDT",
    "exchange": "binance",
    "price": 77072.01,
    "computedAt": 1789244099999,
    "scores": {
      "1d": {
        "score": 25,
        "basis": "full",
        "direction": "bull",
        "persistence": 0.95,
        "contributors": 7,
        "rsi": 54.9
      },
      "4h": {
        "score": -43,
        "basis": "full",
        "direction": "bear",
        "persistence": -0.8,
        "contributors": 9,
        "rsi": 39.9
      },
      "1h": {
        "score": -52,
        "basis": "full",
        "direction": "bear",
        "persistence": 0.3,
        "contributors": 10,
        "rsi": 42
      }
    }
  }
}

item.scores trimmed to 3 of the 5 timeframes returned (15m and 1w dropped)

10

Price action

3 endpoints

Detector hits, distance from all-time high and low, and sharp recent moves.

GET/public/detectors/{kind}5 credits120/min

25 credits when kind=volume on a futures exchange

Detector hits by kind

One call returns every current hit from a single detector family across the coins of one venue and timeframe. The six families are independent scans and the shape of items[].item depends on which one you ask for. The row cap is a server constant of 150, or 500 for kind=levels, and there is no way to page past it.

Path parameters

kindenumrequired
Detector family to read. Any other value returns 400 with the allowed list in the message.
patternstrendlinesdivergencescandlestickslevelsvolume

Query parameters

exchangeenumoptionaldefault binance
Venue to scan, lower-cased before matching. htx-futures is accepted but every kind returns total 0.
binancebinance-futuresbybit-futuresokx-futuresgateio-futureshtx-futures
timeframeenumoptionaldefault 15m
Candle timeframe of the snapshot. Any other value, including sub-15m, returns 400.
15m1h4h1d1w
quoteenumoptional
Keep only markets quoted in this asset, read from the venue's instrument catalogue rather than from the spelling of the symbol, so BTC-USDT-SWAP on okx-futures and BTC_USDT on gateio-futures both match USDT. Case-insensitive. A value outside the list is ignored and the full board is returned.
▸24 accepted values
USDTUSDCFDUSDTUSDUSDPDAIBTCETHBNBEURGBPTRYBRLARSJPYAUDMXNZARUSDXRPSOLDOGETRXDOT

Status and edge cases

  • Unknown kind returns 400: 'Unknown detector "bogus". Allowed: patterns, trendlines, divergences, candlesticks, levels, volume'.
  • Unsupported exchange returns 400 listing all six accepted venues.
  • Invalid timeframe returns 400 listing the five accepted timeframes.
  • Repeating ?exchange= or ?timeframe= returns 400 'exchange and timeframe must each be a single value'.
  • An unrecognised quote returns 200 with the board unfiltered, not a 400.
  • exchange=htx-futures returns 200 with total 0, count 0 and an empty items array.
  • Over 120 requests per minute the throttler returns 429; remaining quota is on the x-ratelimit-remaining-market-medium header (429 behaviour not exercised against production).

Notes

  • There is no limit, offset, page or cursor parameter. The cap is 150 rows, except kind=levels which returns 500.
  • total counts matched rows before the cap. With patterns on binance 4h, total was 504 and only 150 rows came back; the rest are unreachable.
  • Candidates are the top 800 entries of the per-kind index detector:index:{kind}:{exchange}:{timeframe}, so total is the match count over that 800-symbol window, not over the whole venue. quote is applied after that truncation, so a quote whose pairs rank below the window under-counts.
  • A coin emits several rows. Measured live on binance 4h: patterns 1.0 and volume 1.0 rows per coin, divergences 1.2, trendlines 1.2, candlesticks 1.8 (150 rows spanned 84 symbols), levels 19.2 (500 rows spanned 26 symbols).
  • items[].item has a different shape for every kind. candlesticks carries name/class/direction/state (complete, setup or confirmed) and, since 2026-10-01, candles[] (the open time and OHLC of every candle the pattern is made of), completedAt, checks[], context and, for a setup, confirm (the level a later close must cross); its reliability field is a fixed per-name weight, not a measured rate. levels carries type/label/price/kind/proximityPct; label is the level's identity (Pivot R1, Fib 0.618) and never changes with price; kind is only the side of items[].price the level sat on when computed (a level AT that price counts as resistance), a position, not a role; proximityPct is measured from that same price, which on 1d and 1w is the last closed period's close. Newer rows also carry availableAt (the close time of the last candle the level needed), period on pivots (sourceOpen, sourceClose, validFrom, validTo: the set applies to the period after its source candle) and swings[] on swing and Fibonacci levels (each swing's time and confirmedAt). trendlines and patterns carry pivot geometry with a score, divergences carries points[] and volume carries rvol plus volume context. Do not write one parser for all six.
  • kind=volume rows written since 2026-10-01 carry rules: 2. Their rvol is the signal candle's own quote volume divided by the plain mean of the baseline candles right before it (candle and baseline carry both figures and the window), and every volume figure is in the quote currency (unit: 'quote'). confirmed/confirmedLevel mean a close across a pivot or Fibonacci level that was in effect while that candle traded (level, frozen at that value), not a structural breakout. direction is 'unknown' with no buyPct where the venue publishes no taker split (bybit-futures, okx-futures and gateio-futures), never the candle's colour. classification 'exhaustion' is a candidate shape (candleRead), not a confirmed reversal. Older rows lack these fields, and their rvol is the larger of the candle's ratio and the last three candles' average.
  • Rows are ordered by the item's own score when it has one, then by items[].confidence. kind=divergences is the exception since 2026-10-01: newest first by item.confirmedAt (the newer pivot's time on an older row), then by score, so the 150-row cap keeps the most recent rather than an arbitrary slice of a near-flat score.
  • kind=divergences items written since 2026-10-01 also carry oscillator[] (the two indicator swings the type was decided on, each with its candle's open time and the indicator's value), confirmedAt (the close time of the candle that completed the divergence, at least four candles after its newer pivot) and closedBeyondAt (the close time of the first candle that closed through the newer pivot, against the divergence; null while none has). A divergence stays listed until newer swings replace it, so read confirmedAt before treating one as current. Its score is how cleanly both swings formed times a fixed per-indicator weight; it does not include age and is not a probability.
  • kind=patterns hides invalidated patterns and drops any pattern scoring below 30.
  • kind=volume on a futures venue joins open-interest and 1h liquidation context onto items[].item (oiTrend, oiChangePct, liq1h). Spot venues have neither.
  • items[].computedAt is candle-close aligned: all 150 rows on the binance 4h board shared 1789243199999 (2026-09-12T19:59:59.999Z).
  • Responses are cached server-side for 75 s. A cold call to kind=volume has been measured at 11 s; use a client timeout of 30 s or more.
  • The binance spot boards include tokenized-equity instruments such as AMDBUSDT, SOXLBUSDT and HOODBUSDT, not only crypto.
  • quote filters on the market's quote asset from the venue catalogue, so quote=BTC on binance returns BTC-quoted pairs such as NEXOBTC and NEARBTC, not Bitcoin itself. A venue whose catalogue is unavailable falls back to matching the end of the symbol.
▸Response fields(19)
kindstring
Echo of the path parameter
exchangestring
Echo of the resolved venue, lower-case
timeframestring
Echo of the resolved timeframe
totalnumber
Rows matched before the server cap
countnumber
Rows returned, equal to items.length
itemsarray
Detector hits, strongest first
items[].symbolstring
Venue symbol, e.g. ZRXUSDT
items[].exchangestring
Venue the snapshot was computed on
items[].tfstring
Timeframe of the snapshot
items[].pricenumber|null
Last price in the quote currency; null when the snapshot carried none
items[].confidencenumber
Coin-level setup confidence; higher is stronger (observed 6.9 to 8.6 on one board)
items[].directionScorenumber
Directional score for the coin; observed range -100 to 100
items[].biasstring
Coin bias: bullish, bearish or neutral
items[].computedAtnumber
When the snapshot was computed, epoch milliseconds; candle-close aligned, so every row on one board carries the same value
items[].itemobject
The detector payload itself; keys differ per kind
items[].canonicalstring|null
One display name for the instrument across venues, e.g. BINANCE:MOVRUSDT, in the format documented on /public/fast-search/markets. Display only: every other route takes symbol. null when the market is missing from the venue's instrument catalogue, and then so are the three fields below
items[].instrumentKindstring|null
spot, perp, dated, expired, leveraged or rwa
items[].quotestring|null
The market's quote asset from the venue catalogue, e.g. USDT. This is the value the quote filter matches
items[].basestring|null
The venue's own base asset, upper-cased, with any multiplier kept (1000PEPE stays 1000PEPE). Read this rather than parsing symbol or canonical
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/detectors/candlesticks?exchange=binance&timeframe=4h"
Response200
{
  "kind": "candlesticks",
  "exchange": "binance",
  "timeframe": "4h",
  "total": 586,
  "count": 150,
  "items": [
    {
      "symbol": "MOVRUSDT",
      "exchange": "binance",
      "tf": "4h",
      "price": 1.666,
      "confidence": 9.1,
      "directionScore": 71,
      "bias": "bullish",
      "computedAt": 1790755199999,
      "item": {
        "name": "Belt Hold",
        "class": "reversal",
        "direction": "bull",
        "reliability": "low",
        "index": 498
      },
      "canonical": "BINANCE:MOVRUSDT",
      "instrumentKind": "spot",
      "quote": "USDT",
      "base": "MOVR"
    }
  ]
}

items[] truncated to 1 of 150 rows

GET/public/athatl5 credits120/min

ATH and ATL board

Ranks a venue's coins by how far they sit from their all-time high and all-time low, with drawdown, recovery multiple and days since the ATH. The ATH/ATL marks come from CoinGecko and cover the coin's whole history, not just this venue's candles. The board returns at most 300 rows and does not echo the filters you sent.

Query parameters

exchangeenumoptionaldefault binance
Venue whose symbol list is ranked, lower-cased before matching. htx-futures is accepted but returns an empty board.
binancebinance-futuresbybit-futuresokx-futuresgateio-futureshtx-futures
quoteenumoptional
Keep only markets quoted in this asset, read from the venue's instrument catalogue rather than from the spelling of the symbol, so BTC-USDT-SWAP on okx-futures and BTC_USDT on gateio-futures both match USDT. Case-insensitive. A value outside the list is ignored rather than rejected.
▸24 accepted values
USDTUSDCFDUSDTUSDUSDPDAIBTCETHBNBEURGBPTRYBRLARSJPYAUDMXNZARUSDXRPSOLDOGETRXDOT
sortenumoptionaldefault drawdown
Row order: drawdown = deepest below ATH first, nearHigh = closest to ATH first, nearLow = closest to ATL first, mcap = best market-cap rank first, newHigh/newLow = rows printing a new extreme first. An unrecognised value silently falls back to drawdown.
drawdownnearHighnearLowmcapnewHighnewLow
minDrawdownintegeroptional
Keep only coins at least this many percent below their ATH. The value is absolute-valued, rounded to an integer and clamped to 0-100, so -90 and 90.4 both mean 90; a non-numeric value is ignored.
nearHighbooleanoptional
Keep only coins flagged as near their ATH (within about 5 percent). Only the literal true or 1 is truthy; nearHigh=yes is read as false and returns the whole board.
true1
nearLowbooleanoptional
Keep only coins within about 5 percent above their ATL. Only the literal true or 1 is truthy.
true1
newHighbooleanoptional
Keep only coins whose all-time high was set in the last 24 hours, by CoinGecko or by this venue's own price since CoinGecko last updated, and whose price is still within 5% of it. Only the literal true or 1 is truthy.
true1
newLowbooleanoptional
Keep only coins whose all-time low was set in the last 24 hours and whose price is still within 5% above it, the mirror of newHigh. Only the literal true or 1 is truthy.
true1

Status and edge cases

  • Unsupported exchange returns 400 listing the six accepted venues.
  • Repeating ?exchange= returns 400 'exchange must be a single value'.
  • An unrecognised sort silently falls back to drawdown and still returns 200; verified that sort=bogus and sort=drawdown returned the same first row.
  • An unrecognised quote or a non-numeric minDrawdown is ignored and the board comes back unfiltered.
  • nearHigh=yes returned the full 404-row match while nearHigh=true returned 3, so a non-literal truthy value silently disables the filter.
  • exchange=htx-futures returns 200 with {"total":0,"count":0,"items":[]}.
  • Over 120 requests per minute the throttler returns 429 (429 behaviour not exercised against production).

Notes

  • The response does not echo the request. There is no exchange, quote or sort key in the body, unlike every other board in this group.
  • items[].tf is the empty string on every row and items[].exchange only repeats the venue you asked for. Neither carries information.
  • The ATH/ATL marks are third-party: items[].item.source was 'coingecko' on all 300 sampled rows, with cgId and cgName naming the matched coin. Rows written before the worker carried that identity have neither field.
  • There is no limit, offset or page parameter. The cap is 300 rows and total can exceed it (404 observed on binance USDT), so the tail is unreachable.
  • Candidates are the venue's top 800 symbols by market cap, so a low-cap listing can be absent even when it has a blob.
  • quote filters on the market's quote asset from the venue catalogue. quote=BTC on binance returned total 0 on 2026-09-30 because all 586 binance rows on this board are dollar-quoted (USDT, USDC or FDUSD).
  • drawdownPct is negative. Sorting by drawdown puts the most-negative (deepest) rows first; sorting by nearHigh reverses that.
  • Rows also carry item.newHigh, item.newLow, item.nearHigh and item.deepDrawdown booleans, plus confidence, directionScore and bias copied from the coin's setup snapshot.
  • item.newLow is absent on blobs written before the compute stored it; it was present on all 300 sampled rows.
  • Responses are cached server-side for up to 75 s, and rebuilt as soon as the venue's rows are re-derived, which happens a few seconds after each five-minute scan lands.
  • item.athUsd and item.atlUsd are CoinGecko's marks, raised or lowered by this venue's own price when it trades past them between CoinGecko's twice-daily updates; newHigh and newLow mean the mark was set in the last 24 hours and price is still within 5% of it; a market that moves further away keeps the mark and its date but drops the flag.
▸Response fields(20)
totalnumber
Rows matched by the filters before the 300-row cap
countnumber
Rows returned, equal to items.length
itemsarray
Board rows in the requested sort order
items[].symbolstring
Venue symbol, e.g. LUNCUSDT
items[].pricenumber|null
The venue's price per coin (a contract multiplier divided out), from the latest five-minute scan
items[].priceAtnumber|null
When price was read by that scan, epoch milliseconds. Absent on rows derived before 2026-10-02
items[].computedAtnumber
When the marks were last derived from that price, epoch milliseconds, not the price's own time
items[].item.athUsdnumber
All-time high price, USD
items[].item.athDatestring|null
When the ATH printed, ISO 8601 string: CoinGecko's date, or when this venue's price passed it since CoinGecko last updated
items[].item.atlUsdnumber
All-time low price, USD
items[].item.atlDatestring|null
When the ATL printed, ISO 8601 string, dated the same way as athDate
items[].item.drawdownPctnumber
Percent below the ATH, always negative or zero
items[].item.upFromAtlPctnumber|null
Percent above the ATL; null when the ATL is unknown
items[].item.recoveryMultnumber|null
Multiple needed to regain the ATH, a ratio (athUsd / price)
items[].item.daysSinceAthnumber|null
Whole days since the ATH printed
items[].item.mcapRanknumber|null
Market-cap rank; null on 2 of 300 sampled rows
items[].canonicalstring|null
One display name for the instrument across venues, e.g. BINANCE:LUNCUSDT, in the format documented on /public/fast-search/markets. Display only: every other route takes symbol. null when the market is missing from the venue's instrument catalogue, and then so are the three fields below
items[].instrumentKindstring|null
spot, perp, dated, expired, leveraged or rwa
items[].quotestring|null
The market's quote asset from the venue catalogue, e.g. USDT. This is the value the quote filter matches
items[].basestring|null
The venue's own base asset, upper-cased, with any multiplier kept (1000PEPE stays 1000PEPE). Read this rather than parsing symbol or canonical
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/athatl?exchange=binance&quote=USDT&sort=drawdown"
Response200
{
  "total": 407,
  "count": 300,
  "items": [
    {
      "symbol": "LUNCUSDT",
      "exchange": "binance",
      "tf": "",
      "price": 0.00005327,
      "confidence": 5.6,
      "directionScore": 50,
      "bias": "bullish",
      "computedAt": 1790769035191,
      "item": {
        "athUsd": 119.18,
        "athDate": "2022-04-05T04:24:58.000Z",
        "atlUsd": 9.99967e-7,
        "atlDate": "2022-05-12T18:34:40.000Z",
        "mcapRank": 157,
        "source": "coingecko",
        "cgId": "terra-luna",
        "cgName": "Terra Luna Classic",
        "drawdownPct": -100,
        "upFromAtlPct": 5227.18,
        "recoveryMult": 2237281.77,
        "daysSinceAth": 1639,
        "newHigh": false,
        "newLow": false,
        "nearHigh": false,
        "deepDrawdown": true
      },
      "canonical": "BINANCE:LUNCUSDT",
      "instrumentKind": "spot",
      "quote": "USDT",
      "base": "LUNC"
    }
  ]
}

items[] truncated to 1 of 300 rows

Powered by CoinGecko

GET/public/pumping/events5 credits120/min

Pump and dump events

A merged, newest-first feed of short-window price moves and new 24-hour highs and lows detected across the scanned venues. Each row carries the percent move, the 24h quote volume and a relative-volume reading, so a thin spike can be told apart from a funded one. The response is capped at 300 rows while count reports the full pre-cap match.

Query parameters

exchangeenumoptional
Restrict to one venue, lower-cased before matching. Omit it and all five feeds are merged. An unknown value returns 400.
binancebinance-futuresbybit-futuresokx-futuresgateio-futures
typesstringoptional
Comma-separated list of event types to keep. Unknown tokens are dropped and duplicates de-duplicated; if nothing recognisable survives, no type filter is applied.
pump_1mpump_5mpump_10mdump_1mdump_5mdump_10m24h_high24h_low
minPctintegeroptionaldefault 0
Minimum absolute percent move to keep. Rounded to the nearest integer and floored at 0, and compared against abs(pct), so it keeps dumps as well as pumps. A non-numeric value is read as 0.
pairenumoptional
Keep only events on markets quoted in this asset, read from the venue's instrument catalogue (so ZIL-USDT-SWAP on okx-futures matches pair=USDT), uppercased before matching. A value outside the list is ignored and the feed comes back unfiltered.
▸24 accepted values
USDTUSDCFDUSDTUSDUSDPDAIBTCETHBNBEURGBPTRYBRLARSJPYAUDMXNZARUSDXRPSOLDOGETRXDOT

Status and edge cases

  • Unsupported exchange returns 400 listing the five accepted venues; note this list is one shorter than the six that /public/detectors and /public/athatl accept.
  • Repeating ?exchange= returns 400 as well, with the two values joined in the message.
  • types=bogus returns 200 with the full unfiltered feed (300 items, count 5000), not a 400.
  • pair=XYZ returns 200 with the feed unfiltered; only the 24 allowlisted quote assets filter anything.
  • minPct=abc returns 200 and is treated as minPct=0.
  • Over 120 requests per minute the throttler returns 429 (429 behaviour not exercised against production).

Notes

  • count is the pre-cap matched total, not the number of rows returned. An unfiltered call returned count 5000 with 300 items.
  • There is no limit, offset, page or cursor parameter. A caller-supplied limit is ignored and the cap is a fixed 300 rows.
  • Each venue feed holds at most 1000 events, so the unfiltered pool across the five venues is 5000 and roughly 4,700 of them are unreachable.
  • Omitting exchange merges all five venues. One unfiltered 300-row sample split binance-futures 85, binance 67, bybit-futures 54, gateio-futures 49, okx-futures 45.
  • 24h extremes dominate the unfiltered feed: 210 24h_low and 55 24h_high against 35 short-window moves in one 300-row sample. Pass types if you only want pumps or dumps.
  • The accepted venue list is environment-driven in production (a PD_VENUES override) and can change without a code release. The 400 error body is the live source of truth.
  • Besides the fields above, rows also carry prevPrice, volConfirmed, new24hHigh, new24hLow, bias and liq1h (1h liquidation USD). liq1h was null on 113 of 300 sampled rows.
  • items[].spottedAt is the detection time in epoch milliseconds and is what the feed is sorted by, newest first.
  • The feed is served live with no guest delay. The service cache is short, about 15 s by default.
▸Response fields(19)
itemsarray
Matching events, newest first, capped at 300
countnumber
Events matched before the 300-row cap, not items.length
updatedAtnumber
When the response was assembled, epoch milliseconds
items[].symbolstring
Venue symbol; can contain non-ASCII characters
items[].exchangestring
Venue the event was detected on
items[].typestring
Event type, one of the eight values accepted by types
items[].directionstring
pump, dump, high or low
items[].windowstring
Move window: 1m, 5m, 10m, or 24h for the extreme events
items[].pctnumber
Percent move over the window; negative on dumps and 24h_low rows
items[].pricenumber
Price at detection, in the quote currency
items[].quoteVolume24hnumber
Rolling 24h volume in the quote currency
items[].rvolnumber|null
Volume relative to its baseline, a ratio; null when no baseline exists
items[].classificationstring
continuation, exhaustion or neutral
items[].setupScorenumber|null
Smart Setups score for the coin at detection time
items[].spottedAtnumber
Detection time, epoch milliseconds; the feed is sorted by it, newest first
items[].canonicalstring|null
One display name for the instrument across venues, e.g. BINANCE:PHAROSUSDT.P, in the format documented on /public/fast-search/markets. Display only: every other route takes symbol. null when the market is missing from the venue's instrument catalogue, and then so are the three fields below
items[].instrumentKindstring|null
spot, perp, dated, expired, leveraged or rwa
items[].quotestring|null
The market's quote asset from the venue catalogue, e.g. USDT. This is the value the quote filter matches
items[].basestring|null
The venue's own base asset, upper-cased, with any multiplier kept (1000PEPE stays 1000PEPE). Read this rather than parsing symbol or canonical
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/pumping/events?exchange=binance-futures&types=pump_5m&minPct=3"
Response200
{
  "items": [
    {
      "symbol": "PHAROSUSDT",
      "exchange": "binance-futures",
      "type": "pump_5m",
      "direction": "pump",
      "window": "5m",
      "pct": 5.7,
      "price": 0.7157,
      "prevPrice": 0.6771,
      "quoteVolume24h": 8262189,
      "rvol": 4.67,
      "volConfirmed": true,
      "new24hHigh": false,
      "new24hLow": false,
      "classification": "continuation",
      "setupScore": 5.6,
      "bias": "bearish",
      "liq1h": 0,
      "spottedAt": 1790768646581,
      "canonical": "BINANCE:PHAROSUSDT.P",
      "instrumentKind": "perp",
      "quote": "USDT",
      "base": "PHAROS"
    }
  ],
  "count": 30,
  "updatedAt": 1790769070400
}

items[] truncated to 1 representative row of 30

11

Candles and quotes

4 endpoints

The raw OHLCV series behind the charts, the instrument catalogue for each venue, and live quotes for up to 30 markets in one call.

GET/public/ohlcv/{exchange}/symbols1 credit60/min

Venue symbol catalogue

Lists the instruments that have candle data on a venue. Use it to get the exact symbol spelling the candles endpoint expects, and the tickSize that gives a chart a correct price axis. The whole catalogue comes back in one response; there is no paging and no filter.

Path parameters

exchangeenumrequired
Venue id, lowercased server-side. Underscore spellings such as binance_futures return 400.
binancebinance-futuresbybit-futuresokx-futuresgateio-futureshtx-futures

Status and edge cases

  • An unsupported or misspelled exchange returns 400 with the message naming all six allowed ids.
  • If the underlying cache read fails, the route returns 200 with count 0 and symbols [] rather than a 5xx. Treat count 0 as no data, not as an empty venue.
  • Sending an Origin header the API does not allow returns 500. Call this server to server.

Notes

  • tickSize is a string, not a number, and keeps the venue's own trailing zeros ("0.01000000"). Parse it, do not compare it as text.
  • tickSize is optional in the schema. All 828 binance rows carried one on 2026-09-12, but code defensively for its absence.
  • The response is the full catalogue in one body. Observed sizes: binance 828, bybit-futures 639, okx-futures 281, htx-futures 109.
  • The 60/min bucket is per route, not per venue: three calls to three different venues count against one counter.
  • Cache the result. It changes when the venue lists or delists, not per request.
▸Response fields(8)
exchangestring
Venue id, echoed back lowercased
countnumber
Number of entries in symbols[]
symbols[]array
The venue's chartable instruments
symbols[].symbolstring
Venue-native pair symbol, the exact value the candles route takes
symbols[].basestring
Base asset ticker, uppercase
symbols[].quotestring
Quote asset ticker, uppercase
symbols[].tickSizestring
Venue-declared minimum price increment, as the venue's own decimal string; may be absent
symbols[].canonicalstring|null
One display name for the instrument across venues, e.g. BINANCE:ETHBTC, in the format documented on /public/fast-search/markets. Display only: the candles route takes symbol. null on symbols whose names are not ASCII (4 of 742 on binance on 2026-09-30)
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/ohlcv/binance/symbols"
Response200
{
  "exchange": "binance",
  "count": 742,
  "symbols": [
    {
      "symbol": "ETHBTC",
      "base": "ETH",
      "quote": "BTC",
      "tickSize": "0.00001000",
      "canonical": "BINANCE:ETHBTC"
    },
    {
      "symbol": "LTCBTC",
      "base": "LTC",
      "quote": "BTC",
      "tickSize": "0.00000100",
      "canonical": "BINANCE:LTCBTC"
    }
  ]
}

symbols[] truncated to 2 of 742 rows

GET/public/ohlcv/{exchange}/{symbol}/{timeframe}1 credit150/min

OHLCV candles

Returns open/high/low/close/volume bars for a single market on one of six venues. Bars are read straight from the candle cache, so depth is whatever the cache currently holds, not an unbounded history. The symbol must be in the venue's own native spelling (BTCUSDT, BTC-USDT-SWAP, BTC_USDT); take it from the venue's symbol catalogue, not from the search endpoint.

Path parameters

exchangeenumrequired
Venue id, lowercased server-side so OKX-FUTURES works; anything else returns 400 listing the six allowed ids.
binancebinance-futuresbybit-futuresokx-futuresgateio-futureshtx-futures
symbolstringrequired
Venue-native pair symbol, not normalised (BTCUSDT, BTC-USDT-SWAP, BTC_USDT). Uppercased server-side, so btcusdt resolves.
timeframeenumrequired
Candle interval. 1s is deliberately not served here and returns 400.
1m3m5m15m30m1h4h1d1w

Query parameters

fromintegeroptional
Lower bound on openTime, epoch ms, inclusive. A non-numeric value returns 400. It does not page forward: when the range holds more than limit bars the NEWEST limit bars are returned, so from=<an old time>&limit=1500 still ends at the latest bar. Page backwards with to.
tointegeroptional
Upper bound on openTime, epoch ms, inclusive. A non-numeric value returns 400. This is the paging parameter: to read the page before the one you hold, set to to the oldest openTime you have, minus 1.
limitintegeroptionaldefault 500
Max bars returned, floored to an integer and clamped to 1500. Zero, negative or non-numeric returns 400.

Status and edge cases

  • Unknown symbol returns 200 with count 0 and bars [], not a 404. Treat count === 0 as not found.
  • An unsupported exchange returns 400 with the message naming all six allowed ids.
  • timeframe=1s returns 400: this route validates against the cache-only timeframe set, which excludes 1s.
  • limit=0, a negative limit or a non-numeric limit returns 400 "limit must be a positive number".
  • A non-numeric from or to returns 400 "from must be a number (epoch ms)".
  • Sending an Origin header the API does not allow returns 500, not a CORS rejection. Verified live with Origin: https://example.com. Call this server to server.

Notes

  • Bars are ascending: bars[0] is the oldest, the last element is the newest.
  • Whether the newest bar is still forming depends on the timeframe. Measured on binance BTCUSDT at 11:58 UTC on 2026-09-30: 1h and 4h ended on the forming bar (closeTime in the future); 1m ended on the last closed minute; 1d ended on the previous day and 1w on the previous week, so the current day and week are absent rather than forming. Compare closeTime with the current time instead of assuming either.
  • takerBuyVolume and takerBuyQuoteVolume are present only on binance and binance-futures. Verified 2026-09-12: bybit-futures, okx-futures, gateio-futures and htx-futures return neither key.
  • Depth is cache depth, not history. BTCUSDT 1w with limit=1500 returned 473 bars.
  • When from/to select more rows than limit, the newest limit bars inside the range are returned, not the oldest.
  • Venue ids here are HYPHENATED and there are only six. /public/fast-search returns the worker's venue keys (binance_futures) across 54 venues, so piping a search result's exchange into this path returns 400.
  • This is a separate rate-limit bucket from the other two /public/ohlcv routes (150 here, 60 for /symbols, 120 for /volume-movers). Never assume one limit for /public/ohlcv/*.
▸Response fields(15)
exchangestring
Venue id, echoed back lowercased
symbolstring
Symbol, echoed back uppercased
timeframestring
Candle interval, echoed back
countnumber
Number of bars in bars[]; 0 means the symbol has no cached series
bars[]array
Candles in ascending openTime order, oldest first
bars[].openTimenumber
Candle open, epoch ms
bars[].opennumber
Open price, in the quote asset
bars[].highnumber
High price, in the quote asset
bars[].lownumber
Low price, in the quote asset
bars[].closenumber
Close price, in the quote asset
bars[].volumenumber
Base-asset volume traded in the candle
bars[].quoteVolumenumber
Quote-asset volume traded in the candle (USD on a USDT pair)
bars[].closeTimenumber
Candle close, epoch ms; in the future for the still-forming last bar
bars[].takerBuyVolumenumber
Taker-buy portion of volume, in base-asset units; volume minus this is taker-sell volume. Absent on venues that do not publish taker data
bars[].takerBuyQuoteVolumenumber
Taker-buy portion of quoteVolume, in quote-asset units (USD on a USDT pair), not a percentage or ratio; quoteVolume minus this is taker-sell volume. Absent on venues that do not publish taker data
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/ohlcv/binance/BTCUSDT/1h?limit=2"
Response200
{
  "exchange": "binance",
  "symbol": "BTCUSDT",
  "timeframe": "1h",
  "count": 2,
  "bars": [
    {
      "openTime": 1789236000000,
      "open": 77210.58,
      "high": 77216.01,
      "low": 77125.03,
      "close": 77131,
      "volume": 275.13313000000005,
      "quoteVolume": 21232169.284633595,
      "closeTime": 1789239599999,
      "takerBuyVolume": 94.47468999999998,
      "takerBuyQuoteVolume": 7290168.162597203
    },
    {
      "openTime": 1789239600000,
      "open": 77131,
      "high": 77186.01,
      "low": 77059.75,
      "close": 77116.68,
      "volume": 611.69929,
      "quoteVolume": 47187303.64367439,
      "closeTime": 1789243199999,
      "takerBuyVolume": 251.71672999999993,
      "takerBuyQuoteVolume": 19416593.28806689
    }
  ]
}

Full response at limit=2; nothing truncated.

GET/public/ohlcv/{exchange}/volume-movers10 credits120/min

Volume movers

Ranks coins by how far the last N minutes of quote volume exceed that coin's own baseline volume for a span that long, computed from 1-minute candles. Each row also carries the taker buy/sell split for the window where the venue publishes it. The row cap is a server constant of 150 and no limit parameter is read.

Path parameters

exchangeenumrequired
Venue id, lowercased server-side; anything else returns 400 listing the six allowed ids.
binancebinance-futuresbybit-futuresokx-futuresgateio-futureshtx-futures

Query parameters

windowenumoptionaldefault 15
Measurement window in minutes. Any other value, numeric or not, returns 400 naming the allowed set.
15153060

Status and edge cases

  • An unsupported exchange returns 400 with the message naming all six allowed ids.
  • An unsupported window returns 400: Invalid window "7". Allowed (minutes): 1, 5, 15, 30, 60. A non-numeric window is rejected the same way.
  • If the underlying cache read fails the route returns 200 with movers [] and dataAsOf null, not a 5xx.
  • Sending an Origin header the API does not allow returns 500. Call this server to server.

Notes

  • totalSymbols is the number of qualifying coins, not symbols scanned and not the row count. binance-futures returned 150 rows with totalSymbols 269.
  • One row per base asset. A coin listed against several quotes is deduped to its highest-volume pair for the window, so movers[].base never repeats.
  • direction, buyPct and sellPct are only populated where the venue publishes taker volume. Verified 2026-09-12: binance and binance-futures give real values; okx-futures, bybit-futures, gateio-futures and htx-futures returned direction "unknown" with buyPct 0 and sellPct 0 on every row.
  • direction is buy at 55% or more taker buy, sell at 45% or less, mixed in between. The threshold is a server env value, so read direction rather than recomputing it from buyPct.
  • The baseline is the 120 minutes before the window and needs at least 20 minutes of closed candles, so a freshly listed market cannot appear.
  • Coins whose baseline averages under $1,000 of quote volume per minute are dropped as illiquid noise.
  • Any limit query parameter is ignored. 150 rows is a server constant.
  • Coverage varies by venue. On one 2026-09-12 sweep: binance-futures 150 rows, bybit-futures 134, okx-futures 110, binance 109, gateio-futures 62, htx-futures 13.
  • updatedAt is when the response was built; the result itself is cached for about 20 seconds. Use dataAsOf for freshness.
▸Response fields(17)
movers[]array
Rows sorted by ratio descending, capped at 150
movers[].symbolstring
Venue-native pair symbol
movers[].basestring
Base asset ticker, uppercase; unique across the array
movers[].quotestring
Quote asset ticker, uppercase; the quote of the deduped highest-volume pair for this base
movers[].windowVolumenumber
Base-asset (token) volume traded during the window, NOT a USD amount; windowQuoteVolume is the quote-asset figure
movers[].windowQuoteVolumenumber
Quote-asset volume traded during the window (USD on a USDT pair)
movers[].rationumber
windowQuoteVolume divided by the coin's expected volume for a window this long, a ratio not a percent; 9.28 means 9.28x normal
movers[].directionstring
Net taker direction: buy, sell, mixed, or unknown when the venue publishes no taker data
movers[].buyPctnumber
Taker-buy share of the window's quote volume, percent 0-100; 0 when unknown
movers[].sellPctnumber
Taker-sell share of the window's quote volume, percent 0-100; 0 when unknown
movers[].priceChangePctnumber
Price move across the window, percent, first open to last close
movers[].lastCandleTimenumber
closeTime of the newest 1m candle counted, epoch ms
exchangestring
Venue id, echoed back
windowMinutesnumber
Window actually used, in minutes
totalSymbolsnumber
Qualifying coins found before the 150-row cap
dataAsOfnumber|null
closeTime of the newest candle counted among the coins that QUALIFIED, epoch ms; symbols dropped by the minimum-candle or $1,000/min liquidity gates never contribute, so it can lag the venue's newest candle. null when nothing was computed
updatedAtstring
When this response was built, ISO 8601 string, not epoch ms, unlike dataAsOf and movers[].lastCandleTime. Recomputed per request even when the ranking itself is served from the ~20s cache
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/ohlcv/binance-futures/volume-movers?window=15"
Response200
{
  "movers": [
    {
      "symbol": "CHZUSDT",
      "base": "CHZ",
      "quote": "USDT",
      "windowVolume": 31385207,
      "windowQuoteVolume": 444076.9787699999,
      "ratio": 9.28,
      "direction": "sell",
      "buyPct": 35.5,
      "sellPct": 64.5,
      "priceChangePct": -0.28,
      "lastCandleTime": 1789242599999
    },
    {
      "symbol": "CHIPUSDT",
      "base": "CHIP",
      "quote": "USDT",
      "windowVolume": 10495534,
      "windowQuoteVolume": 500910.2565299999,
      "ratio": 7.77,
      "direction": "sell",
      "buyPct": 33.6,
      "sellPct": 66.4,
      "priceChangePct": -0.89,
      "lastCandleTime": 1789242599999
    }
  ],
  "exchange": "binance-futures",
  "windowMinutes": 15,
  "totalSymbols": 269,
  "dataAsOf": 1789242599999,
  "updatedAt": "2026-09-12T19:50:51.415Z"
}

movers[] truncated to 2 of 150 rows

GET/public/market/quotes/batch5 credits120/min

Quotes for many markets

Prices up to 30 markets across the six chart venues in one request: the live price and where it came from, plus a rolling 24-hour open, change, high, low and volume derived from our own candles. Each market is named as venue:symbol, so one call can mix spot and perpetual books from different exchanges. An unknown symbol comes back as a row of nulls rather than failing the request.

Query parameters

mstringrequired
Comma-separated markets as <venue>:<SYMBOL>, at most 30. The venue is one of binance, binance-futures, bybit-futures, okx-futures, gateio-futures, htx-futures, case-insensitive; the symbol is the venue-native spelling from /public/ohlcv/{exchange}/symbols (BTCUSDT, BTC-USDT-SWAP, BTC_USDT). Exact duplicates are collapsed.

Status and edge cases

  • No m, or an empty one, returns 400 "m is required, e.g. m=binance:BTCUSDT,okx-futures:BTC-USDT-SWAP".
  • More than 30 markets returns 400 "Too many markets: 31 (max 30)". The cap counts what you sent, before duplicates are collapsed.
  • A venue outside the six returns 400 naming the allowed venues. Verified: binance_futures:BTCUSDT.
  • An entry without a venue returns 400 "Malformed market \"BTCUSDT\": expected <venueId>:<SYMBOL>"; a symbol outside ^[A-Z0-9._:-]{2,32}$ returns 400 naming it, e.g. "Malformed symbol \"B\"". Both verified live.
  • An unknown symbol on a valid venue returns 200 with every field of that row null. Verified: binance:NOTACOINUSDT.

Notes

  • Venue ids are the hyphenated candle-route ids (binance-futures), not the underscore keys of the movers and funding routes: binance_futures:BTCUSDT returns 400.
  • An unknown or delisted symbol on a valid venue is a row of nulls, not an error, so one stale entry never blanks the rest. Check price for null.
  • The 24h figures are ours, not the venue's own 24h ticker. high24h, low24h and both volumes cover the candles that open at or after now minus 24 hours, the forming one included: 5-minute candles for the partial hour at each end and hourly candles in between, so the window is within five minutes of an exchange's rolling 24h statistics. A market with no candle in the last 24 hours returns null for all four.
  • Rows come back in request order, one per distinct key. Duplicates are collapsed on the exact string you sent, so binance:BTCUSDT and binance:btcusdt are two keys and both come back. Verified live: m=binance:BTCUSDT,binance:BTCUSDT,binance:btcusdt returned two rows.
  • Each market is memoised for about 3 seconds, so polling faster than that returns the same numbers.
  • Symbols are venue-native: BTCUSDT on binance and binance-futures, BTC-USDT-SWAP on okx-futures, BTC_USDT on gateio-futures. Take them from /public/ohlcv/{exchange}/symbols.
▸Response fields(17)
asOfnumber
When the response was assembled, epoch ms
quotes[]array
One row per distinct requested market, in request order
quotes[].mstring
Your request key, echoed byte for byte. Join on this
quotes[].venueIdstring
Venue, lower-cased
quotes[].symbolstring
Symbol, upper-cased
quotes[].pricenumber|null
Current price in the quote asset; null when neither a live tick nor a stored candle exists
quotes[].priceAsOfnumber|null
When this price was last confirmed, epoch ms: our latest confirmation of the tick, or the candle's closeTime
quotes[].priceSourcestring|null
tick when price is a live exchange tick; candle when no fresh tick was available and price is the close of the last closed 1m candle, up to about a minute old
quotes[].open24hnumber|null
The price 24 hours ago: the open of the first stored bar at or after now minus 24h
quotes[].anchorobject|null
The bar open24h came from: tf (1m, 5m or 1h) and openTime (epoch ms). A 1h anchor means the 24h change is only hour-accurate
quotes[].change24hnumber|null
price minus open24h, in the quote asset
quotes[].change24hPctnumber|null
change24h / open24h, percent
quotes[].high24hnumber|null
Highest price over the rolling 24 hours and the live price
quotes[].low24hnumber|null
Lowest price on the same basis
quotes[].volume24hQuotenumber|null
Volume over the same 24 hours, in the quote asset (USD on a USDT pair)
quotes[].volume24hBasenumber|null
The same volume in the base asset
quotes[].lastCandleobject|null
close and closeTime (epoch ms) of the last closed 1m candle
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/market/quotes/batch?m=binance:BTCUSDT,okx-futures:BTC-USDT-SWAP,binance:NOTACOINUSDT"
Response200
{
  "asOf": 1790769504838,
  "quotes": [
    {
      "venueId": "binance",
      "symbol": "BTCUSDT",
      "price": 83849.91,
      "priceAsOf": 1790769502148,
      "priceSource": "tick",
      "open24h": 84391.49,
      "anchor": {
        "tf": "1m",
        "openTime": 1790683140000
      },
      "change24h": -541.5800000000017,
      "change24hPct": -0.6417471714268841,
      "high24h": 84563.99,
      "low24h": 82900,
      "volume24hQuote": 1104717773.014598,
      "volume24hBase": 13219.883010000001,
      "lastCandle": {
        "close": 83860.39,
        "closeTime": 1790769479999
      },
      "m": "binance:BTCUSDT"
    },
    {
      "venueId": "okx-futures",
      "symbol": "BTC-USDT-SWAP",
      "price": 83809.4,
      "priceAsOf": 1790769502239,
      "priceSource": "tick",
      "open24h": 84345,
      "anchor": {
        "tf": "1m",
        "openTime": 1790683140000
      },
      "change24h": -535.6000000000058,
      "change24hPct": -0.6350109668622986,
      "high24h": 84544.9,
      "low24h": 82850.8,
      "volume24hQuote": 5463588397.212769,
      "volume24hBase": 65395.6757,
      "lastCandle": {
        "close": 83823,
        "closeTime": 1790769479999
      },
      "m": "okx-futures:BTC-USDT-SWAP"
    },
    {
      "venueId": "binance",
      "symbol": "NOTACOINUSDT",
      "price": null,
      "priceAsOf": null,
      "priceSource": null,
      "open24h": null,
      "anchor": null,
      "change24h": null,
      "change24hPct": null,
      "high24h": null,
      "low24h": null,
      "volume24hQuote": null,
      "volume24hBase": null,
      "lastCandle": null,
      "m": "binance:NOTACOINUSDT"
    }
  ]
}

Full response; nothing truncated.

12

Reference data

4 endpoints

Instrument search, your key's usage, the plans and prices the enforcement code actually reads, and the product changelog.

GET/public/fast-search/markets1 credit120/min

Market search

Searches the symbol universe across the 54 venues the pipeline ingests and returns one row per tradeable market, plus the facet options for a filter UI. Base tickers match by prefix, coin names match by prefix and by substring for queries of 3 characters or more. Since 2026-09-16 a ticker also matches a venue's own spelling of the same asset, so q=BTC reaches kraken's XXBT books and kucoin_futures' XBTUSDTM; those rows still report baseAsset exactly as the merged universe holds it (XXBT), with the folded value in instrument.base (BTC). It is the market picker's backend, so it returns the worker's own venue keys (binance_futures, crypto-com-exchange), which the candle endpoints will not accept.

Query parameters

qstringoptional
Coin ticker or name. Truncated to 32 characters rather than rejected. Documented as required in Swagger but not enforced: omitting it returns an empty result set, not a 400.
limitintegeroptionaldefault 8
Rows per page, floored and clamped to 25. A non-numeric or non-positive value falls back to 8.
offsetintegeroptionaldefault 0
Rows to skip for paging. Negative values are treated as 0.
typeenumoptional
Contract-type facet, widened from spot|perp on 2026-09-15. The six values partition the result set exactly, so they sum to the unfiltered total: for q=sol, 385 spot + 44 perp + 2 dated + 0 expired + 18 leveraged + 0 rwa = 449. Note that type=spot is now STRICTLY spot: leveraged tokens and tokenised equities used to fall into it and now answer to type=leveraged and type=rwa. Any other value is ignored and the filter is not applied.
spotperpdatedexpiredleveragedrwa
venuestringoptional
Single venue key, matched EXACTLY (case-insensitive), not by prefix. venue=bin returns nothing; venue=binance and venue=binance_futures are different filters.
quotestringoptional
Quote asset ticker, matched case-insensitively, for example USDT. Since 2026-09-16 it matches EITHER the merged universe's spelling or the venue's own, so quote=USD returns kraken's ZUSD books alongside everyone else's USD ones; quote=ZUSD still works and returns only the venues that spell it that way. The quotes[] facet lists the folded spellings, so every option it offers is a currency rather than a venue's internal code.
venuesstringoptional
Comma-separated allowlist that caps which venues may be searched at all. Entries must match [a-z0-9_-]{2,40}; unusable input degrades to no scope, which is the full search.
groupByenumoptional
groupBy=coin returns one row per asset ({ baseAsset, name, venueCount }) instead of one per market. Any other value returns markets.
coin

Status and edge cases

  • Omitting q returns 200 with query "", results [], total 0 and the full facet lists. There is no 400 for a missing query.
  • No match returns 200 with total 0. There is no 404.
  • Sending an Origin header the API does not allow returns 500. Call this server to server.

Notes

  • Venue keys here are the worker's own keys across 54 venues. Derivatives carry a _futures suffix (binance_futures, okx_futures), but the set is not uniformly underscored: crypto-com-exchange is hyphenated. The OHLCV endpoints take a different, 6-entry hyphenated set, so map between the two explicitly instead of substituting separators.
  • htx-futures has no counterpart here at all: fast-search exposes spot huobi only, so an htx-futures market cannot be reached from a search result. Verified 2026-09-12: venue=huobi_futures returns total 0 and huobi_futures is absent from venues[].
  • venue is an exact match, not a prefix, despite what the endpoint's own Swagger says. Live on 2026-09-12: venue=bin gave total 0, venue=binance gave 26, venue=binance_futures gave 8.
  • Base tickers match by prefix only. Names match by prefix, and by substring only when q is 3 characters or longer. Base matches always outrank name matches.
  • q is truncated, not rejected: a 43-character q came back as a 32-character query with total 0.
  • limit clamps at 25: limit=999 returned 25 rows. Page with offset and stop when hasMore is false.
  • groupBy=coin changes both the row shape and the meaning of total. For q=sol: 449 markets, or 19 coins with groupBy=coin.
  • groupBy=coin is not the market list deduplicated by base, and the coin count cannot be derived from the market rows. It skips every row with no coin identity (leveraged tokens, tokenised equities, expired contracts and quarantined rows), so PIPPIN3L and PIPPIN3S appear under markets but never under coins. Measured for q=sol on 2026-09-16: 449 markets spanning 28 distinct baseAsset values, of which 6 appear only on leveraged rows, yet groupBy=coin returns 19. Read total from the grouped response rather than counting bases yourself.
  • Unknown facet values are ignored, not rejected. type=bogus returned the unfiltered total of 449, so validate client-side if a typo must be visible.
  • venues[] and quotes[] are facet options for a filter UI, not properties of the result set. venues[] honours the venues= scope; quotes[] does not.
  • Dated futures contracts are searchable but are ranked below the venue's perpetual.
  • SYMBOL CONVENTIONS. Three different strings name a market on this endpoint and they are not interchangeable. results[].symbol is the venue's own spelling (PIPPIN-USDT-SWAP on okx_futures, PIPPIN_USDT on gateio, pippin_usdt on lbank) and is the ONLY one any API accepts, ours or the venue's. results[].instrument.canonical is one name for the same instrument whatever venue it came from (OKX:PIPPINUSDT.P), for display and cross-venue comparison. results[].baseAsset and quoteAsset are the merged universe's split, which can differ from instrument.base and instrument.quote.
  • The canonical format is BRAND:BASEQUOTE followed by a suffix for the contract kind: no suffix for spot, leveraged tokens and tokenised equities; .P for a linear perpetual and .PI for an inverse one; .F followed by a YYMMDD expiry for a linear dated contract, .FI for an inverse one. So BINANCE:BTCUSDT is spot, OKX:PIPPINUSDT.P is a perpetual, and BINANCE:BTCUSDT.F260925 is a quarterly. The expiry digits are the venue's own spelling, carried through rather than reformatted.
  • Inverse (coin-margined) contracts take the I forms, and they are the clearest illustration of what a canonical is for. OKX spells its inverse Bitcoin perpetual BTC-USD-SWAP and Kraken spells the same instrument PI_XBTUSD; both answer to <BRAND>:BTCUSD.PI, with Kraken's XBT folded to BTC. Kraken's inverse quarterly FI_XBTUSD_260925 is KRAKEN:BTCUSD.FI260925. Only the BRAND differs between venues listing the same instrument, which is what makes the strings comparable.
  • Do not parse a canonical to recover the base and the quote. There is no separator between them, the base can carry a multiplier prefix (BINANCE:1000PEPEUSDT.P), and a quote is not always three or four characters. instrument.base and instrument.quote are given for exactly this reason. Equally, do not treat a canonical as a key or an identifier: it is a display string and it is null whenever resolved is false.
▸Response fields(24)
querystring
The query actually used, after the 32-character truncation
results[]array
Matching markets, best match first, interleaved across venues
results[].baseAssetstring
Base asset ticker, uppercase
results[].quoteAssetstring
Quote asset ticker, uppercase
results[].symbolstring
Venue-native pair symbol, for example PIPPIN-USDT-SWAP
results[].exchangestring
Worker venue key, for example binance_futures, not the hyphenated id the OHLCV routes take
results[].isPerpboolean
Exactly instrument.kind === "perp". It is a router, not a badge, so a dated or expired contract is a derivative but returns false: BTCUSDT_260925 on binance_futures is isPerp false, kind dated. Branch on instrument.kind when you need to tell a quarterly from spot. The field name and type are unchanged since launch; what changed on 2026-09-15 is which rows it is true for.
results[].namestring
Full coin name; absent when no name is known for the base
results[].foldedBaseOnlyboolean
true when the row matched only through a venue's own alias for the base, such as kraken's XXBT book answering q=BTC. groupBy=coin leaves these rows out, so a venue's code never becomes a coin of its own
results[].instrumentobject
Canonical identity for this market, added 2026-09-15. Purely additive: every field above keeps its name and meaning, so a client that ignores this object sees no change beyond the isPerp corrections.
results[].instrument.canonicalstring|null
One name for this instrument across every venue, e.g. OKX:PIPPINUSDT.P. DISPLAY AND COMPARISON ONLY: no API here or at any venue accepts it; send results[].symbol. null when the instrument could not be resolved, in which case render symbol.
results[].instrument.resolvedboolean
false means canonical is null and you must fall back to symbol.
results[].instrument.persistableboolean
Whether instrument.base and instrument.quote are well enough attested to store. false means fall back to results[].baseAsset and results[].quoteAsset, and fall back BOTH fields, never one.
results[].instrument.kindstring
One of spot, perp, dated, expired, leveraged, rwa: the same vocabulary the type facet takes.
results[].instrument.basestring
The VENUE's own base asset. Not always equal to results[].baseAsset, which keeps the merged universe's value because it feeds ranking and the coin-name join.
results[].instrument.quotestring
The VENUE's own quote asset, with the same caveat as base.
results[].instrument.descriptionstring
Human-readable, e.g. "PIPPIN / USDT perpetual".
results[].instrument.tagsarray
Descriptive tags, e.g. ["perpetual", "crypto"]. Replaces the old two-state spot/perp tag.
results[].instrument.leveragedobject
Leveraged tokens only, absent otherwise: { stem, factor (1, 2, 3 or 5), direction ("long" or "short") }.
totalnumber
Total matches after dedupe, not the page length
offsetnumber
Offset actually applied
hasMoreboolean
True when offset plus the page length is still below total
venues[]array
Venue keys available as a venue filter. The first 14 are in a fixed prominence order (binance, binance_futures, bybit, bybit_futures, okx, okx_futures, coinbase, kraken, kraken_futures, bitget, kucoin, gateio, huobi, mexc); every key after mexc is alphabetical
quotes[]array
Quote assets available as a quote filter, capped at 16. The first six are a fixed curated order (USDT, USDC, FDUSD, USD, BTC, ETH); listing count orders only the remainder
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/fast-search/markets?q=sol&limit=3"
Response200
{
  "query": "sol",
  "results": [
    {
      "baseAsset": "SOL",
      "quoteAsset": "USDT",
      "symbol": "SOLUSDT",
      "exchange": "binance",
      "isPerp": false,
      "name": "Solana",
      "foldedBaseOnly": false,
      "instrument": {
        "canonical": "BINANCE:SOLUSDT",
        "resolved": true,
        "persistable": true,
        "kind": "spot",
        "base": "SOL",
        "quote": "USDT",
        "description": "SOL / USDT",
        "tags": ["spot", "crypto"]
      }
    }
  ],
  "total": 480,
  "offset": 0,
  "hasMore": true,
  "venues": ["binance", "binance_futures", "bybit"],
  "quotes": ["USDT", "USDC", "FDUSD"]
}

results[] truncated to 1 of 3 returned (480 total), venues[] to 3 of 55, quotes[] to 3 of 16

GET/public/usage0 credits60/min

Your usage

What your key's account has spent today and this minute, and its limits. It costs nothing and is never refused for being over the limit, so a program that has run out can still find out when it may continue.

Parameters

None. Everything this endpoint returns is pinned server-side.

Status and edge cases

  • Without an API key it answers 401: the site's own calls have no account to report.
  • Sending an Origin header the API does not allow returns 500, not a CORS rejection. Call this server to server.

Notes

  • Credits are counted per account, not per key: every key of one account draws on the same allowance.
  • A number the meter could not read comes back as null, never 0. Treat null as unknown.
  • Every keyed response already carries the same numbers as headers (X-Credits-*, X-RateLimit-*-Minute), so most programs never need this call.
  • Served with Cache-Control: no-store.
▸Response fields(14)
plan.idstring
The plan your account is on, "api-beta" during the beta
plan.namestring
Display name
plan.creditsPerDaynumber
Your account's credits per UTC day, including any raise we have given it
plan.creditsPerMinutenumber
Your account's credits per minute
key.prefixstring
The start of the key you called with, as the API page shows it
today.datestring
The UTC day, YYYY-MM-DD
today.creditsUsednumber|null
Credits your account spent today, across all its keys
today.creditsLeftnumber|null
Credits left today
today.callsnumber|null
Calls your account made today
today.errorsnumber|null
Calls today that ended in an error status
today.resetsAtstring
When today's credits reset, ISO 8601 instant (next 00:00 UTC)
thisMinute.creditsUsednumber|null
Credits spent this minute
thisMinute.creditsLeftnumber|null
Credits left this minute
thisMinute.resetsAtstring
When the next minute starts, ISO 8601 instant
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/usage"
Response200
{
  "plan": {
    "id": "api-beta",
    "name": "API beta",
    "creditsPerDay": 2000,
    "creditsPerMinute": 60
  },
  "key": {
    "prefix": "cb_live_3f9a2c71"
  },
  "today": {
    "date": "2026-10-01",
    "creditsUsed": 245,
    "creditsLeft": 1755,
    "calls": 61,
    "errors": 1,
    "resetsAt": "2026-10-02T00:00:00.000Z"
  },
  "thisMinute": {
    "creditsUsed": 11,
    "creditsLeft": 49,
    "resetsAt": "2026-10-01T21:15:00.000Z"
  }
}

Illustrative values in the route's exact shape: it answers only to a key

GET/public/plans0 credits300/min

Plan catalogue

Returns the account limits a free user of the app is actually held to, a preview of the Pro tier, and the API beta: the credits an account gets, what every route costs, and whether new keys are open. Every number is read from the same constants the API's gates and credit meter use, so it cannot drift from enforcement. Read the limits rather than hardcoding them: they change on a redeploy.

Parameters

None. Everything this endpoint returns is pinned server-side.

Status and edge cases

  • Sending an Origin header the API does not allow returns 500, not a CORS rejection. Verified live with Origin: https://example.com. Call this server to server.

Notes

  • The free-plan values are environment-driven. The sample shows production on 2026-10-01 (5 active alerts, 10 notifications a day, 5 watchlists, 10 coins each); read them at runtime rather than copying them.
  • pro carries no limits object, only status and benefits. Do not expect pro.limits.
  • notificationsResetAt and api.creditsResetAt are computed per request as the next 00:00 UTC, so they move every day.
  • api.routes lists every API route, 49 today, and marks the ones closed to keys with closed: true. Two are closed for now and not documented here: /public/token-unlocks/{base}, until it covers more than a handful of coins, and /public/setups/{exchange}/{symbol}/{timeframe}/full. The other 47 are all documented on this page.
  • The response is served with Cache-Control: public, max-age=300, stale-while-revalidate=3600. Honour it instead of polling.
  • The endpoint takes no input and is rate limited at 300/min.
▸Response fields(34)
freeobject
The free tier of the app
free.idstring
Stable tier id, "free"
free.namestring
Display name
free.priceUsdnumber
Price in USD per month
free.limits.activeAlertsnumber
Alerts armed at the same time
free.limits.notificationsPerDaynumber
Notifications delivered per UTC day, across all alerts and channels
free.limits.watchlistsnumber
Watchlists per account, counting the default list
free.limits.watchlistItemsnumber
Coins per watchlist
proobject
The Pro tier preview
pro.idstring
Stable tier id, "pro"
pro.namestring
Display name
pro.statusstring
Always "coming_soon" at present; there is nothing to buy
pro.benefits[]array
Plain-text lines describing what Pro will change
notificationsResetAtstring
When the daily notification counter next resets, ISO 8601 instant (next 00:00 UTC)
apiobject
The API beta: what an account with an API key gets
api.statusstring
Always "beta" at present
api.priceUsdnumber
Price in USD per month: 0 for the whole beta
api.creditsPerDaynumber
Credits an account may spend per UTC day, shared by all its keys
api.creditsPerMinutenumber
Credits an account may spend per minute
api.keysPerAccountnumber
Active keys an account may hold
api.newKeysPerDaynumber
Keys an account may create per UTC day, revoked ones included
api.heavyCallsAtOncenumber
Heavy calls an account may have running at the same time
api.commercialUseboolean
Whether beta keys may be used commercially: true, under the API terms (coinbeacon.io/terms/api)
api.newKeysstring
"open" while accounts can create keys, "paused" while they cannot
api.listedboolean
Whether the app and these docs point people at the API page yet
api.keyTrafficstring
"on", or "off" while every call made with a key is refused with a 503 (an emergency stop)
api.creditsResetAtstring
When today's credits reset, ISO 8601 instant (next 00:00 UTC)
api.kinds[]array
Credits per call, by kind of call
api.routes[]array
Every API route and what one call costs
api.routes[].pathstring
The route, in the {param} style these docs use
api.routes[].kindstring
reference, lookup, board, heavy or analytics
api.routes[].creditsnumber
Credits one call costs
api.routes[].closedboolean
Present, true, while the route is closed to API keys: a keyed call gets a 403 and costs nothing
api.routes[].variantobject
Only on a route with a costlier form: when it applies (when) and what it costs (credits)
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/plans"
Response200
{
  "free": {
    "id": "free",
    "name": "Free",
    "priceUsd": 0,
    "limits": {
      "activeAlerts": 5,
      "notificationsPerDay": 10,
      "watchlists": 5,
      "watchlistItems": 10
    }
  },
  "pro": {
    "id": "pro",
    "name": "Pro",
    "status": "coming_soon",
    "benefits": [
      "More active alerts and notifications a day",
      "More watchlists, with more coins in each",
      "Deeper history on setups, trends and cascades",
      "Priority support"
    ]
  },
  "notificationsResetAt": "2026-10-02T00:00:00.000Z",
  "api": {
    "id": "api-beta",
    "name": "API beta",
    "status": "beta",
    "priceUsd": 0,
    "creditsPerDay": 2000,
    "creditsPerMinute": 60,
    "keysPerAccount": 2,
    "newKeysPerDay": 5,
    "heavyCallsAtOnce": 1,
    "commercialUse": true,
    "newKeys": "paused",
    "listed": false,
    "keyTraffic": "on",
    "creditsResetAt": "2026-10-02T00:00:00.000Z",
    "kinds": [
      {
        "kind": "reference",
        "credits": 0
      },
      {
        "kind": "lookup",
        "credits": 1
      },
      {
        "kind": "board",
        "credits": 5
      },
      {
        "kind": "heavy",
        "credits": 10
      },
      {
        "kind": "analytics",
        "credits": 25
      }
    ],
    "routes": [
      {
        "id": "athatl",
        "method": "GET",
        "path": "/public/athatl",
        "kind": "board",
        "credits": 5
      },
      {
        "id": "detectors",
        "method": "GET",
        "path": "/public/detectors/{kind}",
        "kind": "board",
        "credits": 5,
        "variant": {
          "id": "detectors.volume-futures",
          "when": "kind=volume on a futures exchange",
          "kind": "analytics",
          "credits": 25
        }
      },
      {
        "id": "token-unlocks.coin",
        "method": "GET",
        "path": "/public/token-unlocks/{base}",
        "kind": "lookup",
        "credits": 1,
        "closed": true
      }
    ]
  }
}

api.routes[] truncated to 3 of 49

GET/public/product-updates0 credits120/min

Product updates

The release notes for the CoinBeacon product: what was added, improved or fixed, with a link into the app where there is one. It is the same feed coinbeacon.io/changelog renders. It records product changes, not API changes, so it is not a changelog for these endpoints.

Parameters

None. Everything this endpoint returns is pinned server-side.

Status and edge cases

  • No parameters are read, so unknown query strings are ignored and still return 200.

Notes

  • The whole feed comes back in one response (158 entries, about 52 KB on 2026-09-30). There are no parameters, no paging and no filter; filter by category or kind on your side.
  • An entry appears from its date, in UTC, and not before. The list is sorted by date only, and several entries often share one.
  • The content is compiled into the API and changes only when we ship, so polling more than a few times a day gains nothing. Remember the ids you have already shown.
▸Response fields(9)
updates[]array
Every published entry, newest date first
updates[].idstring
Stable unique id, e.g. 2026-09-redesigned-settings. Key on this, not on the date
updates[].datestring
Publication date, YYYY-MM-DD, in UTC
updates[].titlestring
Headline
updates[].summarystring
One or two plain sentences
updates[].categorystring
One of alerts, notifications, markets, screeners, charts, detectors, account, platform
updates[].kindstring
new, improved or fixed
updates[].linkstring
Path of the feature in the app, to resolve against https://app.coinbeacon.io (e.g. /settings). Absent on entries with nothing to open (125 of 158 carried one on 2026-09-30)
updates[].linkLabelstring
Text for that link. Present on 19 of 158 entries; where it is absent, coinbeacon.io/changelog prints "Take a look"
Request
curl -H "X-API-Key: $COINBEACON_API_KEY" \
  "https://api.coinbeacon.io/public/product-updates"
Response200
{
  "updates": [
    {
      "id": "2026-09-redesigned-settings",
      "date": "2026-09-29",
      "title": "Redesigned Settings",
      "summary": "Settings is now one workspace for your account, alert defaults and notification channels. Set up email, Discord, Telegram or a webhook, send a test, and see a sample of what each channel delivers.",
      "category": "account",
      "kind": "improved",
      "link": "/settings",
      "linkLabel": "Open Settings"
    },
    {
      "id": "2026-09-redesigned-dashboard",
      "date": "2026-09-29",
      "title": "Redesigned Dashboard",
      "summary": "Everything that is yours on one calm page: setups on your coins with exchange, pair and timeframe filters, what fired and whether it was sent, your watchlist with seven-day lines and a list switcher, and your active rules and scanners.",
      "category": "platform",
      "kind": "improved",
      "link": "/dashboard",
      "linkLabel": "Open your dashboard"
    }
  ]
}

updates[] truncated to 2 of 158 entries

What this is not

This is the read surface behind our own public pages, opened up as a free beta. It is not versioned: there is no service level, no support contract, and no promise that a field will not change. Limits may change while the beta runs; before any limit drops, we email key holders 30 days ahead.

You may use it in personal and commercial projects alike. Credit the data sources where you show their data, and do not resell access or republish the data in bulk. The API terms say this in full.

Treat responses defensively, and read Errors and Conventions before you build on it.

It is market data, not advice. Nothing here is a recommendation to trade, and the numbers are only as good as the venues we read them from.