pumpdata.fun

The pre-buy check for a pump.fun trading agent

· · Calls, limits and prices as of 2026-10-22.

What should a pump.fun trading agent check before it buys?

Three things, in three calls to pumpdata.fun, free under /free/ with no key: who launched the coin and how their earlier launches went (GET /launch/{mint}), who is buying it and what those wallets have done before (POST /wallets), and the odds a coin in that market-cap band had of running (GET /baserate). The answers come from every pump.fun trade since pump.fun's first day, so a deployer's record and a buyer's history are whole, not the last week's. The code below is the whole check; paste it into the agent.

The check in Python

Standard library only. python3 prebuy.py <mint> [buyer wallets...] prints the result as JSON.

# The pre-buy check: three calls to pumpdata.fun before a pump.fun buy. Free under /free/ (30 an hour
# per IP, no key, no signup). Paid path: drop "/free" and pay per call over x402, or send x-api-key.
import json, urllib.request
from datetime import datetime, timedelta, timezone

BASE = "https://pumpdata.fun/free"

def get(path):
    with urllib.request.urlopen(BASE + path, timeout=10) as r:
        return json.load(r)

def post(path, body):
    req = urllib.request.Request(BASE + path, json.dumps(body).encode(), {"content-type": "application/json"})
    with urllib.request.urlopen(req, timeout=10) as r:
        return json.load(r)

def prebuy_check(mint, buyers=(), band="15k-28k"):
    """mint: the coin. buyers: up to 50 wallet addresses that bought it (from your feed). band: the market-cap
    band you buy in. Returns the dev's record, the bundle, how similar launches went, who the buyers are, and the
    base rate for the band, plus plain flags. It is numbers from every pump.fun trade, ever; it is not advice."""
    launch = get(f"/launch/{mint}")
    wallets = post("/wallets", {"addresses": list(buyers)[:50], "mint": mint}) if buyers else {}
    to = datetime.now(timezone.utc).replace(hour=0, minute=0, second=0, microsecond=0)
    frm = to - timedelta(days=1)
    base = get(f"/baserate?band={band}&from={frm:%Y-%m-%dT%H:%M:%SZ}&to={to:%Y-%m-%dT%H:%M:%SZ}")

    dev, bundle, matches = launch["deployer"], launch["bundle_at_creation"], launch["matches"]
    classes = {a: w["class"] for a, w in wallets.items() if isinstance(w, dict) and "class" in w}
    flags = []
    if dev["launches"] >= 20 and dev["graduations"] == 0:
        flags.append(f"dev has {dev['launches']} launches and no graduation")
    if bundle["supply_share"] >= 0.5:
        flags.append(f"{bundle['supply_share']:.0%} of the supply was bought in the first 10 s")
    if (launch.get("insider_supply_share") or 0) >= 0.5:
        flags.append(f"insiders hold {launch['insider_supply_share']:.0%} of the supply")
    if matches["n"] >= 20 and matches["peak_day1"]["dead"] / matches["n"] >= 0.9:
        flags.append(f"{matches['peak_day1']['dead']} of {matches['n']} launches like it were dead by day one")
    sellers = sum(1 for c in classes.values() if c == "supply seller")
    if sellers:
        flags.append(f"{sellers} of {len(classes)} buyers are supply sellers")
    return {"flags": flags, "dev": dev, "bundle": bundle, "similar_launches": matches,
            "buyers": classes, "base_rate": base["reached"], "median_peak": base["median_peak"]}

if __name__ == "__main__":
    import sys
    print(json.dumps(prebuy_check(sys.argv[1], sys.argv[2:]), indent=1))

The same in TypeScript

// The pre-buy check in TypeScript (Node 18+ or any runtime with fetch). Free under /free/, 30 an hour per IP.
const BASE = "https://pumpdata.fun/free"; // paid path: drop "/free" (x402 per call, or x-api-key)

const get = (p: string) => fetch(BASE + p).then((r) => r.json());
const post = (p: string, body: unknown) =>
  fetch(BASE + p, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body) }).then((r) => r.json());

export async function prebuyCheck(mint: string, buyers: string[] = [], band = "15k-28k") {
  const launch = await get(`/launch/${mint}`);
  const wallets = buyers.length ? await post("/wallets", { addresses: buyers.slice(0, 50), mint }) : {};
  const to = new Date(); to.setUTCHours(0, 0, 0, 0);
  const from = new Date(to.getTime() - 86400e3);
  const iso = (d: Date) => d.toISOString().replace(/\.\d{3}Z$/, "Z");
  const base = await get(`/baserate?band=${band}&from=${iso(from)}&to=${iso(to)}`);

  const { deployer: dev, bundle_at_creation: bundle, matches } = launch;
  const classes: Record<string, string> = {};
  for (const [a, w] of Object.entries<any>(wallets)) if (w && typeof w === "object" && "class" in w) classes[a] = w.class;
  const flags: string[] = [];
  if (dev.launches >= 20 && dev.graduations === 0) flags.push(`dev has ${dev.launches} launches and no graduation`);
  if (bundle.supply_share >= 0.5) flags.push(`${Math.round(bundle.supply_share * 100)}% of the supply was bought in the first 10 s`);
  if ((launch.insider_supply_share ?? 0) >= 0.5) flags.push(`insiders hold ${Math.round(launch.insider_supply_share * 100)}% of the supply`);
  if (matches.n >= 20 && matches.peak_day1.dead / matches.n >= 0.9) flags.push(`${matches.peak_day1.dead} of ${matches.n} launches like it were dead by day one`);
  const sellers = Object.values(classes).filter((c) => c === "supply seller").length;
  if (sellers) flags.push(`${sellers} of ${Object.keys(classes).length} buyers are supply sellers`);
  return { flags, dev, bundle, similar_launches: matches, buyers: classes, base_rate: base.reached, median_peak: base.median_peak };
}

