Developer API

Read market data and launch tokens over plain HTTP. There is no API key and nothing to sign up for: a launch is authorised by your own wallet's signature on the fee payment, which is stronger proof than any key we could issue. So we don't issue one.

Non-custodial throughout. We never ask for, accept or store a private key; you sign the launch fee locally, and no endpoint will sign on your behalf or make the platform wallet sign anything you supply.

Base URLs /api/v2 and /api/public/v1

Use v2 for reads where a v2 endpoint exists. v2 returns the body without the { data, meta } envelope, returns errors as { error: string }, and sends no CORS headers, so call it from your server and not from a browser. v1 endpoints that v2 replaces are marked deprecated below. They continue to work.

Every v2 list pages the same way. Send limit (1-100, default 25), order (desc, the default, or asc) and cursor. Each response carries page: { limit, order, nextCursor }. For the next page, send nextCursor back as cursor, with the same order. Only nextCursor: null means the end: a page can hold fewer rows than limit, or none, before it.

Quickstart#

Every endpoint is open behind a per-minute rate limit per IP address. Start from a terminal:

terminal
# No key, no signup, no plan. Just call it.
curl https://www.stonkfun.xyz/api/public/v1/tokens?sort=newest

# Launching is the same — what authorises it is your own
# signature on the launch fee, not a token we hand you.
curl https://www.stonkfun.xyz/api/public/v1/pairs?launchable=true

Building it yourself#

The two calls above hand you a transaction we built. You can skip them entirely and construct the launch yourself against Raydium's LaunchLab program — your own mint keypair, your own instructions, your own bundle — and still get everything this platform does around a launch. Two reads are all you need from us: GET /pairs for a pair, and GET /launchlab/pricing for the numbers that go in the create instruction.

What ties the two together is the platform id you bake into the pool. It is what the LaunchLab program charges the 1% curve fee to, and it is what we scan for: every minute we read the pools attributed to our platforms and adopt the ones we do not already have a record of. An adopted launch is indistinguishable from an API-created one — token page, chart, volume, fee ledger, holder rewards — and the pool's own creator account is who gets paid, so a standard launch forwards its creator share to your wallet without you registering anything.

Sizing: one number, and it is not the SDK's

totalFundRaisingB is a RAW amount in the quote token's decimals, and Raydium's own constant is 85 SOL written in lamports. Pass it through on an 8-decimal xStock and you have asked for a 850-unit raise; on a 6-decimal stablecoin, 85,000. Both launch happily and graduate at a market cap nobody intended. raise.raw from the pricing call is the integer to use — sized so your launch opens and graduates where one launched here would — and curve.derived carries the virtual reserves the program will compute from it, so you can check your opening price before signing rather than after landing. It is priced at request time; re-fetch if you have been sitting on the response.

What we adopt, exactly

Attribution is necessary but not sufficient: a pool carrying our platform id is adopted only if it matches the launch our own builder would have produced. Everything in this list comes straight out of the pricing response, so matching it is a matter of not substituting your own values:

  • the GlobalConfig from curve.configId, and a constant-product curve migrating to cpmm;
  • supply and totalSellA as given — they fix the open-to-graduation run — with a positive totalFundRaisingB;
  • a base mint created by initialize_with_token2022 at 6 decimals, which every LaunchLab launch is;
  • no transfer-fee extension at all for a standard launch, or a rate from modes.reward.transferFeeBps for a reward one — the extension IS the mode, and it is read off the mint rather than claimed;
  • the platform id that matches that mode: platform.standard for an untaxed mint, platform.reward for a taxed one;
  • the platform's curve-rule account — curveRule.standard / curveRule.reward from pricing — appended as the LAST account of the initialize, read-only. Ignored until the platform enforces its launch shape on-chain; once it does, an initialize without it is refused outright (6018) and one outside this list is refused too (6025).

Miss any of them and nothing bad happens on chain — the pool exists and trades on Raydium — but this platform never records it, which for a standard launch means no fee forwarding, and for a taxed one means the warning below.

A taxed mint you get wrong taxes holders for nobody

