CRIUS
PonsLaunchpadsGraduationReal-timeTutorial

Track Pons Bonding Curve Progress With an API

Read Pons bonding curve progress on Robinhood Chain, ETH raised versus the 4.2 ETH threshold, in real time; with code for speed, ETA and graduation alerts.

Crius 8 min read

Short answer: GET /v1/robinhood/token/{address}/launch returns a Pons token’s curve progress as progress.pct, progress.raised and progress.threshold (ETH raised versus the 4.2 ETH graduation target), and GET /v1/robinhood/tokens?list=graduating&launchpad=pons lists every curve still bonding, closest to graduation first. For real-time progress, subscribe to trades:<token> on the WebSocket stream and refresh the lifecycle after each trade; graduations:pons tells you when a curve completes.

Bonding-curve progress is the single most watched number on a launchpad: it says how close a token is to leaving the curve for a real Uniswap v4 pool. This article explains what the number means on Pons, why it moves backwards as often as forwards, and how to track it with code you can run today. All requests and outputs below are from the live API in October 2026.

What “progress” means on a Pons curve

Every Pons V2 launch mints 1,000,000,000 tokens into its own curve contract. Buyers pay ETH into the curve and sellers take ETH out; the curve’s price rises as ETH accumulates. When the ETH raised reaches the graduation threshold, 4.2 ETH for ETH-quoted launches, Pons graduates the token: the 4.2 ETH and about 204 million tokens seed a Uniswap v4 pool behind the PonsV2MemeHook, and that liquidity is locked permanently.

So progress is simply:

progress.pct = progress.raised / progress.threshold × 100

Two consequences follow, and both matter for any tracker:

  • Progress goes down. A sell takes ETH back out of the curve. In the live run further down, one $250 sell moved a curve from 56.24% to 53.62% in a single trade.
  • Progress is in ETH, not dollars. The threshold is a fixed ETH amount, so a token’s dollar market cap at graduation moves with the ETH price. From the graduation values the API reports (4.2 ETH and 204,081,632.65 tokens into the pool), the pool’s opening price is about 2.06 × 10⁻⁸ ETH per token, which puts the fully diluted value at graduation near 20.6 ETH, roughly $48,700 at an ETH price of $2,366.

Reading progress for one token

GET /v1/robinhood/token/{address}/launch is on the Free plan and costs 2 credits:

Terminal window
curl -s "https://api.crius.sh/v1/robinhood/token/0x45a4f7a5e9eb2e376b7d2e64aa8074fd7f7c3fb0/launch" \
-H "x-api-key: $CRIUS_API_KEY" | jq '.data | {status, progress, curve_stats}'
{
"status": "bonding",
"progress": { "pct": 88.0182, "raised": 3.696765698160341791, "threshold": 4.2 },
"curve_stats": {
"buys": 33,
"sells": 11,
"unique_traders": 26,
"volume_quote": 3.792028787417113424,
"first_indexed_block": 96061686,
"history": "complete"
}
}

This token (VST) is 88% of the way to graduating with 3.70 ETH raised, so it needs about 0.50 ETH of net buying. It is also a good example of why progress alone is not a signal: at time of writing its last trade was seven hours earlier. Curves stall, sometimes just short of the line.

The same response gives you context for judging a curve:

  • curve_stats.unique_traders, buys and sells: is this one wallet pumping, or real participation?
  • creator and launched_via: launch_and_buy means the creator bought in the launch transaction itself.
  • fees.snipe_tax: Pons charges launches a snipe tax that starts at 99% (start_bps: 9900) for a 3-second window, which makes block-zero sniping expensive.

All curves at once: the graduating list

GET /v1/robinhood/tokens?list=graduating returns curves that are still bonding, sorted by progress. It needs no key at the anonymous limit:

Terminal window
curl -s "https://api.crius.sh/v1/robinhood/tokens?list=graduating&launchpad=pons&limit=10" \
| jq -r '.data[] | "\(.symbol)\t\(.progress_pct)\t\(.liquidity_usd)\t\(.holders)"'
VST 88.0182 17485.5 25
ZONE 83.558 16599.5 43
THKR 79.2799 15751.4 143
OPEN 74.7853 14856.8 106
FIDES 69.5094 13811.7 168

