curl -X POST "https://api.metastreams.io/v1/discovery" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"chains": ["solana", "base"],
"graduating": {
"sortBy": "volume24hUsd",
"limit": 20,
"filters": { "liquidityUsd": { "min": "20000" }, "holderCount": { "min": 500 } }
}
}'
const response = await fetch("https://api.metastreams.io/v1/discovery", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
chains: ["solana", "base"],
graduating: { sortBy: "volume24hUsd", limit: 20 },
}),
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const { columns } = await response.json();
{
"columns": [
{
"column": "graduating",
"deltas": [
{
"chain": "solana",
"address": "TokenMint1111111111111111111111111111111pump",
"rank": 1,
"data": {
"chain": "solana",
"address": "TokenMint1111111111111111111111111111111pump",
"name": "Example",
"symbol": "EXAMPLE",
"decimals": 6,
"price": { "native": "0.00000042", "usd": "0.000075" },
"marketCap": { "native": "420.5", "usd": "75000" },
"liquidity": { "native": "128.4", "usd": "22900" },
"bondingCurvePct": "91.4",
"updatedAt": 1789632012345
}
}
]
}
]
}
REST
Discovery boards
Rank launchpad tokens by launch stage, across one or more chains, in a single request.
POST
/
v1
/
discovery
curl -X POST "https://api.metastreams.io/v1/discovery" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"chains": ["solana", "base"],
"graduating": {
"sortBy": "volume24hUsd",
"limit": 20,
"filters": { "liquidityUsd": { "min": "20000" }, "holderCount": { "min": 500 } }
}
}'
const response = await fetch("https://api.metastreams.io/v1/discovery", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
chains: ["solana", "base"],
graduating: { sortBy: "volume24hUsd", limit: 20 },
}),
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const { columns } = await response.json();
{
"columns": [
{
"column": "graduating",
"deltas": [
{
"chain": "solana",
"address": "TokenMint1111111111111111111111111111111pump",
"rank": 1,
"data": {
"chain": "solana",
"address": "TokenMint1111111111111111111111111111111pump",
"name": "Example",
"symbol": "EXAMPLE",
"decimals": 6,
"price": { "native": "0.00000042", "usd": "0.000075" },
"marketCap": { "native": "420.5", "usd": "75000" },
"liquidity": { "native": "128.4", "usd": "22900" },
"bondingCurvePct": "91.4",
"updatedAt": 1789632012345
}
}
]
}
]
}
One request names the chains and the columns it wants. Each column is ranked and filtered on its own, and answers with its whole ranked set.
Tokens with equal values keep a fixed order.
Columns
Each column is one stage of a token’s launchpad life; see launchpad terms.| Column | Holds | Default ranking |
|---|---|---|
newPairs | Launchpad tokens below 40% of their bonding curve | createdAt, newest first |
graduating | Launchpad tokens at 40% of their curve or more, not yet graduated | bondingCurveActivity, highest first |
graduated | Launchpad tokens that have graduated, or that have no curve reading | graduatedAt, newest first |
Body
Name at least one chain and at least one column. A repeated chain slug is read once, and every column ranks tokens from all the named chains as one set. Leave a column out to skip it, and send{} to take its defaults. Inside a column, sortBy names the field to rank on, order is desc or asc, a limit outside 1 to 100 is moved into that range rather than refused, and filters adds conditions on top of the column defaults.
Column defaults
Every column applies conditions of its own, on top of your filters:- Every column leaves out tokens with no update in the last 24 hours.
graduatingandgraduatedkeep only tokens with at least 10 holders, 1,000ofliquidityanda5,000 market cap.graduatingalso leaves out tokens with no update in the last 60 minutes, unless they are at 99.5% of their curve or more.
holderCount minimum below 10 on graduated, for example, is raised to 10, and a maxGraduationStaleMinutes above 60 on graduating is lowered to 60.
Sort fields
sortBy | Ranks on |
|---|---|
createdAt | Token creation time |
volume24hUsd | USD volume over the last 24 hours |
marketCapUsd | USD market cap |
liquidityUsd | USD liquidity |
holdersCount | Current holders |
tradeCount24h | Buys plus sells over the last 24 hours |
bondingCurvePct | Bonding-curve completion. On graduating, this ranks on bondingCurveActivity instead. |
bondingCurveActivity | Curve completion weighted by the last hour’s volume: bondingCurvePct multiplied by ln(1 + stats["1h"].volume.usd) |
graduatedAt | Graduation time |
Filters
A token must meet every filter you send, as well as the column defaults. The schema below names each filter; these rules hold across all of them.The API ignores a filter name it does not know, rather than refusing it. Check spellings: the sort field is
holdersCount, but the filter is holderCount.- Ranges are
{ "min": …, "max": … }. Both bounds are inclusive, and either can be left out. Aminabovemaxreturns400 VALIDATION_ERROR. Each bound takes the type of the field it bounds: decimal strings for USD values, numbers for counts and percentages. - Lists are unions: a token passes when it matches any entry.
symbolOrNameandexcludeSymbolOrNamematch the symbol or the name, ignoring case, and a word that looks like an address matches the token’s address exactly instead. withAtLeastOneSocialkeeps tokens that carry at least one social link. It is the only switch, andfalseapplies no condition.- Time limits are
lastActivityMinutes, which keeps tokens updated within that many minutes, andmaxGraduationStaleMinutes, which drops tokens with no update within that many minutes unless they are at 99.5% of their curve or more.maxGraduationStaleMinutesapplies on any column, andgraduatingcaps it at 60. An update is any change to a token’s record, such as a trade, not only curve progress.
twitterReuseCount is accepted but not yet applied: every token passes it.Response
columns holds one entry per requested column, in the order newPairs, graduating, graduated. Each entry’s deltas is the whole ranked column, one item per rank from 1, and each item’s data is the same token object Token details returns.
Errors
| Code | When |
|---|---|
UNSUPPORTED_CHAIN | A slug in chains is not supported |
VALIDATION_ERROR | No chain or no column requested, a range whose min is above its max, or a malformed body |
curl -X POST "https://api.metastreams.io/v1/discovery" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"chains": ["solana", "base"],
"graduating": {
"sortBy": "volume24hUsd",
"limit": 20,
"filters": { "liquidityUsd": { "min": "20000" }, "holderCount": { "min": 500 } }
}
}'
const response = await fetch("https://api.metastreams.io/v1/discovery", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
chains: ["solana", "base"],
graduating: { sortBy: "volume24hUsd", limit: 20 },
}),
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const { columns } = await response.json();
{
"columns": [
{
"column": "graduating",
"deltas": [
{
"chain": "solana",
"address": "TokenMint1111111111111111111111111111111pump",
"rank": 1,
"data": {
"chain": "solana",
"address": "TokenMint1111111111111111111111111111111pump",
"name": "Example",
"symbol": "EXAMPLE",
"decimals": 6,
"price": { "native": "0.00000042", "usd": "0.000075" },
"marketCap": { "native": "420.5", "usd": "75000" },
"liquidity": { "native": "128.4", "usd": "22900" },
"bondingCurvePct": "91.4",
"updatedAt": 1789632012345
}
}
]
}
]
}
Authorizations
Send the API key as Authorization: Bearer <key>.
Body
application/json
A discovery request: one or more chains, up to three columns.
Chains every column ranks over, as one mixed set.
Chain slug. One spelling per chain, in paths and bodies alike. Only a chain with spot data is published.
Available options:
solana, base, bsc, robinhood, arc Graduated column; omitted means not requested.
Show child attributes
Show child attributes
Graduating column; omitted means not requested.
Show child attributes
Show child attributes
New-pairs column; omitted means not requested.
Show child attributes
Show child attributes
Response
One snapshot per requested column, in page order.
POST /v1/discovery response: one snapshot per requested column, in page order.
The requested columns' snapshots.
Show child attributes
Show child attributes