On a reward launch the program assigns our platform's withhold authority (modes.reward.withdrawWithheldAuthority) to the mint at creation. Holders are taxed on every transfer from the first trade, and only that wallet can ever withdraw what is withheld. If the launch is adopted we collect it and pay it out to holders on the reward cycle. If it is not — wrong curve, wrong config, an unpublished tax rate — the tax accrues and is never distributed to anyone. Land a standard launch first, confirm it appears in GET /tokens with launchpad: "launchlab", and only then build a taxed one.

The whole thing, end to end:

build.mjs
import {
  ComputeBudgetProgram, Connection, Keypair, PublicKey, Transaction,
} from '@solana/web3.js';
import { TOKEN_2022_PROGRAM_ID } from '@solana/spl-token';
import {
  getPdaLaunchpadAuth, getPdaLaunchpadConfigId, getPdaLaunchpadPoolId, getPdaLaunchpadVaultId,
  getPdaPlatformAllowConfig, getPdaPlatformCurveRule, initializeWithToken2022,
} from '@raydium-io/raydium-sdk-v2';
import BN from 'bn.js';

const API = 'https://www.stonkfun.xyz/api/public/v1';
const QUOTE = 'YOUR_QUOTE_MINT';   // a mint from /pairs
const TAX_BPS = 100;               // reward launch: an offered tier. 0 = standard (deprecated), no tax.
const COMMUNITY_MODE = false;      // reward launch on the Community Mode platform.
const STANDARD_V2 = false;         // taxed launch on the StandardV2 platform: fees to the creator
                                   // unless you record fee recipients first (see StandardV2).
const connection = new Connection(pickRpcUrl());
const creator = Keypair.fromSecretKey(/* your own wallet, never sent anywhere */);

const get = async (path) => (await (await fetch(API + path)).json()).data;

// 1. The pair must be launchable here AND carry a LaunchLab config on chain.
const { pairs } = await get('/pairs?launchable=true&launchLabReady=true');
const pair = pairs.find((item) => item.mint === QUOTE);
if (!pair) throw new Error('Not launchable against that quote right now');

// 2. Size the curve. raise.raw is a raw amount in the quote's decimals. The SDK's 85-SOL
//    constant would mean 850 units on an 8-decimal xStock and 85,000 on a 6-decimal stablecoin.
const pricing = await get(`/launchlab/pricing?quoteMint=${QUOTE}`);
if (STANDARD_V2) {
  if (!pricing.standardV2Enabled) throw new Error('StandardV2 is not enabled');
  const range = pricing.modes.standardV2.transferFeeBpsRange;
  if (COMMUNITY_MODE) throw new Error('Community Mode is not available for StandardV2');
  if (!Number.isInteger(TAX_BPS) || TAX_BPS < range.min || TAX_BPS > range.max) {
    throw new Error('A StandardV2 tax must be a whole bps in modes.standardV2.transferFeeBpsRange');
  }
} else if (TAX_BPS && !pricing.modes.reward.transferFeeBps.includes(TAX_BPS)) {
  throw new Error('That tax rate is not one this platform publishes');
}
if (COMMUNITY_MODE && (!TAX_BPS || !pricing.communityMode.offeredOnThisQuote)) {
  throw new Error('Community Mode is a reward launch, offered only where offeredOnThisQuote is true');
}

// 3. Build the create. The platform id attributes the pool to us, and it is the mode: pick it.
const mode = STANDARD_V2
  ? 'standardV2'
  : TAX_BPS ? (COMMUNITY_MODE ? 'community' : 'reward') : 'standard';
// Take the platform id from the same pricing response the accounts are checked against below.
const programId = new PublicKey(pricing.curve.programId);
const platformId = new PublicKey(pricing.platform[mode]);
const quoteMint = new PublicKey(QUOTE);