What comes back

FieldWhat it says
flagsPlain sentences for the things the check found: a dev with many launches and none graduated, a bundle over half the supply, a high insider share, launches like it that died, buyers who are supply sellers. An empty list means the check found none of these, not that the coin is safe.
devThe deployer's record over the whole history: launches, graduations, best_peak (USD), launches_last_day, the gap since its last launch.
bundlebuyers_first_10s and the supply_share they took at creation.
similar_launchesHow launches with the same shape (dev record, bundle, insider share, curve progress at the same age) went in their first day: n, graduated_share, the peak multiple's percentiles and how many were dead.
buyersEach buyer wallet's class: winner, bot, supply seller, new (first seen on this coin), or none.
base_rate, median_peakOf every coin that first traded in the band yesterday, the share that reached 2x, 5x, 10x and 20x within three hours, and the median peak.

Where it goes in the agent

The feed of new coins comes from pump.fun's own stream (or PumpPortal); pumpdata.fun is not a feed. The check runs once per candidate, after the agent's own filter and before the buy, so the free allowance covers about 30 candidates an hour, ten if the agent sends buyers to /wallets every time. An agent that screens more than that pays per call without the /free prefix (the pump.fun API shows the x402 flow) or uses a free key for 100 an hour.

The flags are reasons to skip, not a score. The one number worth sizing on is the base rate: a rule whose picks do not beat base_rate is picking no better than chance, and a replay of its picks will say so with fees and the dead coins counted.

A prompt for agents

Give this to the agent, or put it in its system prompt, so the check runs before every buy and the answers are read for what they are.

Before any pump.fun buy, run the pre-buy check against pumpdata.fun (https://pumpdata.fun/llms.txt):
1. GET /free/launch/{mint}: the deployer's record (launches, graduations, best earlier peak), the bundle in the
   first 10 seconds, the insider share, and how launches that looked like this one went (matches).
2. POST /free/wallets with up to 50 buyer addresses and the mint: each wallet's class (winner, bot, supply seller,
   new), its SOL in and out over its whole history.
3. GET /free/baserate?band=<the market-cap band you buy in>&from=<yesterday 00:00Z>&to=<today 00:00Z>: how often
   coins in that band reached 2x, 5x, 10x and 20x within three hours. That is the odds of a random pick; your
   rule has to beat it.
Rules: treat the base rate as the prior, not a prediction. Never call a coin safe; the check finds what the chain
shows, not what will happen. A dev with many launches and no graduation, a bundle over half the supply, or buyers
who are supply sellers are reasons to skip, not to size down. Past 30 free calls an hour, call the same paths
without /free/ and pay per call ($0.005 to $0.01, USDC over x402) or send a free API key (x-api-key).
Do not call pumpdata.fun for the feed of new coins; take that from pump.fun's own stream and use these calls to
decide.

Questions

Does pumpdata.fun give a feed of new pump.fun coins?

No. Take new mints from pump.fun's own websocket or a stream such as PumpPortal. pumpdata.fun answers the question that comes next: should the agent buy this one. Its calls carry every pump.fun trade, ever, so the deployer's whole record and each buyer's whole history are in the answer.

How many free calls does a trading agent get?

30 an hour per IP under /free/, with no key and no signup. Past that, the same paths without /free/ answer 402 with a price ($0.005 a lookup, $0.01 for /wallets), paid per call in USDC over x402 with no account, or 100 an hour with a free API key (https://pumpdata.fun/keys). A whole pre-buy check (the three calls) is $0.02 paid.

Which call says whether a coin is a rug?

None of them says rug or safe. GET /launch/{mint} shows what the chain shows: the deployer's launches and graduations, how much of the supply the first buyers took, the insider share, and how launches with the same shape went in their first day. The agent decides; the page never calls a coin safe.

What does the base rate add?

The odds a random pick in the agent's market-cap band had of doubling, 5x-ing, 10x-ing or 20x-ing within three hours, from every coin that first traded in that band on the day. A rule that cannot beat the base rate is choosing coins no better than chance; GET /baserate is how the agent knows.

Can an MCP agent run the check?

Yes. The MCP server at https://pumpdata.fun/mcp has the same calls as tools (launch_history, wallets, baserate and the rest) and uses /free/ by itself when a tool call carries no payment and no key.

No code: the same check as a Grok bot template, pasted once into Grok, ChatGPT or Claude. Every call with a real answer: the pump.fun API. The shapes, for a model: llms.txt and openapi.json. The MCP server: https://pumpdata.fun/mcp.