Use list=bonding for every curve regardless of progress, min_liquidity_usd or min_volume_usd to cut noise, and created_after_ts to focus on fresh launches. Each item includes price, market cap, windowed volume and buyer counts, so one call is usually enough for a dashboard.

Speed and time to graduation (Python)

Progress tells you where a curve is; its rate of change tells you where it is going. This poller samples the graduating list every minute and prints each curve’s speed and a naive ETA:

"""Pons bonding-curve progress, speed and a naive time-to-graduation estimate (poll every minute)."""
import os, time, requests
API = "https://api.crius.sh/v1/robinhood"
HEADERS = {"x-api-key": os.environ["CRIUS_API_KEY"]}
INTERVAL = int(os.environ.get("INTERVAL", "60"))
def graduating(limit=15):
r = requests.get(f"{API}/tokens", params={"list": "graduating", "launchpad": "pons", "limit": limit}, headers=HEADERS, timeout=15)
r.raise_for_status()
return r.json()["data"]
seen = {}
while True:
now = time.time()
for t in graduating():
pct, prev = t["progress_pct"], seen.get(t["address"])
seen[t["address"]] = (pct, now)
if prev is None:
continue
per_min = (pct - prev[0]) / (now - prev[1]) * 60
eta = f"~{(100 - pct) / per_min:.0f} min" if per_min > 0 else ("falling" if per_min < 0 else "flat")
print(f"{t['symbol']:<10} {pct:6.2f}% {per_min:+6.2f} pts/min {eta:<9} holders {t['holders']}")
print("---")
time.sleep(INTERVAL)

A real sample from a quiet Saturday morning:

VST 88.02% +0.00 pts/min flat holders 25
ZONE 83.44% +0.25 pts/min ~66 min holders 43
THKR 79.28% +0.00 pts/min flat holders 143
OPEN 74.79% +0.00 pts/min flat holders 106
MUTEX 63.56% +0.00 pts/min flat holders 108

Treat the ETA as a description of the last minute, not a forecast. Curves move in bursts, and the median Pons graduation takes only 2,479 blocks (about four minutes) from launch, so the curves that graduate usually do it in one rush rather than at a steady pace.

Real-time progress with the WebSocket stream (Node.js)

Polling once a minute misses the rush. The stream doesn’t push progress directly; instead, subscribe to each curve’s trades and refresh its lifecycle after a trade. Since only a trade can move a curve, this catches every change while making very few API calls.

// curve-alerts.mjs: node curve-alerts.mjs (Node.js 22+)
const API = "https://api.crius.sh/v1/robinhood";
const KEY = process.env.CRIUS_API_KEY;
const headers = { "x-api-key": KEY };
const ALERTS = [75, 90];
const state = new Map(); // token -> { symbol, pct, alerted, lastFetch }
async function refresh(token) {
const s = state.get(token);
if (Date.now() - s.lastFetch < 5000) return; // at most one lookup per token every 5 s
s.lastFetch = Date.now();
const { data } = await (await fetch(`${API}/token/${token}/launch`, { headers })).json();
const p = data.progress;
const moved = p.pct - s.pct;
s.pct = p.pct;
console.log(`${s.symbol.padEnd(10)} ${p.pct.toFixed(2)}% (${moved >= 0 ? "+" : ""}${moved.toFixed(2)}) raised ${p.raised.toFixed(3)} / ${p.threshold} ETH`);
for (const a of ALERTS) {
if (p.pct >= a && !s.alerted.has(a)) { s.alerted.add(a); console.log(`ALERT ${s.symbol} crossed ${a}%`); }
}
}
// Start from the ten curves closest to graduating.
const { data: watch } = await (await fetch(`${API}/tokens?list=graduating&launchpad=pons&limit=10`, { headers })).json();
for (const t of watch) {
state.set(t.address, { symbol: t.symbol, pct: t.progress_pct, alerted: new Set(ALERTS.filter((a) => t.progress_pct >= a)), lastFetch: 0 });
}
const ws = new WebSocket(`wss://api.crius.sh/v1/robinhood/stream?api_key=${KEY}`);
ws.onopen = () => ws.send(JSON.stringify({
op: "subscribe",
channels: [...watch.map((t) => `trades:${t.address}`), "graduations:pons"],
}));
ws.onmessage = (e) => {
const m = JSON.parse(e.data);
if (m.ch === "graduations:pons") return console.log(`GRADUATED ${m.data.token} -> pool ${m.data.pool}`);
if (m.ch?.startsWith("trades:") && state.has(m.data.token)) {
console.log(`${m.data.type} ${m.data.value_usd} USD on ${state.get(m.data.token).symbol}`);
refresh(m.data.token).catch((err) => console.error(err.message));
}
};