// Derive the quote's GlobalConfig and the platform's two accounts for it from the platform id
// above. Read the platform id on every build: it can change. Check each address against the
// pricing response and stop on a difference: your SDK and this API disagree.
const configId = getPdaLaunchpadConfigId(programId, quoteMint, 0, 0).publicKey;
const allowConfigId = getPdaPlatformAllowConfig(programId, platformId, configId).publicKey;
const curveRuleId = getPdaPlatformCurveRule(programId, platformId, configId).publicKey;
if (
  !configId.equals(new PublicKey(pricing.curve.configId)) ||
  !allowConfigId.equals(new PublicKey(pricing.allowConfig[mode])) ||
  !curveRuleId.equals(new PublicKey(pricing.curveRule[mode]))
) {
  throw new Error('Derived accounts differ from the pricing response');
}

const mintKeypair = Keypair.generate();
const mint = mintKeypair.publicKey;
const { publicKey: poolId } = getPdaLaunchpadPoolId(programId, mint, quoteMint);

const instruction = initializeWithToken2022(
  programId,
  creator.publicKey,                       // payer
  creator.publicKey,                       // creator: the wallet fees are forwarded to
  configId,
  platformId,
  getPdaLaunchpadAuth(programId).publicKey,
  poolId,
  mint,
  quoteMint,
  getPdaLaunchpadVaultId(programId, poolId, mint).publicKey,
  getPdaLaunchpadVaultId(programId, poolId, quoteMint).publicKey,
  // mintProgramB — the program owning the QUOTE mint. Every xStock is Token-2022, so reading it
  // from the pair rather than assuming classic SPL is what keeps the account correct.
  new PublicKey(pair.tokenProgram),
  pricing.curve.baseDecimals,
  'My Token', 'MYTKN', 'https://example.com/metadata.json',
  {
    type: 'ConstantCurve',
    supply: new BN(pricing.curve.supply),
    totalSellA: new BN(pricing.curve.totalSellA),
    totalFundRaisingB: new BN(pricing.raise.raw),   // must come from the pricing response
    migrateType: 'cpmm',
  },
  new BN(0), new BN(0), new BN(0),         // no vesting
  pricing.curve.cpmmCreatorFeeOn,
  // Taxed launches only. Both keys must match the Raydium SDK's declaration exactly, as written
  // here. The SDK ignores keys it does not recognise and then writes a zero-rate transfer-fee
  // extension, which looks taxed but collects nothing.
  TAX_BPS ? { transferFeeBasePoints: TAX_BPS, maxinumFee: new BN('1000000000000000') } : undefined
);

// Account 10 is the base token program (always Token-2022) and 11 the quote program passed
// above. Check them: a reshuffled SDK layout must fail here, not on chain.
if (!instruction.keys[10].pubkey.equals(TOKEN_2022_PROGRAM_ID)) throw new Error('layout changed');
if (!instruction.keys[11].pubkey.equals(new PublicKey(pair.tokenProgram))) {
  throw new Error('layout changed');
}

// Always append the allow-config account, then the curve-rule account, both read-only. This
// create stays valid when the platform turns its allowlist on or off. An initialize missing a
// required account fails with error 6018, and one outside the published shape fails with 6025.
instruction.keys.push({ pubkey: allowConfigId, isSigner: false, isWritable: false });
instruction.keys.push({ pubkey: curveRuleId, isSigner: false, isWritable: false });

// 4. Sign with both the creator and the new mint, then send it yourself.
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
const tx = new Transaction()
  .add(ComputeBudgetProgram.setComputeUnitLimit({ units: 600_000 }))
  .add(instruction);
Object.assign(tx, { recentBlockhash: blockhash, lastValidBlockHeight, feePayer: creator.publicKey });
tx.sign(creator, mintKeypair);
console.log('sent:', await connection.sendRawTransaction(tx.serialize()));

// 5. There is nothing else to call. Within a minute or two the pool is adopted. Once the venue
//    is public, GET /tokens/${mint} answers with launchpad "launchlab".

Two details in there are worth repeating, because both fail silently. The transfer-fee parameters take the exact names the Raydium SDK declares — transferFeeBasePoints and maxinumFee — and a key that does not match is simply ignored, leaving an extension with a zero rate: a mint that looks like a reward coin and taxes nobody. The SDK also supplies the classic SPL program in the quote-token-program account, so a Token-2022 quote (every xStock) needs that key substituted before you sign.

