{"openapi":"3.1.0","info":{"title":"Launchpad API","version":"0.1.0","description":"Indexer + HTTP API for the NOXA-style launchpad on Robinhood Chain (chain id 46630). All amounts are base units (wei) as strings, with `*Formatted` display helpers. USD fields appear only when an ETH/USD rate is available."},"servers":[{"url":"/","description":"This server"}],"tags":[{"name":"system","description":"Health, sync status, chain params, gas, price"},{"name":"tokens","description":"Token discovery, detail, trades, candles, holders, trust"},{"name":"trading","description":"Quotes/calldata and launch preparation"},{"name":"wallets","description":"Wallet holdings and watchlist"},{"name":"social","description":"Comments"},{"name":"auth","description":"SIWE sign-in and sessions"},{"name":"media","description":"Image upload"},{"name":"docs","description":"This contract"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Session token from POST /api/auth/verify, sent as `Authorization: Bearer <token>`"}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]},"TokenSummary":{"type":"object","description":"Ranking/list summary shape shared by /tokens, /board and wallet listings","properties":{"address":{"type":"string"},"name":{"type":"string"},"symbol":{"type":"string"},"image":{"type":["string","null"],"description":"Sanitized image URL, null if unsafe/absent"},"creator":{"type":"string","description":"Checksummed creator address"},"priceWeth":{"type":"string","description":"WETH per token, base-unit string"},"priceWethFormatted":{"type":"string"},"marketCapWeth":{"type":"string"},"marketCapWethFormatted":{"type":"string"},"volumeWeth":{"type":"string","description":"All-time volume in WETH, base-unit string"},"volumeWethFormatted":{"type":"string"},"priceUsd":{"type":"string","description":"Present only when an ETH/USD rate is available"},"marketCapUsd":{"type":"string","description":"Present only when an ETH/USD rate is available"},"volumeUsd":{"type":"string","description":"Present only when an ETH/USD rate is available"},"priceChange":{"type":"object","properties":{"sinceLaunch":{"type":"number","description":"Fractional change since launch price (0.1 = +10%)"},"h24":{"type":"number","description":"Fractional 24h change; 0 when no trade in the last 24h"}}},"holderCount":{"type":"integer"},"lastTradeAt":{"type":["integer","null"],"description":"Unix seconds of the last trade, null if none"},"createdAt":{"type":"integer","description":"Unix seconds"},"graduation":{"type":"object","description":"Graduation progress. Eligible token: {eligible:true, metric, currentWei, targetWei, progressBps, graduated, graduatedAtBlock, indexedBlock}. Legacy token: {eligible:false, reason:'legacyDeployment'}. The whole object may be null when an eligible token's metric is momentarily unavailable. The pool stays live and tradeable both before AND after graduation.","properties":{"eligible":{"type":"boolean","description":"True only for a token on the CURRENT factory's FeeHook. Legacy V4 coins are {eligible:false, reason:'legacyDeployment'} and never graduate."},"reason":{"type":"string","description":"Present only when eligible=false (e.g. 'legacyDeployment')"},"metric":{"type":"string","description":"'netPoolEth' = net ETH in the pool, SUM(ethIn)-SUM(ethOut), exact wei"},"currentWei":{"type":"string","description":"Net pool ETH in wei (eligible only)"},"targetWei":{"type":"string","description":"Graduation target in wei (eligible only)"},"progressBps":{"type":"integer","description":"currentWei/targetWei in basis points, clamped 0..10000 (eligible only)"},"graduated":{"type":"boolean","description":"True once currentWei first reached targetWei; permanent (eligible only)"},"graduatedAtBlock":{"type":["integer","null"],"description":"Block the target was first crossed; null before that (eligible only)"},"indexedBlock":{"type":["integer","null"],"description":"Indexer head at read time, a freshness marker; may be null"}},"additionalProperties":true}}},"FeesBlock":{"type":"object","description":"Recommended fee params + per-tx cost. Degrades to just { note } when RPC fee data or the gas estimate is unavailable.","properties":{"gasEstimate":{"type":"string","description":"Present when a gas estimate was computed"},"gasEstimateSource":{"type":"string","description":"'simulated' (exact, needs ?from=) or 'fallback' (buffered default)"},"gasPrice":{"type":"string"},"maxFeePerGas":{"type":"string"},"maxPriorityFeePerGas":{"type":"string"},"estimatedGasCostWei":{"type":"string"},"estimatedGasCostEth":{"type":"string"},"estimatedTotalWei":{"type":"string","description":"DISPLAY ONLY (value + gas); do NOT use as msg.value"},"estimatedTotalEth":{"type":"string"},"totalNote":{"type":"string"},"note":{"type":"string","description":"Present instead of the fields above when fee/gas data was unavailable"}},"additionalProperties":true},"TokenDetail":{"allOf":[{"$ref":"#/components/schemas/TokenSummary"},{"type":"object","properties":{"description":{"type":"string"},"socials":{"type":"object","description":"Sanitized socials map (creator-controlled)","properties":{},"additionalProperties":true},"pool":{"type":"string","description":"Uniswap V3 pool address"},"tokenId":{"type":"string","description":"LP position NFT id"},"launchPriceWeth":{"type":"string"},"launchPriceWethFormatted":{"type":"string"},"athPriceWeth":{"type":"string"},"athPriceWethFormatted":{"type":"string"},"athAt":{"type":["integer","null"],"description":"Unix seconds of the ATH trade, null before any trade"},"downFromAthPct":{"type":"number"},"liquidityWeth":{"type":["string","null"],"description":"Pool WETH balance, null if the read failed"},"liquidityWethFormatted":{"type":["string","null"]},"liquidityUsd":{"type":"string","description":"Present only when an ETH/USD rate is available"},"tradeCount":{"type":"integer"},"holders":{"type":"integer"},"duplicateNameCount":{"type":"integer"},"isPotentialCopycat":{"type":"boolean","description":"True only if an OLDER same-name/symbol token exists"}}}]},"Trade":{"type":"object","properties":{"txHash":{"type":"string"},"blockNumber":{"type":"integer"},"logIndex":{"type":"integer"},"ts":{"type":"integer","description":"Unix seconds"},"side":{"type":"string","enum":["buy","sell"]},"trader":{"type":["string","null"],"description":"Wallet that traded (swap recipient); null for pre-backfill rows"},"wethIn":{"type":"string"},"wethOut":{"type":"string"},"tokenIn":{"type":"string"},"tokenOut":{"type":"string"},"priceWeth":{"type":"string"},"priceWethFormatted":{"type":"string"},"volumeWeth":{"type":"string"},"volumeWethFormatted":{"type":"string"},"sqrtPriceX96":{"type":"string"},"tick":{"type":"integer"}}},"RecentTrade":{"type":"object","description":"One entry in the board's persistent live-activity feed (newest swaps across all visible V4 tokens)","properties":{"txHash":{"type":"string"},"logIndex":{"type":"integer"},"blockNumber":{"type":"integer"},"ts":{"type":"integer","description":"Unix seconds"},"dexVersion":{"type":"integer","description":"3 (legacy V3) or 4 (V4)"},"tokenAddress":{"type":"string"},"tokenSymbol":{"type":"string"},"side":{"type":"string","enum":["buy","sell"]},"trader":{"type":["string","null"],"description":"Wallet that traded; null for pre-backfill rows"},"volumeWeth":{"type":"string","description":"ETH value of the trade, base-unit string"},"volumeWethFormatted":{"type":"string"}}},"Candle":{"type":"object","properties":{"time":{"type":"integer","description":"Bucket start, unix seconds"},"open":{"type":"number"},"high":{"type":"number"},"low":{"type":"number"},"close":{"type":"number"},"volumeWeth":{"type":"number"},"trades":{"type":"integer"}}},"Holder":{"type":"object","properties":{"address":{"type":"string"},"balance":{"type":"string","description":"Base-unit string"},"balanceFormatted":{"type":"string"}}},"Comment":{"type":"object","properties":{"id":{"type":"integer"},"author":{"type":"string","description":"Checksummed author address"},"body":{"type":"string"},"createdAt":{"type":"integer","description":"Unix seconds"}}},"WatchlistItem":{"type":"object","properties":{"address":{"type":"string"},"name":{"type":"string"},"symbol":{"type":"string"},"image":{"type":["string","null"]},"priceWeth":{"type":"string"},"priceWethFormatted":{"type":"string"},"marketCapWeth":{"type":"string"},"marketCapWethFormatted":{"type":"string"},"lastTradeAt":{"type":["integer","null"]},"createdAt":{"type":"integer"},"addedAt":{"type":"integer","description":"Unix seconds the token was watchlisted"}}}}},"paths":{"/api/health":{"get":{"tags":["system"],"summary":"Liveness + chain params","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"chainId":{"type":"integer"},"factory":{"type":["string","null"]}}}}}}}}},"/api/status":{"get":{"tags":["system"],"summary":"Indexer/chain sync status","responses":{"200":{"description":"Sync status. synced = the indexer is within the confirmation window of head.","content":{"application/json":{"schema":{"type":"object","properties":{"chainId":{"type":"integer"},"factory":{"type":["string","null"]},"indexedBlock":{"type":["integer","null"]},"headBlock":{"type":"integer"},"blocksBehind":{"type":["integer","null"]},"synced":{"type":"boolean"},"tokenCount":{"type":"integer"},"lastIndexedAt":{"type":["integer","null"],"description":"Unix seconds"}}}}}},"422":{"description":"Could not read chain head","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/stats":{"get":{"tags":["system"],"summary":"Aggregate totals","description":"Cache-Control: public, max-age=5.","responses":{"200":{"description":"Totals across all tokens","content":{"application/json":{"schema":{"type":"object","properties":{"totalTokens":{"type":"integer"},"totalVolumeWeth":{"type":"string"},"totalVolumeWethFormatted":{"type":"string"},"last24hVolumeWeth":{"type":"string"},"last24hVolumeWethFormatted":{"type":"string"}}}}}}}}},"/api/board":{"get":{"tags":["tokens"],"summary":"Discovery board (newest / volume surge / top gainers)","description":"Cache-Control: public, max-age=5.","parameters":[{"name":"limit","in":"query","required":false,"description":"Per-list limit, default 10, max 50","schema":{"type":"integer"}}],"responses":{"200":{"description":"Three ranked lists over the TokenSummary shape, plus a persistent live-activity feed (recentTrades)","content":{"application/json":{"schema":{"type":"object","properties":{"newest":{"type":"array","items":{"$ref":"#/components/schemas/TokenSummary"}},"volumeSurge":{"type":"array","items":{"$ref":"#/components/schemas/TokenSummary"}},"topGainers":{"type":"array","items":{"$ref":"#/components/schemas/TokenSummary"}},"recentTrades":{"type":"array","items":{"$ref":"#/components/schemas/RecentTrade"}}}}}}}}}},"/api/eth-price":{"get":{"tags":["system"],"summary":"Current ETH/USD","description":"Cache-Control: public, max-age=5.","responses":{"200":{"description":"From the 60s price cache; ethUsd null if never reachable this run","content":{"application/json":{"schema":{"type":"object","properties":{"ethUsd":{"type":["number","null"]},"updatedAt":{"type":["integer","null"],"description":"Unix seconds"},"source":{"type":"string","description":"Price source hostname"}}}}}}}}},"/api/gas":{"get":{"tags":["system"],"summary":"Recommended fee params for this chain","responses":{"200":{"description":"Set these so the wallet doesn't over-estimate on this Orbit chain","content":{"application/json":{"schema":{"type":"object","properties":{"gasPrice":{"type":"string"},"gasPriceGwei":{"type":"string"},"maxFeePerGas":{"type":"string"},"maxPriorityFeePerGas":{"type":"string"}}}}}},"422":{"description":"Could not read the chain gas price","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/stream":{"get":{"tags":["system"],"summary":"Server-Sent Events stream of launches + trades","description":"text/event-stream. Emits `event: launch` on every new TokenLaunched and `event: trade` on every new Swap, as `event: <name>\\ndata: <json>\\n\\n`. A `:keep-alive` comment every 20s. 503 when the global or per-IP connection cap is hit.","responses":{"200":{"description":"Event stream","content":{"text/event-stream":{"schema":{"type":"string","description":"SSE frames"}}}},"503":{"description":"Too many stream connections","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tx/{hash}":{"get":{"tags":["system"],"summary":"Transaction status + decoded summary if it touched the launchpad","parameters":[{"name":"hash","in":"path","required":true,"description":"0x-prefixed 32-byte tx hash","schema":{"type":"string"}}],"responses":{"200":{"description":"Mined receipt summary, or { status: 'pending' } if not yet mined","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["pending","success","reverted"]},"blockNumber":{"type":"integer","description":"Absent when pending"},"confirmations":{"type":"integer","description":"Absent when pending"},"from":{"type":["string","null"]},"to":{"type":["string","null"]},"gasUsed":{"type":"string","description":"Absent when pending"},"summary":{"type":"object","description":"Present only if the tx was a tracked Swap or TokenLaunched","properties":{},"additionalProperties":true}}}}}},"400":{"description":"Invalid tx hash","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Could not read the receipt / malformed receipt","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tokens":{"get":{"tags":["tokens"],"summary":"List/search tokens","description":"Returns a JSON array of TokenSummary. Cache-Control: public, max-age=5. Response headers: X-Total-Count (filtered total), X-Next-Cursor (opaque keyset cursor, only when the page was full). Both are in Access-Control-Expose-Headers.","parameters":[{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["new","volume","mcap","trending"],"default":"new"}},{"name":"limit","in":"query","required":false,"description":"Default 50, clamped [1,500]","schema":{"type":"integer"}},{"name":"offset","in":"query","required":false,"description":"Legacy offset pagination","schema":{"type":"integer"}},{"name":"cursor","in":"query","required":false,"description":"Opaque keyset cursor from a previous X-Next-Cursor","schema":{"type":"string"}},{"name":"search","in":"query","required":false,"description":"Name/symbol substring (FTS trigram >=3 chars, else LIKE)","schema":{"type":"string"}},{"name":"creator","in":"query","required":false,"description":"Filter by creator address","schema":{"type":"string"}},{"name":"maxAgeSec","in":"query","required":false,"description":"Only tokens launched within the last N seconds","schema":{"type":"integer"}},{"name":"minHolders","in":"query","required":false,"schema":{"type":"integer"}},{"name":"minLiquidityWeth","in":"query","required":false,"description":"Decimal WETH in the pool; RPC-backed, requires a narrowed set (<=200 candidates)","schema":{"type":"number"}}],"responses":{"200":{"description":"Matching tokens","headers":{"X-Total-Count":{"schema":{"type":"string"},"description":"Filtered total"},"X-Next-Cursor":{"schema":{"type":"string"},"description":"Opaque next-page cursor (only when the page was full)"},"Cache-Control":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TokenSummary"}}}}},"400":{"description":"Invalid filter value / too-broad minLiquidityWeth","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tokens/{address}":{"get":{"tags":["tokens"],"summary":"Token detail","description":"Cache-Control: public, max-age=5.","parameters":[{"name":"address","in":"path","required":true,"description":"Token contract address","schema":{"type":"string"}}],"responses":{"200":{"description":"Full token detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenDetail"}}}},"404":{"description":"Token not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tokens/{address}/trades":{"get":{"tags":["tokens"],"summary":"Recent trades (newest first)","parameters":[{"name":"address","in":"path","required":true,"description":"Token contract address","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Default 50, max 500","schema":{"type":"integer"}}],"responses":{"200":{"description":"Trades","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Trade"}}}}},"404":{"description":"Token not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tokens/{address}/candles":{"get":{"tags":["tokens"],"summary":"OHLCV candles (oldest first)","parameters":[{"name":"address","in":"path","required":true,"description":"Token contract address","schema":{"type":"string"}},{"name":"interval","in":"query","required":false,"schema":{"type":"string","enum":["1m","1h"],"default":"1m"}},{"name":"limit","in":"query","required":false,"description":"Default 500, max 2000","schema":{"type":"integer"}}],"responses":{"200":{"description":"Candles","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Candle"}}}}},"400":{"description":"Invalid interval","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Token not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tokens/{address}/holders":{"get":{"tags":["tokens"],"summary":"Top holders (infra addresses excluded)","parameters":[{"name":"address","in":"path","required":true,"description":"Token contract address","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Default 50, max 500","schema":{"type":"integer"}}],"responses":{"200":{"description":"Holders","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Holder"}}}}},"404":{"description":"Token not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tokens/{address}/similar":{"get":{"tags":["tokens"],"summary":"Copycat/impersonation check (same name or symbol)","parameters":[{"name":"address","in":"path","required":true,"description":"Token contract address","schema":{"type":"string"}}],"responses":{"200":{"description":"Other tokens sharing this name/symbol, oldest first","content":{"application/json":{"schema":{"type":"object","properties":{"address":{"type":"string"},"symbol":{"type":"string"},"name":{"type":"string"},"duplicateNameCount":{"type":"integer"},"isPotentialCopycat":{"type":"boolean"},"similar":{"type":"array","items":{"type":"object","properties":{"address":{"type":"string"},"name":{"type":"string"},"symbol":{"type":"string"},"creator":{"type":"string"},"createdAt":{"type":"integer"}}}}}}}}},"400":{"description":"Invalid token address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Token not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tokens/{address}/trust":{"get":{"tags":["tokens"],"summary":"Trust panel (holdings, concentration, anti-snipe, dev-sold, snipe proxy)","description":"Mixes db-derived metrics with best-effort live chain reads; failed reads degrade to null fields plus a note (never 500).","parameters":[{"name":"address","in":"path","required":true,"description":"Token contract address","schema":{"type":"string"}}],"responses":{"200":{"description":"Trust metrics","content":{"application/json":{"schema":{"type":"object","properties":{"address":{"type":"string"},"creator":{"type":"string"},"creatorHoldingPct":{"type":["number","null"]},"creatorHoldingPctFormatted":{"type":["string","null"]},"creatorBalanceWei":{"type":"string"},"totalSupplyWei":{"type":"string","description":"Fixed 1e27"},"indexedSupplyWei":{"type":"string"},"liquidityWeth":{"type":["string","null"]},"liquidityWethFormatted":{"type":["string","null"]},"liquidityUsd":{"type":"string","description":"Present only when an ETH/USD rate is available"},"topHolders":{"type":"array","items":{"type":"object","description":"Holder + pctOfSupply + pctOfSupplyFormatted","properties":{},"additionalProperties":true}},"top10Pct":{"type":"number"},"top10PctFormatted":{"type":["string","null"]},"sniperPct":{"type":["number","null"]},"bundlePct":{"type":["number","null"]},"sniperWallets":{"type":"integer"},"snipeFlag":{"type":"string"},"snipeNote":{"type":"string"},"devSold":{"type":"object","properties":{"sold":{"type":"boolean"},"soldAmountWei":{"type":"string"},"movedOut":{"type":"boolean"},"movedAmountWei":{"type":"string"},"note":{"type":"string"}},"additionalProperties":true},"antiSnipe":{"oneOf":[{"type":"object","properties":{"active":{"type":"boolean"},"capPct":{"type":["number","null"]},"maxWalletWei":{"type":"string"},"endBlock":{"type":"string"},"blocksLeft":{"type":"integer"},"currentL1Block":{"type":"string"}}},{"type":"null"}],"description":"Null when the live anti-snipe read failed"},"badges":{"type":"object","properties":{"lpLockedForever":{"type":"object","properties":{"value":{"type":"boolean"},"locker":{"type":["string","null"]},"tokenId":{"type":"string"},"note":{"type":"string"}}},"standardContract":{"type":"object","properties":{"value":{"type":"boolean"},"note":{"type":"string"}}},"mevProtected":{"type":"object","properties":{"value":{"type":"boolean"},"note":{"type":"string"}}}}},"notes":{"type":"array","items":{"type":"string"}}}}}}},"400":{"description":"Invalid token address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Token not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tokens/{address}/fees":{"get":{"tags":["trading"],"summary":"Claimable creator fees + claim calldata","parameters":[{"name":"address","in":"path","required":true,"description":"Token contract address","schema":{"type":"string"}}],"responses":{"200":{"description":"WETH side is claimable by the creator; token side is burned","content":{"application/json":{"schema":{"type":"object","properties":{"tokenId":{"type":"string"},"claimableWethWei":{"type":"string"},"claimableWethFormatted":{"type":"string"},"burnTokenSideWei":{"type":"string"},"feeRecipient":{"type":"string","description":"Checksummed creator address"},"claim":{"type":"object","properties":{"to":{"type":"string"},"data":{"type":"string"},"value":{"type":"string"}}}}}}}},"422":{"description":"Could not read claimable fees","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Fees endpoint not configured (locker/npm)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/quote":{"get":{"tags":["trading"],"summary":"Buy/sell quote + ready-to-send swap calldata","description":"Cache-Control: no-store. buy = WETH->token (amountIn is WETH wei), sell = token->WETH (amountIn is token wei). recipient (or from) is REQUIRED so the swap output isn't lost.","parameters":[{"name":"token","in":"query","required":true,"description":"Token contract address","schema":{"type":"string"}},{"name":"side","in":"query","required":true,"schema":{"type":"string","enum":["buy","sell"]}},{"name":"amountIn","in":"query","required":true,"description":"Positive base-unit integer","schema":{"type":"string"}},{"name":"slippageBps","in":"query","required":false,"description":"Default 300 (3%), clamped [0,5000]","schema":{"type":"integer"}},{"name":"recipient","in":"query","required":false,"description":"Swap output recipient (required unless ?from= given)","schema":{"type":"string"}},{"name":"from","in":"query","required":false,"description":"Sender; enables allowance read, simulation and per-tx gas estimate","schema":{"type":"string"}},{"name":"simulate","in":"query","required":false,"description":"Dry-run the swap via eth_call (requires ?from=)","schema":{"type":"string","enum":["true","1"]}},{"name":"approvedTx","in":"query","required":false,"description":"Confirmed approve() tx hash; allowance is read at its block","schema":{"type":"string"}}],"responses":{"200":{"description":"Quote + calldata. antiSnipe/maxWalletWarning/simulation appear conditionally.","content":{"application/json":{"schema":{"type":"object","properties":{"side":{"type":"string","enum":["buy","sell"]},"token":{"type":"string"},"pairToken":{"type":"string","description":"WETH address"},"fee":{"type":"integer","description":"Pool fee tier"},"amountIn":{"type":"string"},"amountInFormatted":{"type":"string"},"amountOut":{"type":"string"},"amountOutFormatted":{"type":"string"},"minReceived":{"type":"string","description":"Uses the REQUESTED slippageBps"},"minReceivedFormatted":{"type":"string"},"slippageBps":{"type":"integer","description":"The APPLIED slippage (what minReceived was computed from), clamped to maxSlippageBps"},"maxSlippageBps":{"type":"integer","description":"Shared ceiling (5000 = 50%); the frontend must clamp submitted slippage to this too"},"priceImpactBps":{"type":"integer"},"priceImpactPct":{"type":"number"},"poolLiquidityWeth":{"type":["string","null"]},"poolLiquidityWethFormatted":{"type":["string","null"]},"lowLiquidity":{"type":"boolean","description":"Thin pool OR high price impact"},"recommendedSlippageBps":{"type":"integer","description":"Advisory post-quote buffer only: 3% normal / 10% thin; NEVER derived from price impact"},"warning":{"type":["string","null"],"description":"Low-liquidity/high-impact warning, else null"},"antiSnipe":{"type":"object","description":"Buy-path advisory; omitted entirely if the live reads fail (fail-open)","properties":{"windowActive":{"type":"boolean"},"endBlockL1":{"type":["integer","null"],"description":"L1 block the restriction ends at"},"maxWalletWei":{"type":["string","null"]},"maxWalletFormatted":{"type":["string","null"]},"recipientExempt":{"type":"boolean"},"recipientBalanceWei":{"type":["string","null"]},"wouldExceedMaxWallet":{"type":"boolean"}}},"maxWalletWarning":{"type":"string","description":"Present only when a buy would exceed the max wallet in-window"},"gasEstimate":{"type":"string"},"fees":{"$ref":"#/components/schemas/FeesBlock"},"route":{"type":"string"},"quoteExpiresAt":{"type":"integer","description":"Unix seconds"},"tx":{"type":"object","properties":{"to":{"type":"string"},"data":{"type":"string"},"value":{"type":"string","description":"msg.value; frontend must set recipient if it was defaulted"}}},"approval":{"type":"object","properties":{"needed":{"type":"boolean"},"token":{"type":"string"},"spender":{"type":"string"},"amount":{"type":"string"}}},"simulated":{"type":"boolean","description":"Present when simulate=true"},"wouldRevert":{"type":"boolean","description":"Present when simulate=true"},"revertReason":{"type":["string","null"],"description":"Present when simulate=true"},"simError":{"type":"boolean","description":"Present when the simulation itself failed on an RPC error"}}}}}},"400":{"description":"Invalid params","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Token/pool not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"No liquidity / RPC read failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Trade endpoints not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/launch/prepare":{"get":{"tags":["trading"],"summary":"Build the createToken launch tx","description":"Cache-Control: no-store. Validates params, computes value = creationFee + initialBuyEth, returns {to,data,value} + a fee/estimate breakdown.","parameters":[{"name":"name","in":"query","required":true,"description":"1-64 chars","schema":{"type":"string"}},{"name":"symbol","in":"query","required":true,"description":"1-16 chars","schema":{"type":"string"}},{"name":"image","in":"query","required":false,"description":"ipfs:// or https:// URL, <=256 chars","schema":{"type":"string"}},{"name":"description","in":"query","required":false,"description":"<=1000 chars","schema":{"type":"string"}},{"name":"socials","in":"query","required":false,"description":"<=1000 chars","schema":{"type":"string"}},{"name":"salt","in":"query","required":false,"description":"32-byte hex, defaults to zero hash","schema":{"type":"string"}},{"name":"initialBuyEth","in":"query","required":false,"description":"Decimal ETH self-buy amount","schema":{"type":"string"}},{"name":"antiSnipeBps","in":"query","required":false,"description":"0 or [50,10000]","schema":{"type":"integer"}},{"name":"antiSnipeBlocks","in":"query","required":false,"description":"[0,100000]; a non-zero window requires a cap","schema":{"type":"integer"}},{"name":"creatorAllocBps","in":"query","required":false,"description":"[0,10000]; echoed but not encoded","schema":{"type":"integer"}},{"name":"from","in":"query","required":false,"description":"Sender; enables an exact gas estimate","schema":{"type":"string"}}],"responses":{"200":{"description":"Launch tx + breakdown","content":{"application/json":{"schema":{"type":"object","properties":{"to":{"type":"string","description":"Factory address"},"data":{"type":"string"},"value":{"type":"string"},"valueFormatted":{"type":"string"},"creationFee":{"type":"object","properties":{"wei":{"type":"string"},"formatted":{"type":"string"}}},"initialBuy":{"type":"object","properties":{"wei":{"type":"string"},"formatted":{"type":"string"}}},"initialBuyEstimate":{"type":"object","properties":{"estimate":{"type":"boolean"},"estimatedTokens":{"type":"string"},"estimatedTokensFormatted":{"type":"string"},"startPriceWeth":{"type":"string"},"startPriceWethFormatted":{"type":"string"},"initialTick":{"type":"integer"},"note":{"type":"string"}}},"fees":{"$ref":"#/components/schemas/FeesBlock"},"params":{"type":"object","properties":{"name":{"type":"string"},"symbol":{"type":"string"},"image":{"type":"string"},"description":{"type":"string"},"socials":{"type":"string"},"salt":{"type":"string"},"antiSnipeBps":{"type":"integer"},"antiSnipeBlocks":{"type":"integer"},"creatorAllocBps":{"type":"integer"}}}}}}}},"400":{"description":"Invalid params","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Launch endpoint not configured (no factory address)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/wallets/{address}":{"get":{"tags":["wallets"],"summary":"Tokens a wallet created + currently holds","parameters":[{"name":"address","in":"path","required":true,"description":"Wallet address","schema":{"type":"string"}}],"responses":{"200":{"description":"Created tokens (TokenSummary) + current holdings with WETH/USD value","content":{"application/json":{"schema":{"type":"object","properties":{"address":{"type":"string"},"created":{"type":"array","items":{"$ref":"#/components/schemas/TokenSummary"}},"holdings":{"type":"array","items":{"type":"object","properties":{"address":{"type":"string"},"name":{"type":"string"},"symbol":{"type":"string"},"image":{"type":["string","null"]},"balance":{"type":"string"},"balanceFormatted":{"type":"string"},"priceWeth":{"type":"string"},"valueWeth":{"type":"string"},"valueWethFormatted":{"type":"string"},"valueUsd":{"type":"string","description":"Present only when an ETH/USD rate is available"}}}}}}}}},"400":{"description":"Invalid wallet address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/wallets/{address}/watchlist":{"get":{"tags":["wallets"],"summary":"A wallet's watched tokens (newest-added first)","parameters":[{"name":"address","in":"path","required":true,"description":"Wallet address","schema":{"type":"string"}}],"responses":{"200":{"description":"Watchlist","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WatchlistItem"}}}}},"400":{"description":"Invalid wallet address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"tags":["wallets"],"summary":"Add a token to the wallet's watchlist","security":[{"bearerAuth":[]}],"parameters":[{"name":"address","in":"path","required":true,"description":"Wallet address (must equal the session address)","schema":{"type":"string"}},{"name":"token","in":"path","required":true,"description":"Token address","schema":{"type":"string"}}],"responses":{"200":{"description":"Added","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"wallet":{"type":"string"},"token":{"type":"string"}}}}}},"400":{"description":"Invalid wallet address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cannot modify another wallet's watchlist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Token not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["wallets"],"summary":"Remove a token from the wallet's watchlist","security":[{"bearerAuth":[]}],"parameters":[{"name":"address","in":"path","required":true,"description":"Wallet address (must equal the session address)","schema":{"type":"string"}},{"name":"token","in":"path","required":true,"description":"Token address","schema":{"type":"string"}}],"responses":{"200":{"description":"Removed","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"wallet":{"type":"string"},"token":{"type":"string"}}}}}},"400":{"description":"Invalid address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cannot modify another wallet's watchlist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tokens/{address}/comments":{"get":{"tags":["social"],"summary":"Comments for a token (newest first, hidden excluded)","parameters":[{"name":"address","in":"path","required":true,"description":"Token contract address","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Default 50, clamped [1,200]","schema":{"type":"integer"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Comments","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Comment"}}}}},"404":{"description":"Token not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["social"],"summary":"Post a comment (author = session address)","security":[{"bearerAuth":[]}],"parameters":[{"name":"address","in":"path","required":true,"description":"Token contract address","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","description":"1..commentMaxLen chars"}},"required":["body"]}}}},"responses":{"201":{"description":"Created comment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Comment"}}}},"400":{"description":"Invalid body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Token not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tokens/{address}/comments/{id}/report":{"post":{"tags":["social"],"summary":"Report a comment (increments a counter)","parameters":[{"name":"address","in":"path","required":true,"description":"Token contract address","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"description":"Comment id","schema":{"type":"string"}}],"responses":{"200":{"description":"Reported","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"400":{"description":"Invalid comment id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Token or comment not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/auth/nonce":{"post":{"tags":["auth"],"summary":"Issue a SIWE nonce + message to sign","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"address":{"type":"string","description":"Wallet address"}},"required":["address"]}}}},"responses":{"200":{"description":"Nonce + SIWE message","content":{"application/json":{"schema":{"type":"object","properties":{"nonce":{"type":"string"},"message":{"type":"string","description":"The exact message the wallet must sign"}}}}}},"400":{"description":"Invalid address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/auth/verify":{"post":{"tags":["auth"],"summary":"Verify the signed SIWE message, mint a session","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"address":{"type":"string"},"message":{"type":"string"},"signature":{"type":"string","description":"0x-prefixed hex"}},"required":["address","message","signature"]}}}},"responses":{"200":{"description":"Session token","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","description":"Bearer token"},"address":{"type":"string"},"expiresAt":{"type":"integer","description":"Unix seconds"}}}}}},"401":{"description":"Invalid credentials / nonce / signature","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/auth/logout":{"post":{"tags":["auth"],"summary":"Revoke the current session (idempotent)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Always ok","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/api/upload":{"post":{"tags":["media"],"summary":"Upload a coin image","description":"multipart/form-data field `image` (or `file`). Rate-limited; stored name is sha256(bytes).<ext> from the content-type allowlist.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"image":{"type":"string","format":"binary","description":"Image bytes (field `image` or `file`)"}}}}}},"responses":{"200":{"description":"Stored image","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"},"key":{"type":"string"},"contentType":{"type":"string"},"size":{"type":"integer","description":"Bytes"},"ipfsUri":{"type":"string","description":"Present when IPFS pinning is configured"}}}}}},"400":{"description":"Missing/unsupported/invalid image","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication required (only when upload auth is enabled)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Image exceeds MAX_UPLOAD_MB","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"507":{"description":"Upload storage full","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/openapi.json":{"get":{"tags":["docs"],"summary":"This OpenAPI document","description":"Cache-Control: public, max-age=60.","responses":{"200":{"description":"The OpenAPI 3.1 spec","content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":true}}}}}}},"/api/docs":{"get":{"tags":["docs"],"summary":"Rendered API docs","responses":{"200":{"description":"HTML docs page","content":{"text/html":{"schema":{"type":"string"}}}}}}}}}