Developer API

Launch tokens and read platform data programmatically. Base URL /api/public/v1.

Non-custodial by construction. We never ask for, accept or store a private key. You sign your own launch fee locally; there is no endpoint that will sign on your behalf, and none that can make the platform wallet sign anything you supply.

Quickstart

There are no API keys and nothing to sign up for. Every endpoint — including launching — is open, with a per-minute rate limit per IP address.

# 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

A launch is authorised by the creator's own signature on the fee payment, which is stronger proof than any key we could issue — so we do not issue one. Your wallet key stays on your machine and is never sent anywhere.

Launching a token

Two calls: prepare, then submit. In between you sign the launch fee with the creator's wallet.

Fee coin · mode: "standard"

Trades on a 1% pool. Trading fees split 50/50 between the creator and the platform; the creator claims their half from the token page or by wallet.

Reward coin · mode: "reward"

Trades on a 4% pool and pays 85% of trading fees straight to holders, automatically, in the token it is paired against. No creator fee position.

Raydium pairs — what you launch against

Every token is priced against a real asset rather than SOL: tokenized stocks (xStocks), pre-IPO stocks (PreStocks), currencies, or a custom mint. Fetch the current list from GET /pairs and pass one as quoteMint.

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

const API = 'https://www.stonkfun.xyz/api/public/v1';
const creator = Keypair.fromSecretKey(            // your own wallet, never sent anywhere
  Uint8Array.from(JSON.parse(fs.readFileSync('creator.json', 'utf8')))
);

const headers = { 'Content-Type': 'application/json' };   // no key, nothing to sign up for
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. Pick a pair to launch against.
const { pairs } = await call('/pairs?launchable=true');
const pair = pairs.find((item) => item.symbol === 'NVDAx') ?? pairs[0];

// 2. Prepare. Returns an UNSIGNED payment transaction.
const logo = 'data:image/png;base64,' + fs.readFileSync('logo.png').toString('base64');
const prepared = await call('/launches/prepare', {
  method: 'POST',
  headers,
  body: JSON.stringify({
    creatorWallet: creator.publicKey.toBase58(),
    quoteMint: pair.mint,
    name: 'My Token',
    symbol: 'MYTKN',
    mode: 'standard',          // 'standard' splits trading fees 50/50 with you
    logo,
  }),
});

// 3. Sign the fee payment locally. Your key never leaves this process.
const tx = Transaction.from(Buffer.from(prepared.paymentTransaction, 'base64'));
tx.sign(creator);

// 4. Submit. Usually returns a finished token in this one call.
let result = await call('/launches/submit', {
  method: 'POST',
  headers,
  body: JSON.stringify({
    signedQuote: prepared.signedQuote,
    signedTransaction: tx.serialize().toString('base64'),
    logo,                      // must be byte-identical to step 2
  }),
});

// 5. If the platform's launch slots were busy, poll. NEVER pay again.
while (result.status === 'processing') {
  await new Promise((resolve) => setTimeout(resolve, 5000));
  result = await call(`/launches/${result.paymentSignature}`);
}

console.log('Live:', result.mint);

If submit returns "processing"

Your payment landed and the launch is queued behind the platform's concurrent launch limit. The work is checkpointed against your payment signature and will be completed automatically even if your process dies. Poll GET /launches/{paymentSignature} until it reads completed. Never pay twice — a second payment creates a second token.

Rate limits

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

EndpointsPer minuteWhy
Everything except prepare120Reads, submit, resume, status
POST /launches/prepare10Quotes cost us chain reads before you pay

That is the whole story — no plans, no tiers, no keys, and nothing to sign up for. Limits are per IP address and per minute. Read responses are CDN-cached, and a cache hit never reaches our servers, so it costs you nothing against these limits. Building something that needs more headroom? Get in touch.

GET/api/public/v1/tokens

Every token with a live platform pool, with market data. Works without a key at a lower rate limit.

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.

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}/rewards

Distribution totals for a reward coin. Standard launches answer with mode "standard" and a null rewards object.

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

Trading fees currently claimable by the creator of a standard (fee coin) launch. Read-only: claiming is a wallet-signed action on the token page, never an API operation. Reward coins and pump launches return claimable: null with a reason.

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. Only meaningful for pump launches.

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

The launch ledger, newest first. Filter by creator to find your own.

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.

category
string·Filter by category.
launchable
boolean·Set true to exclude retired categories.
GET/api/public/v1/rewards

Lifetime payout totals per reward coin plus recent distribution transactions.

limit
integer·1-100, defaults to 25.
GET/api/public/v1/revenue

Fee revenue, buybacks and burns.

limit
integer·1-100, defaults to 25.
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.

Also available

GET /api/public/total-assetsno key

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 below when you want prices, market caps and volume.

Errors

Every failure returns { error: { code, message } }. Branch on code, which is stable — messages are for humans and may be reworded.

CodeHTTPMeaning
invalid_request400A parameter is missing or malformed.
forbidden403This deployment refuses the action outright — currently only reward launches, while they are admin-only. No credential would change it.
not_found404No such resource.
method_not_allowed405Wrong HTTP method for this path.
conflict409The request cannot proceed — for a launch, that the payment landed but needs manual recovery. Never retry or re-pay.
rate_limited429Per-minute limit exceeded. Honour Retry-After.
internal500Something broke on our side. Safe to retry.
service_unavailable503A dependency or feature is temporarily unavailable.