You pay only what Solana charges — rent, fees, and any priority fee you add. There is no launch fee on this path and nothing to submit to us afterwards: no paymentSignature exists to poll, so watch GET /tokens/{mint} instead. A dev buy is yours to arrange too — append a buy_exact_in to the same transaction and it fills against a pool nobody has touched.

Claiming fees#

A fee coin accrues creator fees, a share of every trading fee — about half on the default 1% pool, about three quarters on the 2% tier — on a locked position until they are claimed. The token page has a button for it; this is the same thing for a script, so you can claim across many tokens on a schedule instead of clicking through them one at a time.

Three calls. GET /tokens/{mint}/fees tells you what is waiting and needs no wallet at all; POST /tokens/{mint}/fees/claim/prepare returns an unsigned claim transaction; you sign it and hand it to POST /tokens/{mint}/fees/claim/submit. Fees arrive in both tokens of the pair — your token and the one it trades against — and land directly in your own token accounts.

Only your signature can claim your fees

The claim transaction is only valid when signed by the wallet holding that launch's Fee Key NFT, and it pays that wallet's own accounts. Preparing a claim is therefore not a privileged action and needs no credential: for a token you do not own it returns a transaction you cannot make valid, which would pay someone else if you could. No platform key signs any part of it, and submit relays only the exact transaction prepare issued — its instructions are checked against what we built before anything is broadcast.

The whole thing, end to end:

claim.mjs
import { Keypair, Transaction } from '@solana/web3.js';
import fs from 'node:fs';

const API = 'https://www.stonkfun.xyz/api/public/v1';
const mint = 'YOUR_TOKEN_MINT';
const creator = Keypair.fromSecretKey(            // the wallet holding the Fee Key NFT
  Uint8Array.from(JSON.parse(fs.readFileSync('creator.json', 'utf8')))
);

