REST API
Public read endpoints. JSON, no authentication, no API keys. Base URL: https://lumpfun.com. Per-IP rate limits apply — reads are generous, transaction building is tighter, and exceeding either returns 429 with a retry-after header. Requests are same-origin by default: these routes send no CORS headers, so call them from a server rather than a browser on another origin.
All bigint values (lovelace, token quantities, reserves) are returned as strings to preserve precision; parse them with BigInt, never Number.
Two pool generations are live. Current tokens (poolVersion: "v3") trade on a bonding curve that graduates in place into a permanent AMM pool — the same UTxO, flipped by a datum field, tradable forever afterwards on LumpSwap. Older v1/v2 tokens are historical and several endpoints behave differently for them; each notes where it matters.
Endpoints
GET /api/tokensGET /api/token/{policyId}GET /api/curveGET /api/v3/poolGET /api/quoteGET /api/holdersGET /api/tradesGET /api/price-historyGET /api/wallet-assetsPOST /api/tx/buildPOST /api/tx/submitErrors/api/tokens
List every token registered with LumpFun, ordered newest first. Each entry is the full TokenMetarecord — the same shape stored in our KV registry.
Response (200) — array of:
{
"policyId": "ec11a20dc05761a24c415cfc85b42ef5b31caa52dd501082d6744b9c",
"assetName": "4d5547", // hex of utf-8 ticker
"ticker": "MUG",
"name": "Mug",
"creatorAddress": "addr1q...", // bech32 of creator wallet
"creatorFeeBps": 100, // 100 = 1%, max 200
"curveAddress": "addr1w...", // bonding-curve script
"validatorCbor": "59...", // parameterised PlutusV3
"graduationAdaLovelace": "21000000000", // optional, default 21k ADA
"imageUri": "https://...",
"description": "...",
"website": "https://...", // all socials optional
"twitter": "@handle",
"telegram": "t.me/...",
"discord": "discord.gg/...",
"launchedAt": "2026-05-05T11:48:29.797Z",
// Set when graduation has happened:
"graduatedTxHash": "f326c7...",
"minswapPoolTxHash": "77d4bd...",
"minswapPoolId": "ec11a2...4d5547",
"poolAdaLovelace": "12000000",
"poolTokens": "3970836",
// Set when creator picked a launch vesting window:
"vestingAddress": "addr1w...",
"vestingValidatorCbor": "...",
"vestingUnlockMs": 1799123456000,
"vestingClaimedTxHash": "...",
"extraVestings": [ /* additional re-vest positions */ ],
// Set on tokens launched after the fee accumulator shipped:
"feeAccumulatorAddress": "addr1w...",
"feeAccumulatorValidatorCbor": "...",
"feeAccumulatorClaimedTxHash": "..."
}curl
curl https://lumpfun.com/api/tokensts
const tokens = await fetch('https://lumpfun.com/api/tokens').then(r => r.json());
for (const t of tokens) {
console.log(t.ticker, t.policyId);
}/api/token/{policyId}
Single token lookup with live curve state attached. Cheaper than fetching /api/tokens and filtering when you already know the policy ID.
Response (200):
{
...all TokenMeta fields,
"live": {
"adaReserve": "12345678", // lovelace currently at the curve
"tokenReserve": "987654321", // tokens still purchasable
"priceLovelace": "3049999", // (adaReserve+virtual)*1e6/tokenReserve
// NOTE: SCALED BY 1e6. To get ADA/token
// divide by 1e12, not 1e6 — the 1e6 is a
// fixed-point scale, and the lovelace→ADA
// conversion is a second 1e6.
"marketCapAda": 3049.999, // priceLovelace * total_supply / 1e12
"bondedPct": 0.05, // 0–100, 100 = at graduation
"graduated": false
}
}live is null for fully-graduated tokens whose curve UTxO has been drained — read poolAdaLovelace / poolTokens from the meta instead.
curl
curl https://lumpfun.com/api/token/ec11a20dc05761a24c415cfc85b42ef5b31caa52dd501082d6744b9c/api/curve
Raw on-chain curve state. The lowest-latency way to poll reserves for a trading agent — bypasses any cache layer above Blockfrost.
Query params:
| name | description | |
|---|---|---|
| address | bech32 curve script address (from token meta) | required |
| asset | concatenation of policyId + assetName (hex) | required |
Response (200):
{
"adaReserve": "5000000", // lovelace in the curve UTxO
"tokenReserve": "996679946" // tokens still in the curve
}Returns 404 with {"error":"curve UTxO not found"} after the token has graduated and the UTxO is gone.
Side effect:any GET to this endpoint also kicks off a graduation check for that token. If reserves have crossed the threshold and the migration hasn't run yet, the server queues it. Idempotent and safe to poll.
curl
curl "https://lumpfun.com/api/curve?address=addr1wxp8497v67f4vzpsrqmc97rv2vyq6vntrzkz4pc2ce92sncmzz5z5&asset=ec11a20dc05761a24c415cfc85b42ef5b31caa52dd501082d6744b9c4d5547"/api/v3/pool
Live pool state for a current-cohort token, read from the pool UTxO's own inline datum. This is the authoritative source for a v3 token's reserves, price and phase.
Query params:
| name | description | |
|---|---|---|
| policyId | token policy ID | required |
Response (200):
{
"adaReserve": "2000000",
"tokenReserve": "1142607197",
"mode": "Bootstrap", // "Bootstrap" = bonding curve
// "Amm" = graduated permanent pool
"bondedBps": 3, // curve progress, 10000 = ready to graduate
"creatorFeeBps": 100,
"platformFeeBps": 0,
"platformFeeFlat": "2000000", // flat 2 ADA per trade
"txHash": "...", // the pool UTxO being read
"outputIndex": 0
}Always take mode from here, never from the registry. Graduation is permissionless — anyone may submit it once the curve is bought out — so it can land between two polls, and the two phases price with different arithmetic. In Bootstrap the reserves carry virtual offsets; in Amm they are the real balances.
Returns 502 when the chain backend cannot be read, and 404 for a token that is not v3.
curl
curl "https://lumpfun.com/api/v3/pool?policyId=POLICY"/api/quote
Pre-trade quote computed against live reserves with the on-chain curve math (quoteBuy / quoteSellGross from web/src/lib/curve-math.ts). Same numbers the validator will check at submit time — use this so your agent and the chain agree.
Query params:
| name | description | |
|---|---|---|
| policyId | token policy ID (from registry) | required |
| side | "buy" or "sell" | required |
| amount | bigint string. Buy: lovelace in. Sell: tokens in. | required |
| slippageBps | 0–500. Default 50 (0.5%). | optional |
Response (200):
{
"side": "buy" | "sell",
"policyId": "...",
"assetUnit": "<policyId><assetName>",
"amountIn": "5000000",
"expectedOut": "166112956", // tokens (buy) or lovelace gross (sell)
"minOut": "165280391", // expectedOut after slippage applied
"creatorFeeBps": 100,
"creatorFeeLovelace": "50000", // bps × ada_in (buy) or × ada_gross (sell)
"platformFeeLovelace": "1000000", // flat, per trade — see note below
"adaNetLovelace": "...", // sell only — gross − creator − platform
"reserves": { "adaReserve": "...", "tokenReserve": "..." },
"graduated": false,
"slippageBps": 50
}This endpoint serves v1/v2 tokens only. For a current (v3) token it returns 409 wrong_cohort: v3 uses different curve constants and a mode-selected arithmetic, so quoting it with these formulas would produce numbers the validator rejects. Read /api/v3/pool and quote from its reserves instead. The flat platform fee is 2 ADA on v3 and 1 ADA on the legacy cohorts; the creator fee is 1% of the ADA leg on both, paid on top of a buy and deducted from a sell.
A 409 also means a legacy curve has already graduated. v1 graduation drained the curve to a Minswap pool; v2 and v3 flip in place and keep trading.
curl (buy 5 ADA)
curl "https://lumpfun.com/api/quote?policyId=POLICY&side=buy&amount=5000000"curl (sell 1M tokens)
curl "https://lumpfun.com/api/quote?policyId=POLICY&side=sell&amount=1000000"/api/holders
Top holders of an asset, derived from Blockfrost's asset-addresses index. Includes the bonding curve and any vesting script addresses — filter client-side if you only want wallets.
Query params:
| name | description | |
|---|---|---|
| asset | concatenation of policyId + assetName (hex) | required |
Response (200) — array of:
{
"address": "addr1q...",
"quantity": "996679946" // bigint string
}curl
curl "https://lumpfun.com/api/holders?asset=ec11a20dc05761a24c415cfc85b42ef5b31caa52dd501082d6744b9c4d5547"/api/trades
Recent trades on a curve, derived from on-chain tx deltas. Sorted newest first, capped at 25 entries. Each row reports the actual buyer/seller (the wallet that signed the tx, identified via inputs — not the treasury or creator-fee output addresses).
Query params:
| name | description | |
|---|---|---|
| address | bech32 curve script address | required |
| asset | concatenation of policyId + assetName | required |
Response (200) — array of:
{
"txHash": "9a1b2c...",
"type": "buy" | "sell",
"adaDelta": "10200000", // |Δ pool lovelace| (a buy includes its fees)
"adaAmount": "10000000", // ADA without fees: buy = into the curve, sell = received
"tokenDelta": "32156789", // |Δ token_reserve| in token units
"trader": "addr1q...",
"blockTime": 1777991234 // unix seconds
}Cached for 24h per tx-hash via Next.js ISR — recent trades come live, deeper history is stable so we don't re-query Blockfrost on every page load.
/api/price-history
OHLC bars for chart rendering. Server buckets trades into the requested timeframe. Same query params as /api/trades plus the bucket size.
Query params:
| name | description | |
|---|---|---|
| address | bech32 curve script address | required |
| asset | concatenation of policyId + assetName | required |
| timeframe | "5m" | "15m" | "1h" | "all". Default "15m". | optional |
Response (200) — array of bars:
{
"t": "5/5 13:00", // formatted display label
"timestamp": 1777991100, // unix seconds (bucket start)
"open": 0.04,
"high": 0.045,
"low": 0.04,
"close": 0.043
}Prices are floating-point ADA-per-token, derived from the curve datum at each tx (not lovelace). For the precise on-chain price use /api/curve → spotPrice from curve-math.
/api/wallet-assets
Non-ADA assets held by a Cardano address, with LumpFun registry metadata joined on for any asset that was launched via this protocol.
Query params:
| name | description | |
|---|---|---|
| address | bech32 (mainnet addr1...) | required |
Response (200):
{
"assets": [
{
"unit": "ec11a20...4d5547",
"quantity": "3298081",
"registry": { // present only for LumpFun-launched tokens
"policyId": "ec11a20...",
"assetName": "4d5547",
"ticker": "MUG",
"name": "Mug",
"imageUri": "https://..."
}
}
]
}Returns {"assets": []} (status 200) for an address with no assets. Resolution runs against our own node's chain index, which covers all history, so there is no "not indexed yet" case.
/api/tx/build
Builds an unsigned transaction against our own Cardano node and returns its CBOR. Your wallet signs it; the server cannot. It holds no key for your address and operates a read-only wallet, so the only thing this endpoint can hand you is a transaction you must sign yourself.
Contract parameters are deliberately not taken from the request. Pool address, validator script, fee rate and fee routing are read from the registry, which is re-derived and verified at registration time. You supply only who is paying and how much.
Body:
| name | description | |
|---|---|---|
| action | 'buy' | 'sell' | 'launch' | 'order-buy' | 'order-sell' | 'order-cancel' | 'claim-fees' | 'claim-vesting' | 'revest' | required |
| address | bech32 — whose UTxOs fund the tx and where change goes | required |
| policyId | token being acted on (all actions except launch) | conditional |
| amount | bigint string — lovelace for buys, token units for sells | conditional |
| slippageBps | integer 0..5000 (default 100) | optional |
Response (200):
{
"cbor": "84a300d90102...", // unsigned tx — sign this
"tokensOut": "1662787" // buys; sells return adaNet instead
}Flow:
const built = await post('/api/tx/build', { action: 'buy', policyId, address, amount });
const witness = await walletApi.signTx(built.cbor, true); // partial sign
const { txHash } = await post('/api/tx/submit', { cbor: built.cbor, witness });Returns 409 for actionable conditions — chain index behind tip, no UTxOs at the address, sell too large for the pool to honour, pool UTxO missing.
/api/tx/submit
Attaches a CIP-30 witness set to a transaction this server built and submits it. The transaction is re-hydrated from the exact bytes you signed, so the signature cannot be invalidated by a rebuild.
Body:
| name | description | |
|---|---|---|
| cbor | the unsigned tx returned by /api/tx/build | required |
| witness | hex witness set from walletApi.signTx(cbor, true) | required |
Response (200):
{ "txHash": "288ab0f22c5bacfa58f76b8a1c7bc1081d3af732624adb0b471624b7d0f2a926" }An invalid or missing signature is rejected by the ledger. The server cannot substitute one.
Errors
Errors are JSON with a single error field. Common shapes:
400— missing/invalid query params (e.g. non-bigintamount).404— token not in registry, or the pool UTxO is genuinely not on chain.409— real token, operation not applicable to its current state: a v3 token on a v2-only endpoint, a graduated legacy curve, or an amount the pool cannot fill.429— rate limited. Honourretry-after.500— internal error.502/503— a data source we depend on could not be read. The answer is unknown, not empty.
That last distinction is load-bearing and these routes hold to it: a failed read never returns 200 []. An empty array means the chain really is empty; a backend failure is a 502/503 with a reason. Code that treats them alike will eventually report a healthy zero for an outage — retry on 5xx rather than caching the emptiness.