Market state API
Public read endpoints for Candle’s view of a market: its lifecycle, a curve quote, launch verification, the trade page’s feed buckets, and agent records. None requires authentication. They are convenience reads: the on-chain registry and contract state remain authoritative for market identity, as described in Terminals and indexers.
Market state
Section titled “Market state”GET /api/v1/markets/:chain/:mintchain is solana or hood. The response is one chain-agnostic shape regardless of whether the mint is a Solana bonding curve or a Hood CandleCurve, cached about 5 seconds server-side:
{ "success": true, "market": { "chain": "solana", "mint": "...", "lifecycle": "trading", "buysOpen": true, "sellsOpen": true, "curveAddress": "...", "poolAddress": null, "quoteMint": "...", "feeBps": 100, "graduationVenue": "meteora-damm-v2", "tier": "open", "crossingModel": "full-fill-surplus", "candleLaunched": true, "launchpad": "candle", "venue": "candle-curve", "trade": { "endpoint": "POST /api/v1/trade/agent/quote", "routable": true }, "decimals": 6, "quoteDecimals": 9, "metadata": { "...": "..." }, "migration": { "status": "not_started", "reserveRaw": "...", "thresholdRaw": "...", "progressBps": 4120 } }}| Field | Notes |
|---|---|
lifecycle | trading, completed, migrated, or recovery. |
buysOpen, sellsOpen | Whether each side is currently executable. The two are independent; see the table below. |
curveAddress | The bonding curve (Solana pool or Hood CandleCurve) address. |
poolAddress | The post-migration venue pool on Solana (Meteora DAMM v2); null before migration and always null on Hood, where v3 and v4 pool discovery is on-chain. See Hood market integration. |
quoteMint | The quote asset’s mint or token address. |
feeBps | The venue’s own trading fee in basis points, for where the token trades now. On the curve it is the curve’s fee as read on chain (100 by default). After graduation it is the Meteora DAMM v2 pool’s base fee: 50, or 150 or 250 for an experimental fast curve launched with an extra creator fee of 1% or 2%. 0 is a placeholder, not free trading: it is reported for a legacy Meteora launch (whose pool fee Candle does not set), a completed token with no pool yet, and external tokens. It does not include Candle’s own platform fee. |
graduationVenue | meteora-damm-v2 on Solana; uniswap-v3 or uniswap-v4 on Hood. |
tier | open or exclusive, when known. |
crossingModel | full-fill-surplus on Solana, capped-refund on Hood. |
candleLaunched, launchpad | Whether Candle launched this mint, and the launchpad that did (candle for a Candle curve). |
venue | Where a trade routes now: candle-curve, jupiter, dex, hood-dex, or null while none is available. |
trade | { endpoint, routable, reason? }. Stored eligibility for the agent quote endpoint, never a quote or an authorization check. reason says why a market is not routable (for example solana_graduating). |
decimals, quoteDecimals | The token’s decimals and its quote asset’s decimals, for converting amounts to raw base units. |
metadata | The token’s name, symbol, image and socials as Candle holds them, or null. |
migration | Graduation progress. See below. |
Migration status
Section titled “Migration status”"migration": { "status": "in_progress", "attempts": 3, "nextAttemptAt": 1754400120000 }status | Meaning |
|---|---|
not_started | The curve is still trading. |
in_progress | The curve is done and the graduated venue is being seeded. |
completed | Trading has moved to the graduated venue. Carries migratedAt. |
delayed | Automated seeding exhausted its retries and a human has been alerted. |
cancelled | Hood Recovery: no pool will open. Holders redeem from the curve. Overrides migration retries. |
migratedAt is stamped when a token first completes migration, so markets that graduated before this release report completed without one. On Hood the block also carries the keeper’s attempts, nextAttemptAt, and gaveUpAt where they apply. While a Solana curve is still trading, the block carries live graduation progress read from the pool: reserveRaw (quote raised so far), thresholdRaw (the graduation threshold), both in the quote asset’s raw units, and progressBps (capped at 10000). Watch these rather than the curve address’s balance: the quote sits as wrapped SOL in the pool’s vault.
The target is that a completed curve is live on its graduated venue within 10 minutes: the graduation keepers sweep every 2 minutes and retry with backoff. delayed is the machine-readable form of “this one needs a human”, not a normal step in the sequence.
Buys and sells
Section titled “Buys and sells”buysOpen and sellsOpen are separate flags. On Solana they can differ; on Hood a graduated curve closes both sides until the pool is seeded (CandleCurve reverts PoolMigrated for any trade outside Trading):
lifecycle | Solana | Hood |
|---|---|---|
trading | Buys and sells open | Buys and sells open |
completed | Both closed during migration | Both closed until the Uniswap pool is seeded (migration.status completed) |
migrated | Both open on the graduated venue | Both open on the graduated venue |
recovery | n/a | Both closed; recovery is a claim flow, not a trade |
External markets (no Candle tokens row)
Section titled “External markets (no Candle tokens row)”When the mint is in Candle’s feed index or Jupiter can name it, the same endpoint returns HTTP 200
with external: true plus discovery flags (jupiterOk, externalTradeable, paperDiscoveryOk,
organic0LiveOk). That shape means Jupiter-routable (Solana) or Hood DEX reachable, not a
Candle-launched curve, but tradeable on the agent rail when tier allows.
MARKET_NOT_FOUND (404) carries error.routing.reason (chain_mismatch, token_unknown, and others) and
error.discovery. On chain_mismatch the mint is indexed on the other chain: discovery.indexed is
true and discovery.chain names the chain to retry with. On token_unknown nobody knows the mint
(discovery.indexed: false).
Errors use the structured envelope described in the Headless launch API: an invalid chain is VALIDATION_FAILED (400), an unknown market is MARKET_NOT_FOUND (404), and a dependency failure is QUOTE_UNAVAILABLE (503, retryable).
GET /api/v1/markets/:chain/:mint/quote?side=buy|sell&amountIn=<base units>&slippageBps=50Prices one trade through the exact same integer math the curve runs on-chain, so terminals do not have to re-implement crossing edge cases. Public, rate-limited to 120 requests per minute per client, cached about 5 seconds.
{ "success": true, "chain": "hood", "mint": "0x...", "side": "buy", "amountIn": "5000000000000000000", "crossingModel": "capped-refund", "quote": { "amountOut": "...", "fee": "...", "minAmountOut": "...", "crossesGraduation": true, "refund": "...", "quoteConsumed": "..." }}Every amount is a decimal string in the smallest unit of the quote asset (buys) or the base token (sells).
crossesGraduation applies to buys only, and what it implies differs by chain, which is why crossingModel travels with it. On Hood a crossing buy is capped at the threshold and the remainder refunded, so refund and quoteConsumed tell you how much was actually spent. On Solana a crossing buy fills in full and the surplus stays in the pool, so the refund fields never appear.
minAmountOut applies your slippageBps to the capped fill rather than the uncapped one, so a quote is always satisfiable on-chain, even across graduation.
A curve that cannot execute the requested side returns MARKET_NOT_TRADABLE (409), and the message names where trading continues: the Uniswap pool, the Jupiter or Meteora route, or “buys and sells closed while graduating”.
This quote covers Candle curves only. A mint that is not a Candle market returns MARKET_NOT_FOUND (404) with a message pointing to POST /api/v1/trade/agent/quote, which quotes external tokens. Other errors: RATE_LIMITED (429), QUOTE_PAIR_UNKNOWN for an unrecognized quote asset, and QUOTE_UNAVAILABLE (503, retryable) when a dependency fails.
Verify
Section titled “Verify”GET /api/v1/verify/:chain/:mintThe authoritative answer to “is this mint a genuine Candle launch”, so users and terminals can reject look-alike mints. Public, cached about 60 seconds.
{ "success": true, "candleLaunched": true, "chain": "hood", "mint": "0x...", "tier": "open", "quoteMint": "0x...", "graduated": false, "pool": null, "createdAt": 1754400000000, "creator": "0x...", "viaAgentKey": true, "provenance": { "curve": "0x...", "factory": "0x...", "configHash": "0x...", "dexVersion": "v4" }}An unknown mint, or one launched with non-production visibility, returns 200 with { "candleLaunched": false } rather than a 404, so a caller branches on one response shape either way.
Hood responses carry the provenance block above, re-verifiable against the registry. Solana responses instead carry attribution (the bonding-curve program and the attribution signer), so an indexer can re-derive the same conclusion on-chain using the procedure in Solana market identification.
viaAgentKey is true when the launch came through an agent API key, which is the same signal behind the agent badge in the Candle UI.
GET /api/v1/markets/feed?bucket=new|graduated|onfire|finalstretch&chain=solana|hoodA thin public read onto the same feed buckets the trade page tabs use, optionally filtered to one chain. It is served live from the feed engine (no cache); while the engine starts it answers 503 FEED_UNAVAILABLE with Retry-After. bucket is required; chain is optional.
The feed also takes where, sort, fields, limit, since_seq and discovery=paper, and the response carries matched, scanned, cursor, warming, organicScoreGuidance, and on a since_seq read reset and removed. bucket=finalstretch (pump.fun tokens at 50% or more of their bonding curve) has no delta: it always answers the whole list with reset: true, and adds asOf, stale, feed and exact. bucket=bluechip is deprecated and will be removed. See Reading the feed for the query syntax.
{ "success": true, "bucket": "new", "tokens": [ { "chain": "solana", "address": "...", "name": "Trend Coin", "symbol": "TREND", "image": "https://...", "isAgent": true } ]}Each row carries chain, address, name, symbol, image, price, volume, and market-cap statistics, and isAgent, which is true for a Candle-origin launch created through an agent API key. An unknown bucket or chain is VALIDATION_FAILED (400).
Agent profile
Section titled “Agent profile”GET /api/v1/users/:idOrWallet/agentA public read for any account: whether it has agent features enabled, its address and username, and its launch counts, total versus those attributed to an agent key.
{ "success": true, "agent": { "enabled": true, "address": "...", "username": "trendbot", "launches": 12, "launchesViaApi": 9, "tier": "pro" }}tier is the account’s plan today: max, pro, believer or free.
Unlike the market endpoints, this route’s errors are plain: { "error": "User not found" } with status 404.
Hood mark
Section titled “Hood mark”GET /api/v1/markets/hood/:mint/markA Hood token’s mark: the market provider’s indexed price (priceUsd), plus sellUsd and buyUsd adjusted for the deepest pool’s fees (feeBps, lpFeeBps, hookFeeBps), the pool, and asOf. It is a price for carrying positions, not a quote for a trade. Public, limited to 600 requests per minute per client, cached 10 seconds per mint. A token with no usable price is MARKET_NOT_FOUND (404); a provider failure is QUOTE_UNAVAILABLE (503, retryable).
Copy score
Section titled “Copy score”GET /api/v1/markets/agents/:profileId/copy-scoreWhether a published agent’s edge is one a follower could capture, computed from that agent’s own fills. The response carries score with profileId, name, wallet, the assessment, and the inputs it used (a null input was not measured). An agent whose record is not published answers 404 MARKET_NOT_FOUND, the same as an unknown one. Public, 60 requests per minute per client, cached 60 seconds.
Cohorts
Section titled “Cohorts”GET /api/v1/markets/cohorts/:cohort?limit=10Agents worth watching, curated from published records and ordered by how followable they are. cohort is steady, high_conviction or early_finder; limit is 1 to 50 (default 10). The response carries cohort, members (each with profileId, name and address), and truncated. Only agents whose owner published their record are eligible. Public, 60 requests per minute per client, cached 2 minutes.
Hood Recovery
Section titled “Hood Recovery”A market recorded in Recovery reports lifecycle: "recovery", both trade flags false,
trade.reason: "market_recovery", and migration.status: "cancelled" even if seeding
previously exhausted retries. Its recovery block includes curve, quoteToken,
reserveSnapshotRaw, eligibleSupplyRaw, surrenderedRaw,
method: "claimRecovery(uint256)", and requiresApprovalTo (the curve address).
All amounts are raw integer strings, read together at one chain block. The zero quote-token
address means native ETH; otherwise the payout is that ERC-20 quote asset.
For a raw token amount, payout is amount * reserveSnapshotRaw / eligibleSupplyRaw,
rounded down in quote base units. Approve that amount to the curve on the launched token,
then call claimRecovery(amount) on the curve from the same holder wallet. The claim burns
the surrendered tokens. Claim order does not change the fixed rate; outstanding claims do
not expire. The trade and quote errors use the existing reason market_recovery and
retryable: false. No pool will open, and retrying a trade cannot help.