const headers = { 'Content-Type': 'application/json' };
const call = async (path, init) => {
  const response = await fetch(API + path, init);
  const body = await response.json();
  if (!response.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
  return body.data;
};

// 1. What is waiting? A plain read — no wallet involved.
const { claimable } = await call(`/tokens/${mint}/fees`);
if (!claimable) throw new Error('Nothing claimable on this launch');
console.log('Waiting:', claimable.quote.amountTokens, claimable.quote.symbol);

// 2. Prepare. Returns an UNSIGNED claim transaction, valid for 90 seconds.
const wallet = creator.publicKey.toBase58();
const prepared = await call(`/tokens/${mint}/fees/claim/prepare`, {
  method: 'POST',
  headers,
  body: JSON.stringify({ creatorWallet: wallet }),
});

// 3. Sign locally. Your key never leaves this process, and this transaction can only ever
//    pay you: sign it as-is, since altering the instructions invalidates the claim.
const tx = Transaction.from(Buffer.from(prepared.transaction, 'base64'));
tx.sign(creator);

// 4. Submit. The fees land straight in your own token accounts.
const claimed = await call(`/tokens/${mint}/fees/claim/submit`, {
  method: 'POST',
  headers,
  body: JSON.stringify({
    creatorWallet: wallet,
    intentId: prepared.intentId,
    signedTransaction: tx.serialize().toString('base64'),
  }),
});

console.log('Claimed:', claimed.signature);

A prepared claim expires after 90 seconds, because the transaction carries a live blockhash. Expiring costs you nothing — prepare again; the fees are still sitting on the position. Retrying a submit that timed out is safe too: an intentId that already went through answers with its original signature and alreadySubmitted: true rather than claiming a second time. Reward coins and pump launches have no creator position at all, so they answer 403, and 409 means there is simply nothing to claim yet.

LaunchLab launches don't work like this

Everything above describes a launch with a locked Raydium position and a Fee Key NFT. A LaunchLab launch has neither, and its creator is paid a different way: the platform collects the pool's 1% fee and forwards the creator's share to their wallet automatically. There is nothing to sign and nothing to poll — GET /tokens/{mint}/fees says so in its reason, and a reward launch distributes the mint's transfer tax to holders and has no creator fees at all, so both claim calls answer 403.

One exception, and it is worth knowing before you write a loop over a portfolio: launches created before the platform's fee shape was unified accrue into an on-chain vault keyed by creator and quote token — not by launch. When the read reports one, it carries scope: "creator-quote-vault", the amount is quote-side only, and claiming it from any one of that creator's launches against that quote sweeps the balance for all of them. Claim once per quote token, not once per mint.

Rate limits#

Every response carries X-RateLimit-Remaining and X-RateLimit-Reset. A 429 adds Retry-After; honour it.

EndpointsPer minuteWhy
Every /api/public/v1 endpoint except the two prepares300Reads, both submits, status
POST /launches/prepare25Launch quotes
POST /tokens/{mint}/fees/claim/prepare20Claim quotes
/api/v2/revenue/summary, /platform-token/split30Whole-history aggregates
Every other /api/v2 endpoint240v2 reads

Limits are per IP address and per minute, and that table is the whole story: there are no paid tiers above it. Read responses are CDN-cached, and a cache hit never reaches our servers, so it costs you nothing against these numbers. Building something that needs more headroom? Get in touch.

Endpoint reference#

OpenAPI spec →
GET/api/v2/launches/recent

Launches from the last windowMs milliseconds (10 minutes), read from the launch records. Use it to show a launch before the pool sweep includes it. Each pool has pending: true. Market figures come from the latest indexed chain state, or from the opening market cap when there is none yet. status is never graduated, and liquidityUsd is absent. The body is {pools, degraded, network, windowMs, page, generatedAt}. A page can hold fewer than limit pools before the end, because hidden launches are removed. degraded: true means the read failed and pools is empty: try again.

limit
integer·1-100, defaults to 25. A value out of range is clamped.
order
'desc' | 'asc'·Defaults to desc (newest first). Send the same order with every cursor.
cursor
string·page.nextCursor from the previous response. Omit it for the first page. A cursor from a different endpoint or order answers 400.
GET/api/v2/launches/{mint}

The launch record for a mint, in the pool shape, with pending: true. Works at any age of the launch. Market figures are calculated as in /launches/recent, so for a token that trades already, GET /api/public/v1/tokens/{mint} is more complete. The body is {pool, degraded, network, generatedAt}. Answers 200 with pool: null when the platform did not launch the mint. degraded: true means the read failed: try again.

mint*
string·Token mint address.
GET/api/v2/tokens/{mint}/socials

The website, twitter and telegram links of a token, as its token page shows them. Each key is absent when the token has no such link. An address that is not valid gives {}.

mint*
string·Token mint address.
GET/api/v2/tokens/{mint}/rewards

Lifetime holder-reward totals of a reward coin. The body is {mint, mode, quote, basis, rewards, base, generatedAt}. rewards holds quote-token amounts. base holds what the launch paid in its own token, and is null when it never did. A standard launch gives mode: "standard" with null rewards. basis is "ledger" or "snapshot", the source of the totals. basis: "awaiting-snapshot" means the totals are not built yet, and rewards is null: try again in one minute. The figures that change on each payout are on /tokens/{mint}/rewards/pending. walletsPaid counts the distinct wallets ever paid in that asset. Fee recipient payouts are not in these totals: see /tokens/{mint}/rewards/fee-recipients. Each *Raw field is an integer string. Each *Tokens field is null when the decimals are not known.

mint*
string·Token mint address.
GET/api/v2/tokens/{mint}/rewards/holders

Lifetime totals of what the holders of a reward coin were paid. The body is {mint, mode, quote, basis, rewards, base, generatedAt}. These are the /tokens/{mint}/rewards totals, which do not include fee recipient payouts. rewards is {distributedRaw, distributedTokens, payoutCount} in the quote token. base is the same in the launch token with an asset field, and is null when no holder was paid in it. mode has the same meaning as on /tokens/{mint}/rewards. basis is "ledger". basis: "awaiting-ledger" means the totals are not built yet, and rewards is null: try again in one minute. Each *Raw field is an integer string. Each *Tokens field is null when the decimals are not known.

mint*
string·Token mint address.
GET/api/v2/tokens/{mint}/rewards/fee-recipients

What a StandardV2 launch paid its fee recipients, and one page of its recipient wallets. The body is {mint, quote, shareBps, recipientCount, rewards, base, rows, page}. shareBps is the share of the transfer fee all recipients take together. recipientCount is the number of current recipients. rewards is what they were paid in the quote token, and base what they were paid in the launch token, null when nothing was. Each paid figure is {distributedRaw, distributedTokens, payoutCount, lastPayoutAt}, delivered payouts only. Each row is {wallet, isCreator, slot, shareBps, asset, quote, base}. isCreator is true for the wallet that launched the token. shareBps and asset are null for a wallet that is no longer a recipient. A quote recipient can also be paid in the launch token. A launch with no fee recipients answers 404. Each *Raw field is an integer string. Each *Tokens field is null when the decimals are not known.

mint*
string·Token mint address.
limit
integer·1-100, defaults to 25. A value out of range is clamped.
order
'desc' | 'asc'·Defaults to asc: current recipients in slot order, then former ones. Send the same order with every cursor.
cursor
string·page.nextCursor from the previous response. Omit it for the first page. A cursor from a different endpoint or order answers 400.
GET/api/v2/tokens/{mint}/rewards/pending

What holders of a reward coin are owed and have not received. The body is {mint, mode, quote, pending, base, generatedAt}. In pending, undistributedRaw is in the pot and not yet allocated. queuedRaw is allocated, and its funding transfer has not landed. inFlightRaw is in the distribution wallet, and waits for delivery or for the holder to open a token account. strandedRaw cannot be delivered and waits for an admin. What holders are owed is undistributedRaw + queuedRaw + inFlightRaw. base gives the same figures, without undistributed, in the launch's own token, and is null when they are all zero. What is owed to fee recipients is not in these figures. Each *Raw field is an integer string, with a *Tokens field next to it.

mint*
string·Token mint address.
GET/api/v2/tokens/{mint}/rewards/payouts

One page of the payouts delivered to holders of a reward coin. The body is {rows, page}. Each row is {signature, holder, assetMint, amountRaw, amountTokens, createdAt}. One signature can pay many holders. assetMint is the quote token, or the launch mint for a payout in the launch's own token. amountTokens is null when the decimals are not known. Fee recipient payouts are not in the rows: see /tokens/{mint}/rewards/fee-recipients.

mint*
string·Token mint address.
limit
integer·1-100, defaults to 25. A value out of range is clamped.
order
'desc' | 'asc'·Defaults to desc (newest first). Send the same order with every cursor.
cursor
string·page.nextCursor from the previous response. Omit it for the first page. A cursor from a different endpoint or order answers 400.
GET/api/v2/rewards/launches

One page of lifetime reward totals, one row for each launch and the asset it paid. The body is {asset, sort, basis, rows, page}. Each row is {mint, asset, distributedRaw, distributedTokens, payoutCount, walletsPaid, lastPayoutAt}. asset is {mint, symbol, decimals}. walletsPaid counts the distinct wallets ever paid in that asset. sort=distributed orders by distributedTokens and leaves out rows whose decimals are not known. Amounts in different assets are compared as token counts, not by value. sort=recent orders by lastPayoutAt. Totals include payouts up to about one minute old. basis: "awaiting-backfill" means the totals are not built yet, and rows is empty.

asset
'quote' | 'base'·Defaults to quote. base lists rewards paid in the launch's own token.
sort
'distributed' | 'recent'·Defaults to distributed. desc gives the largest or the newest first.
limit
integer·1-100, defaults to 25. A value out of range is clamped.
order
'desc' | 'asc'·Defaults to desc (newest first). Send the same order with every cursor.
cursor
string·page.nextCursor from the previous response. Omit it for the first page. A cursor from a different endpoint or order answers 400.
GET/api/v2/rewards/payouts

One page of the payouts delivered to holders of every reward coin. The body is {rows, page}. Each row is {signature, launchMint, holder, assetMint, amountRaw, amountTokens, createdAt}. One signature can pay many holders and several launches. amountTokens is null when the decimals are not known.

asset
'quote' | 'base'·Defaults to quote. base lists payouts made in the launch's own token.
limit
integer·1-100, defaults to 25. A value out of range is clamped.
order
'desc' | 'asc'·Defaults to desc (newest first). Send the same order with every cursor.
cursor
string·page.nextCursor from the previous response. Omit it for the first page. A cursor from a different endpoint or order answers 400.
GET/api/public/v1/tokens

Every token with a live platform pool, with market data. Works without a key at a lower rate limit. V3 reward tokens additionally carry transferFee.bps (a Token-2022 transfer tax paid to holders — use the Token-2022 program for their accounts) and, while in the buyback rankings, flywheel.active. Community Mode tokens carry communityMode.shareBps: the share of every holder payout that goes to holders of the quote token instead. StandardV2 tokens carry feeRecipients.shareBps: the share of the transfer tax paid to the fee recipients set at launch (the creator by default) before holders.

q
string·Search name, symbol or mint.
sort
'marketCap' | 'newest' | 'volume'·Defaults to marketCap.
mode
'standard' | 'reward'·Filter by fee model.
status
'new' | 'aboutToGraduate' | 'graduated'·Filter by graduation status.
quoteMint
string·Filter by paired token.
category
string·Filter by pair category, e.g. xstock.
page
integer·Defaults to 1.
pageSize
integer·1-100, defaults to 25.
GET/api/public/v1/tokens/{mint}

Live market data plus the launch record, when the platform launched it. V3 reward tokens carry the same optional transferFee, communityMode, feeRecipients and flywheel fields as /tokens.

mint*
string·Token mint address.
GET/api/public/v1/tokens/{mint}/burns

Totals and recent burns of this token by the platform fee sweep.

mint*
string·Token mint address.
limit
integer·1-100, defaults to 25.
GET/api/public/v1/tokens/{mint}/rewardsdeprecated

Distribution totals for a reward coin. Standard launches answer with mode "standard" and a null rewards object. Amounts under "rewards" are quote-token amounts; the separate "base" object carries what the launch paid holders in its OWN token, and is null when that has never happened.

Deprecated. Use GET /v2/tokens/{mint}/rewards and GET /v2/tokens/{mint}/rewards/pending instead. v2 splits the figures: lifetime totals are on /rewards and the undistributed, queued, inFlight and stranded figures are on /rewards/pending. Each base object is null on its own. v2 does not read the chain, so quote.decimals and the *Tokens fields are null where v1 read the decimals from the mint account. Before the totals are first built, v2 gives basis: "awaiting-snapshot" where v1 gives 503.

mint*
string·Token mint address.
GET/api/public/v1/tokens/{mint}/airdrop

The airdrop a token launched with, if any: what share of supply was carved out of the pool, how many wallets received it, and where those wallets came from. Reads the frozen snapshot taken at quote time, so it is the drop that was actually paid for rather than a live balance scan. A token that launched without one answers airdrop: null, which is not an error — most tokens have no airdrop.

mint*
string·Token mint address.
GET/api/public/v1/tokens/{mint}/backing

USD permanently locked behind a pump-launched token, summed from the platform’s own locked positions. Pump launches only: every other launch — Raydium CLMM and LaunchLab alike — answers 400 invalid_request rather than a zero, since backing is not a thing those have. Check launchpad from /tokens/{mint} before calling.

mint*
string·Token mint address.
GET/api/public/v1/launches

The launch ledger, newest first. Filter by creator to find your own. Launches built directly against the venue appear here too, once adopted, under launchpad "launchlab" — no payment of ours exists for those, so they are read here or from /api/v2/launches/{mint} rather than by polling a payment signature.

creator
string·Filter by creator wallet.
mode
'standard' | 'reward'·Filter by fee model.
since
ISO 8601·Only launches at or after this time.
page
integer·Defaults to 1.
pageSize
integer·1-100, defaults to 25.
GET/api/public/v1/pairs

Quote tokens a new launch can be paired against. Call this first — quoteMint must be one of these. Two different gates apply and both are reported: `launchable` is this platform’s own rule (retired categories and mints are false), while `launchLabReady` says whether Raydium has created the on-chain GlobalConfig a LaunchLab launch needs. A pair can be launchable but not yet LaunchLab-ready; constructing a launch against one of those fails on-chain. `launchLabReady` is absent rather than false when the venue is off or the probe could not run. `communityMode` says whether a Community Mode launch can pair against the token, the same answer as `communityMode.offeredOnThisQuote` in GET /launchlab/pricing; it is absent while the venue is off. `standardV2Enabled` says whether StandardV2 launches are enabled on this deployment. When it is true, every LaunchLab-ready pair accepts a StandardV2 launch.

category
string·Filter by category.
launchable
boolean·Set true to exclude retired categories.
launchLabReady
boolean·Set true to return only pairs with a live LaunchLab config on-chain.
communityMode
boolean·Set true to return only pairs a Community Mode launch can pair against.
GET/api/public/v1/rewardsdeprecated

Lifetime payout totals per reward coin plus recent distribution transactions. "launches" and "recentDistributions" are quote-token amounts only; rewards paid in a launch's own token appear in "baseDistributions" and "recentBaseDistributions". In those two, "decimals" and the token amount are null together when the launch record cannot be resolved — read the raw amount instead of scaling it yourself. "launches" and "baseDistributions" are sorted by amount distributed and paged together by "page" and "pageSize"; each reports its own total in "launchesPagination" and "baseDistributionsPagination", and a page past its end is empty. Symbol and decimals for every quote mint in the response are in "quotes", keyed by mint (and in the "quote" object of each row). total and totalPages are null: read pages until one has fewer than pageSize rows. Rows whose decimals are not known are left out.

Deprecated. Use GET /v2/rewards/launches and GET /v2/rewards/payouts instead. v2 pages each list with a cursor (page.nextCursor) instead of page numbers, and asks for quote and base totals separately with asset=quote|base. v2 gives walletsPaid where v1 gives holderCount, and one payout row per holder where v1 groups recent distributions by signature.

limit
integer·Recent distributions, 1-100, defaults to 25.
page
integer·Defaults to 1.
pageSize
integer·1-1000, defaults to 100.
GET/api/public/v1/stats

Aggregate totals plus the thresholds and switches a client needs, so your UI tracks the platform instead of hardcoding it. config.paidLaunchesEnabled and config.launchLabEnabled together say which launch path is live: the two-call /launches flow, the transaction you build yourself, or both. Read them before offering a launch button.

GET /api/public/total-assetsno key

One more, outside the versioned base path: a flat index of every token this platform has launched, built for exchanges, aggregators and explorers. It carries asset identity only — mint, name, symbol, decimals, logo — and no market data, so it is cheap to poll on a schedule. Predates v1 and is unversioned; it is not going anywhere. Use GET /tokens above when you want prices, market caps and volume.

Errors#

Every v1 failure returns { error: { code, message } }. Branch on code, which is stable; messages are for humans and may be reworded. A v2 failure returns { error: string }: branch on the HTTP status in the table below.

CodeHTTPMeaning
invalid_request400A parameter is missing or malformed.
forbidden403The action is refused outright.
not_found404No such resource.
method_not_allowed405Wrong HTTP method for this path.
conflict409Well-formed, but the moment is wrong. For a launch, the payment landed and needs manual recovery — never retry or re-pay. For a fee claim, nothing is claimable yet or the prepared claim expired, and preparing again is the fix.
rate_limited429Per-minute limit exceeded. Honour Retry-After.
internal500Something broke on our side. Safe to retry.
service_unavailable503A dependency or feature is temporarily unavailable.

Spotted something wrong or unclear on this page? Tell us on X and we'll fix it.