Real output from a four-minute run:

buy 48.6376 USD on ZONE
ZONE 80.61% (+0.48) raised 3.386 / 4.2 ETH
sell 250.009 USD on MIMO
MIMO 53.62% (-2.62) raised 2.252 / 4.2 ETH
buy 144.488 USD on ZONE
ZONE 81.12% (+0.51) raised 3.407 / 4.2 ETH
buy 9.88808 USD on ZONE
ZONE 82.66% (+1.54) raised 3.472 / 4.2 ETH
sell 87.2013 USD on MUTEX
MUTEX 62.41% (-0.90) raised 2.621 / 4.2 ETH

A few notes for production:

  • Throttle per token. The 5-second guard keeps a burst of trades from turning into a burst of lifecycle calls (2 credits each).
  • Rotate the watch list. Re-read the graduating list every few minutes and subscribe to newcomers; a Free plan connection allows 10 subscriptions, Pro allows 1,000.
  • Handle graduations. After graduations:pons, unsubscribe from the curve’s trades and start following the new pool: price:<token> and lp:<token> keep working, because Crius moves a token’s price to its pool automatically.
  • Reconnects. Keep the last seq per channel and send a resume after re-subscribing to receive anything missed in the last 60 seconds. See the WebSocket guide.

Charting a curve

OHLCV candles include a launchpad token’s bonding-curve trades by default and continue on the Uniswap v4 pool after graduation, so a chart of a token’s whole life is one call:

Terminal window
curl -s "https://api.crius.sh/v1/robinhood/token/0xdd215018a9c558fcdfb2db56ab4d8c60ddf25491/candles?interval=1m&limit=300&fill=true"

Because the curve price is a function of ETH raised, the curve section of the chart is effectively a progress chart in price form.

When progress is not enough

A curve at 90% with three holders is not the same as a curve at 90% with 150. Before acting on progress, combine it with:

  • Holder spread and early buyers from /bundles, to see whether a few connected wallets are driving the curve. See bundle detection.
  • The creator’s record from /dev/{address}: how many of their previous tokens graduated, and how much they sold.
  • Realized tax from /security once the token trades on its pool.

FAQ

What is the Pons graduation threshold? 4.2 ETH raised on the curve for ETH-quoted launches. The /launch response includes the exact threshold for every token, in the curve’s quote asset.

Why did a token’s progress go down? Sells take ETH back out of the curve, so raised and progress.pct fall. Progress is a live balance, not a high-water mark.

How often is progress updated? On every indexed trade. The lifecycle endpoint and the token lists reflect a trade within about a block of it landing on Robinhood Chain.

Can I get progress for all bonding Pons tokens at once? Yes: GET /v1/robinhood/tokens?list=bonding&launchpad=pons pages through every curve, with progress_pct on each item; list=graduating sorts by progress.

Does this work for other launchpads? The lifecycle endpoint and lists cover every attributed launchpad, including Flap.sh, whose curves report progress the same way. See the Flap.sh API and launchpads API.

Sources

Build with Crius

Robinhood Chain data in one API

Free plan with 1M credits a month. Your key in under a minute.

Related APIs

More from the blog