{"openapi":"3.1.0","info":{"title":"OceanX Developer API","version":"1.0.0","description":"Public API for the OceanX trading platform. Currently in beta and free to use while in beta.\n\nThis spec covers the **spot quote** domain. The wallet **tracker** and **perps** domains are documented at https://docs.oceanx.trade/api/overview and are not yet described here.","contact":{"url":"https://docs.oceanx.trade"},"termsOfService":"https://www.oceanx.trade/legal/terms","license":{"name":"Proprietary","url":"https://www.oceanx.trade/legal/terms"}},"servers":[{"url":"https://www.oceanx.trade","description":"Production"}],"tags":[{"name":"Market Data","description":"Read-only OceanX market context sourced and cached by VM producers."},{"name":"Spot","description":"Executable Solana swap quotes off OceanX's own router, and the exit checker that reports whether a whole position can be sold."},{"name":"Callouts","description":"Public token callouts — user-posted token calls with live click/volume attribution stats. Read-only."}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"An OceanX API key, created in the app under Settings → Developer API. Send it as `Authorization: Bearer ox_live_…`. These endpoints require the `md.read` scope, which is on every key by default."}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Stable machine-readable code. Branch on this, not the message.","example":"no_route"},"message":{"type":"string","description":"Human-readable detail. May change."}}}}},"RouteLeg":{"type":"object","description":"One hop of the route the engine picked.","required":["dex","inputMint","outputMint"],"properties":{"dex":{"type":"string","example":"Raydium CLMM"},"pool":{"type":["string","null"]},"inputMint":{"type":"string"},"outputMint":{"type":"string"},"percent":{"type":["number","null"],"description":"Share of the input this leg carries, in percent."},"amountIn":{"type":["string","null"]},"amountOut":{"type":["string","null"]},"priceImpactPct":{"type":["number","null"],"description":"This leg's impact, in PERCENT."}}},"Quote":{"type":"object","required":["inputMint","outputMint","inAmount","outAmount","minOutAmount","slippageBps","impactMeasurable","clamped","route","venues","engine"],"properties":{"inputMint":{"type":"string"},"outputMint":{"type":"string"},"inAmount":{"type":"string","pattern":"^\\d+$","description":"Atomic (base-unit) amount as a decimal integer string. A string, not a number, because a large 9-decimal balance exceeds Number.MAX_SAFE_INTEGER and would be corrupted by JSON float parsing.","example":"1000000000"},"outAmount":{"type":"string","pattern":"^\\d+$","description":"Atomic (base-unit) amount as a decimal integer string. A string, not a number, because a large 9-decimal balance exceeds Number.MAX_SAFE_INTEGER and would be corrupted by JSON float parsing.","example":"1000000000"},"minOutAmount":{"type":"string","pattern":"^\\d+$","description":"Worst-case output after slippageBps, as enforced on-chain.","example":"1000000000"},"slippageBps":{"type":"integer","minimum":1,"maximum":1000},"priceImpactPct":{"type":["number","null"],"description":"Price impact in PERCENT (1.5 = 1.5%). NOTE: Jupiter's equivalent field is fractional (0.015), so code ported from Jupiter is off by 100x — in the direction that makes an untradeable position look fine.","example":1.5},"impactMeasurable":{"type":"boolean","description":"False when impact sits inside the engine's noise floor (~0.1%), where the figure is a cached mid rather than a measurement. Render '—' rather than the number."},"clamped":{"type":"boolean","description":"True when this is the router's out-of-liquidity floor price rather than an executable fill. Returned with HTTP 200. NEVER present a clamped quote as proceeds."},"contextSlot":{"type":["integer","null"]},"route":{"type":"array","items":{"$ref":"#/components/schemas/RouteLeg"}},"venues":{"type":"array","items":{"type":"string"}},"engineTimeMs":{"type":["number","null"],"description":"Router compute time in milliseconds, typically 1–2."},"swapUsdValue":{"type":["number","null"],"description":"Upstream USD notional when available; null on many pairs. Don't depend on it."},"requestId":{"type":["string","null"],"description":"Quote id. Include it if you report a bad route to us."},"engine":{"type":"string","example":"raptor"}}},"ExitRung":{"type":"object","description":"One fraction of the position, quoted independently.","required":["fraction","amount","isBaseline"],"properties":{"fraction":{"type":"number","description":"Fraction of the position this rung represents. 1 is the whole thing."},"amount":{"type":"string","pattern":"^\\d+$","description":"Atomic (base-unit) amount as a decimal integer string. A string, not a number, because a large 9-decimal balance exceeds Number.MAX_SAFE_INTEGER and would be corrupted by JSON float parsing.","example":"1000000000"},"uiAmount":{"type":["number","null"]},"quote":{"oneOf":[{"$ref":"#/components/schemas/Quote"},{"type":"null"}],"description":"Null when this rung had no route; `error` then says why."},"error":{"type":["string","null"],"description":"Set when this rung failed: no_route, dust_rung, or an engine code."},"outAmount":{"type":["string","null"]},"outUiAmount":{"type":["number","null"]},"realizedPrice":{"type":["number","null"],"description":"quoteMint units per whole input token — the realized price for selling THIS size. Requires both decimals."},"realizedImpactPct":{"type":["number","null"],"description":"OUR measurement: this rung's rate against the smallest rung's rate, in percent. May be NEGATIVE — the router re-solves per size and a different pool can win, which is a real outcome and not an error."},"upstreamImpactPct":{"type":["number","null"],"description":"The engine's own impact figure for this rung. Unusable below 0.1%."},"isBaseline":{"type":"boolean","description":"The rung every other rung is measured against. Its realizedImpactPct is 0 BY DEFINITION, not by measurement — do not read it as evidence that this size is cheap to exit."}}},"ExitSummary":{"type":"object","required":["verdict","venues","warnings"],"properties":{"verdict":{"type":"string","enum":["clean","thin","trapped","no_route"],"description":"clean = full size exits within 2% realized impact; thin = 2–10%; trapped = over 10%, hit the liquidity floor, or no route; no_route = nothing routed at any rung."},"fullExitImpactPct":{"type":["number","null"]},"fullExitPrice":{"type":["number","null"]},"fullExitOutAmount":{"type":["string","null"]},"fullExitOutUiAmount":{"type":["number","null"]},"maxCleanFraction":{"type":["number","null"],"description":"Largest QUOTED fraction that stayed inside 2%. This is ladder resolution, not a solved optimum — pass a denser ladder for a tighter answer."},"maxCleanUiAmount":{"type":["number","null"]},"venues":{"type":"array","items":{"type":"string"}},"warnings":{"type":"array","description":"Caveats to surface verbatim. Each entry is 'code: message'; split on the first colon for the stable code.","items":{"type":"string","example":"negative_marginal_proceeds: the 0.5 rung returns LESS than the 0.1 rung — selling more of this bag nets you less"}}}},"ExitCheckResult":{"type":"object","required":["mint","quoteMint","amount","slippageBps","ladder","summary","rungs"],"properties":{"mint":{"type":"string"},"quoteMint":{"type":"string"},"amount":{"type":"string","pattern":"^\\d+$","description":"Atomic (base-unit) amount as a decimal integer string. A string, not a number, because a large 9-decimal balance exceeds Number.MAX_SAFE_INTEGER and would be corrupted by JSON float parsing.","example":"1000000000"},"uiAmount":{"type":["number","null"]},"decimals":{"type":["integer","null"]},"quoteDecimals":{"type":["integer","null"]},"slippageBps":{"type":"integer"},"ladder":{"type":"array","items":{"type":"number"}},"summary":{"$ref":"#/components/schemas/ExitSummary"},"rungs":{"type":"array","items":{"$ref":"#/components/schemas/ExitRung"}},"units":{"type":"object","description":"Self-describing unit notes, safe to ignore once you've read them once.","additionalProperties":true}}},"TrackedWallet":{"type":"object","description":"One wallet in your tracker.","required":["wallet"],"properties":{"wallet":{"type":"string","description":"Base58 Solana address."},"label":{"type":["string","null"]},"emoji":{"type":["string","null"]},"groupId":{"type":["string","null"]},"addedAtMs":{"type":["integer","null"]}}},"TrackerGroup":{"type":"object","required":["id"],"properties":{"id":{"type":"string"},"name":{"type":["string","null"]},"walletCount":{"type":["integer","null"]}}},"TrackerTrade":{"type":"object","description":"A normalized trade by one of your tracked wallets.","properties":{"type":{"type":"string","example":"trade"},"wallet":{"type":"string"},"mint":{"type":"string"},"side":{"type":"string","enum":["buy","sell"]},"price_usd":{"type":["number","null"]},"volume_usd":{"type":["number","null"]},"volume_sol":{"type":["number","null"]},"ts":{"type":"integer","description":"Unix milliseconds."},"signature":{"type":"string"},"pool":{"type":["string","null"]},"dex":{"type":["string","null"]},"market_cap_usd":{"type":["number","null"]},"symbol":{"type":["string","null"]},"name":{"type":["string","null"]},"image":{"type":["string","null"]}}},"Callout":{"type":"object","description":"A public token callout: one user's shill post for one mint, with live attribution stats. Creators earn a share of platform fees on volume their callout drives.","required":["id","mint","body","status","createdAt","expiresAt","creator"],"properties":{"id":{"type":"string","description":"Short slug; the share URL is /c/{id}."},"mint":{"type":"string","description":"Base58 Solana mint the callout targets."},"body":{"type":"string"},"tokenSymbol":{"type":["string","null"]},"tokenName":{"type":["string","null"]},"tokenImageUrl":{"type":["string","null"]},"priceUsdAtCreate":{"type":["number","null"],"description":"Token price when the callout was posted — baseline for % since callout."},"status":{"type":"string","enum":["active","expired","removed"]},"clickCount":{"type":"integer"},"traderCount":{"type":"integer","description":"Distinct attributed traders."},"attributedVolumeUsd":{"type":"number"},"earnedUsd":{"type":"number"},"pointsAwarded":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"},"creator":{"type":"object","required":["id"],"properties":{"id":{"type":"string"},"username":{"type":["string","null"]},"displayName":{"type":["string","null"]},"avatarUrl":{"type":["string","null"]}}}}},"ChartBar":{"type":"object","required":["ts","o","h","l","c","v","n"],"description":"One OHLCV bucket, in the same shape our own charts render. `ts` is the bucket's OPEN time in unix MILLISECONDS — most OHLCV vendors emit seconds, so divide before comparing against another feed.","properties":{"ts":{"type":"integer","format":"int64","description":"Bucket open time, unix milliseconds.","example":1755300000000},"o":{"type":"number","description":"Open."},"h":{"type":"number","description":"High."},"l":{"type":"number","description":"Low."},"c":{"type":"number","description":"Close."},"v":{"type":"number","description":"Volume traded in the bucket, always in USD — including under `denom=sol`, which converts only the OHLC prices."},"n":{"type":"integer","description":"Trades in the bucket. Solana only: EVM history comes from vendor OHLCV that carries no trade count, and is reported as 0 rather than guessed."}}},"CalloutPage":{"type":"object","required":["callouts","nextCursor"],"properties":{"callouts":{"type":"array","items":{"$ref":"#/components/schemas/Callout"}},"nextCursor":{"type":["string","null"],"description":"Opaque cursor for the next page; null when exhausted."}}}}},"paths":{"/api/v1/tracker/wallets":{"get":{"operationId":"listTrackedWallets","tags":["Tracker"],"summary":"List tracked wallets","description":"Every wallet in your tracker. Requires the `tracker.read` scope.","security":[{"bearerAuth":[]}],"parameters":[{"name":"group","in":"query","schema":{"type":"string"},"description":"Scope to one tracker group."}],"responses":{"200":{"description":"Your tracked wallets.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."}},"content":{"application/json":{"schema":{"type":"object","required":["wallets"],"properties":{"wallets":{"type":"array","items":{"$ref":"#/components/schemas/TrackedWallet"}}}}}}},"400":{"description":"Failed validation before reaching the engine.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honour `Retry-After`.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."},"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The routing engine is unreachable or timed out. Retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"trackWallet","tags":["Tracker"],"summary":"Track a wallet","description":"Add a Solana wallet to your tracker. Idempotent — tracking an already-tracked wallet succeeds and updates its label. Requires `tracker.read`.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["wallet"],"properties":{"wallet":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"Base58 Solana wallet address."},"label":{"type":"string","description":"Your name for it."},"emoji":{"type":"string"},"group":{"type":"string","description":"Tracker group to add it to."}}},"examples":{"whale":{"summary":"Track a whale with a label","value":{"wallet":"5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1","label":"Whale #1","emoji":"🐳"}}}}}},"responses":{"200":{"description":"The wallet is now tracked.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."}},"content":{"application/json":{"schema":{"type":"object","properties":{"wallet":{"type":"string"},"tracked":{"type":"boolean"},"groupId":{"type":["string","null"]}}}}}},"400":{"description":"Failed validation before reaching the engine.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honour `Retry-After`.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."},"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The routing engine is unreachable or timed out. Retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/tracker/wallets/{wallet}":{"delete":{"operationId":"untrackWallet","tags":["Tracker"],"summary":"Untrack a wallet","description":"Remove a wallet from your tracker. Idempotent — untracking a wallet you were not tracking still returns 200. Requires `tracker.read`.","security":[{"bearerAuth":[]}],"parameters":[{"name":"wallet","in":"path","required":true,"schema":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"Base58 Solana mint address."},"description":"The wallet to stop tracking."}],"responses":{"200":{"description":"No longer tracked.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."}},"content":{"application/json":{"schema":{"type":"object","properties":{"wallet":{"type":"string"},"tracked":{"type":"boolean","enum":[false]}}}}}},"400":{"description":"Failed validation before reaching the engine.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honour `Retry-After`.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."},"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The routing engine is unreachable or timed out. Retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/tracker/snapshot":{"get":{"operationId":"getTrackerSnapshot","tags":["Tracker"],"summary":"Tracker snapshot","description":"Your whole tracker in one call: groups, wallets and status. Cheaper than listing wallets and groups separately. Requires `tracker.read`.","security":[{"bearerAuth":[]}],"parameters":[{"name":"group","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Groups, wallets and status.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."}},"content":{"application/json":{"schema":{"type":"object","required":["groups","wallets"],"properties":{"groups":{"type":"array","items":{"$ref":"#/components/schemas/TrackerGroup"}},"wallets":{"type":"array","items":{"$ref":"#/components/schemas/TrackedWallet"}},"status":{"type":"object","properties":{"globalWalletCount":{"type":"integer"}}}}}}}},"400":{"description":"Failed validation before reaching the engine.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honour `Retry-After`.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."},"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The routing engine is unreachable or timed out. Retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/tracker/trades":{"get":{"operationId":"listTrackerTrades","tags":["Tracker"],"summary":"Recent trades","description":"Recent normalized trades across your tracked wallets, newest first.\n\nServed from a rolling cache of roughly the 250 most recent events per wallet, so this is a recent window rather than full history. For continuous coverage use the realtime feed. Requires `tracker.read`.","security":[{"bearerAuth":[]}],"parameters":[{"name":"wallet","in":"query","schema":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"Base58 Solana mint address."},"description":"Filter to one tracked wallet."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":500,"default":100}},{"name":"group","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Recent trades, newest first.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."}},"content":{"application/json":{"schema":{"type":"object","required":["trades","count"],"properties":{"count":{"type":"integer"},"trades":{"type":"array","items":{"$ref":"#/components/schemas/TrackerTrade"}}}}}}},"400":{"description":"Failed validation before reaching the engine.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honour `Retry-After`.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."},"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The routing engine is unreachable or timed out. Retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/tracker/realtime/session":{"get":{"operationId":"createTrackerRealtimeSession","tags":["Tracker"],"summary":"Realtime session","description":"Mint a short-lived WebSocket URL for live trade, balance and PnL frames across your tracked wallets.\n\nThe returned `wsUrl` embeds a ticket valid for about 60 seconds — fetch a fresh session before each connect rather than caching the URL. With no tracked wallets you get a 200 with an empty `wsUrl` and a note, not an error. Requires `tracker.read`.","security":[{"bearerAuth":[]}],"parameters":[{"name":"group","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"A ticketed WebSocket URL.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."}},"content":{"application/json":{"schema":{"type":"object","required":["wsUrl","wallets","expiresInSeconds"],"properties":{"wsUrl":{"type":"string","description":"Connect within `expiresInSeconds`. Empty when nothing is tracked."},"wallets":{"type":"array","items":{"type":"string"}},"expiresInSeconds":{"type":"integer","example":60},"note":{"type":"string"}}}}}},"400":{"description":"Failed validation before reaching the engine.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honour `Retry-After`.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."},"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The routing engine is unreachable or timed out. Retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/market/chart/{token}":{"get":{"operationId":"getTokenChart","tags":["Market Data"],"summary":"Token OHLCV chart","description":"OHLCV bars for a token — the same series the OceanX charts draw, from the same sources. Solana mints are served from OceanX's own indexed trades (one volume-ranked pool per bucket); EVM tokens are served from vendor OHLCV with our indexed trades merged on top.\n\nWith no `from`/`to` you get the most recent `limit` buckets. Responses are cached briefly per token+resolution, so a poll loop faster than the bucket width returns the same bars without costing you anything.\n\nRequires the `md.read` scope, which is on every key by default.","security":[{"bearerAuth":[]}],"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string"},"description":"Base58 Solana mint, or a 0x EVM token address when `chain` names an EVM chain.","example":"So11111111111111111111111111111111111111112"},{"name":"chain","in":"query","schema":{"type":"string","enum":["solana","ethereum","base","bnb","arbitrum","polygon","monad","hyperevm","robinhood"],"default":"solana"},"description":"Which chain the token lives on."},{"name":"resolution","in":"query","schema":{"type":"string","enum":["1s","5s","15s","30s","1m","5m","15m","30m","1h","2h","4h","6h","8h","12h","1d","1w","1mn"],"default":"1m"},"description":"Bucket width. Sub-minute resolutions are Solana-only in practice — no EVM data vendor publishes them, so an EVM request is served at the nearest FINER supported bucket and `resolutionSeconds` tells you which."},{"name":"from","in":"query","schema":{"type":"integer","format":"int64"},"description":"Window start, unix SECONDS (the bars themselves are milliseconds). Defaults to `to - limit × resolution`."},{"name":"to","in":"query","schema":{"type":"integer","format":"int64"},"description":"Window end, unix SECONDS. Defaults to now."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":1000,"default":500},"description":"Maximum bars to return, counted from the end of the window."},{"name":"mode","in":"query","schema":{"type":"string","enum":["price","mc"],"default":"price"},"description":"`price` returns USD prices; `mc` returns market cap on the same axis (price × circulating supply). A token with no known supply figure — wrapped SOL, for instance — returns prices under either value."},{"name":"denom","in":"query","schema":{"type":"string","enum":["usd","sol"],"default":"usd"},"description":"Denomination of the OHLC prices. `sol` divides each bar by the SOL price of its own bucket, and is Solana-only — asking for it on an EVM chain is a 400. Volume (`v`) stays in USD either way."},{"name":"pool","in":"query","schema":{"type":"string"},"description":"Restrict bars to one pool address. Solana only. Omit to let the server pick the volume-ranked pool per bucket, which is what the OceanX chart does."}],"responses":{"200":{"description":"Bars, oldest first.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."}},"content":{"application/json":{"schema":{"type":"object","required":["token","chain","resolution","resolutionSeconds","from","to","bars"],"properties":{"token":{"type":"string"},"chain":{"type":"string","example":"solana"},"resolution":{"type":"string","example":"1m"},"resolutionSeconds":{"type":"integer","description":"Bucket width actually served. Equals `requestedResolutionSeconds` on Solana; larger on an EVM chain whose vendor cannot serve the requested width."},"requestedResolutionSeconds":{"type":"integer"},"mode":{"type":"string","enum":["price","mc"]},"denom":{"type":"string","enum":["usd","sol"]},"pool":{"type":["string","null"]},"from":{"type":"integer","format":"int64","description":"Window start, unix seconds."},"to":{"type":"integer","format":"int64","description":"Window end, unix seconds."},"bars":{"type":"array","items":{"$ref":"#/components/schemas/ChartBar"}}}}}}},"400":{"description":"Failed validation before reaching the engine.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honour `Retry-After`.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."},"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The routing engine is unreachable or timed out. Retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"504":{"description":"The upstream aggregation did not finish in time. Narrow the window (fewer bars, or a coarser resolution) and retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/market/lighthouse":{"get":{"operationId":"getMarketLighthouse","tags":["Market Data"],"summary":"Solana Lighthouse","description":"Latest VM-cached Solana market, DEX and launchpad activity frame. Includes 5m, 1h, 6h and 24h transactions, unique wallets, buy/sell volume, token creation and migrations with change percentages. The response is read-only and does not spend one SolanaTracker request per caller.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Latest complete Lighthouse frame.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."}},"content":{"application/json":{"schema":{"type":"object","required":["source","generatedAtMs","markets"],"properties":{"source":{"type":"string","example":"solanatracker:lighthouse"},"generatedAtMs":{"type":"integer","format":"int64"},"markets":{"type":"array","items":{"type":"object","required":["market","label","stats"],"properties":{"market":{"type":"string","example":"pumpfun"},"label":{"type":"string","example":"Pump.fun"},"icon":{"type":"string"},"url":{"type":"string"},"parent":{"type":["string","null"]},"stats":{"type":"object","additionalProperties":true}}}}}}}}},"400":{"description":"Failed validation before reaching the engine.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honour `Retry-After`.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."},"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The routing engine is unreachable or timed out. Retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/spot/quote":{"get":{"operationId":"getSpotQuote","tags":["Spot"],"summary":"Spot quote","description":"One normalized quote for one size, off OceanX's own router. Costs 1 against the 300/min quote budget.\n\nRead `priceImpactPct` as a PERCENT, check `impactMeasurable` before showing it, and check `clamped` before treating `outAmount` as proceeds.","security":[{"bearerAuth":[]}],"parameters":[{"name":"inputMint","in":"query","required":true,"schema":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"Base58 Solana mint address."}},{"name":"outputMint","in":"query","required":true,"schema":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"Base58 Solana mint address."}},{"name":"amount","in":"query","schema":{"type":"string","pattern":"^\\d+$","description":"Atomic (base-unit) amount as a decimal integer string. A string, not a number, because a large 9-decimal balance exceeds Number.MAX_SAFE_INTEGER and would be corrupted by JSON float parsing.","example":"1000000000"},"description":"Required unless you pass `uiAmount` + `inputDecimals`."},{"name":"uiAmount","in":"query","schema":{"type":"number","exclusiveMinimum":0},"description":"Human units. Requires `inputDecimals`."},{"name":"inputDecimals","in":"query","schema":{"type":"integer","minimum":0,"maximum":18}},{"name":"outputDecimals","in":"query","schema":{"type":"integer","minimum":0,"maximum":18},"description":"Adds `outUiAmount` and `minOutUiAmount` to the response."},{"name":"slippageBps","in":"query","schema":{"type":"integer","minimum":1,"maximum":1000,"default":50}},{"name":"dexes","in":"query","schema":{"type":"string"},"description":"Comma-separated venue labels to restrict routing to."},{"name":"pools","in":"query","schema":{"type":"string"},"description":"Comma-separated pool addresses to restrict routing to."},{"name":"maxHops","in":"query","schema":{"type":"integer","minimum":1,"maximum":4}},{"name":"onlyDirectRoutes","in":"query","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"A quote.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Quote"}}}},"400":{"description":"Failed validation before reaching the engine.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No route exists for this pair and size. A routing outcome, not an outage.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honour `Retry-After`.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."},"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The routing engine is unreachable or timed out. Retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/spot/exit-check":{"post":{"operationId":"postSpotExitCheck","tags":["Spot"],"summary":"Exit check","description":"Quotes several fractions of a position and reports the realized rate at each size.\n\nThe headline price of a token tells you what the FIRST token sells for; this tells you what the LAST one does. Read `rungs[].realizedImpactPct` top to bottom, and treat `summary.maxCleanFraction` as the actionable number.\n\nCosts ONE PER LADDER RUNG against the 300/min quote budget.\n\nA thin book that stops routing at size is data, not an error: you get a 200 with a `no_route` verdict. A non-2xx means the ladder could not be produced at all.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["mint"],"properties":{"mint":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"The token you are exiting."},"quoteMint":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"What you are exiting into. Must differ from `mint`.","default":"So11111111111111111111111111111111111111112"},"amount":{"type":"string","pattern":"^\\d+$","description":"Bag size. Required unless you pass `uiAmount` + `decimals`.","example":"1000000000"},"uiAmount":{"type":"number","exclusiveMinimum":0},"decimals":{"type":"integer","minimum":0,"maximum":18},"quoteDecimals":{"type":"integer","minimum":0,"maximum":18},"slippageBps":{"type":"integer","minimum":1,"maximum":1000,"default":50},"ladder":{"type":"array","items":{"type":"number","exclusiveMinimum":0,"maximum":1},"minItems":1,"maxItems":8,"default":[0.1,0.25,0.5,1],"description":"Fractions of the position to quote. Impact is measured against the SMALLEST rung, so pass a small first rung — [0.01, 0.1, 0.25, 0.5, 1] gives a much tighter baseline than the default, and the response warns you via `coarse_baseline` when yours is too coarse."}}},"examples":{"tightBaseline":{"summary":"A memecoin position, quoted into USDC with a 1% baseline","value":{"mint":"DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263","uiAmount":500000000,"decimals":5,"quoteMint":"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v","quoteDecimals":6,"ladder":[0.01,0.1,0.25,0.5,1]}}}}}},"responses":{"200":{"description":"The ladder, including any rungs that had no route.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExitCheckResult"}}}},"400":{"description":"Failed validation before reaching the engine.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honour `Retry-After`.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."},"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The routing engine is unreachable or timed out. Retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/spot/quote/stream":{"get":{"operationId":"getSpotQuoteStream","tags":["Spot"],"summary":"Quote stream","description":"Re-quotes one pair on an interval and streams each result as Server-Sent Events. Costs ONE PER TICK against the 300/min quote budget.\n\nSERVER-SIDE ONLY: authentication is the `Authorization` header, and the browser EventSource API cannot set headers — which is correct, because your key is a secret. Consume this from your backend and relay it over your own transport.\n\nEvents: `open` (echoed config) → `quote` → `close`. Also `error` (the stream CONTINUES) and `throttled` (budget spent; ticks resume when the window rolls). `: hb` comment lines every 20s keep intermediaries from idling the connection out.","security":[{"bearerAuth":[]}],"parameters":[{"name":"inputMint","in":"query","required":true,"schema":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"Base58 Solana mint address."}},{"name":"outputMint","in":"query","required":true,"schema":{"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$","description":"Base58 Solana mint address."}},{"name":"amount","in":"query","schema":{"type":"string","pattern":"^\\d+$","description":"Atomic (base-unit) amount as a decimal integer string. A string, not a number, because a large 9-decimal balance exceeds Number.MAX_SAFE_INTEGER and would be corrupted by JSON float parsing.","example":"1000000000"}},{"name":"uiAmount","in":"query","schema":{"type":"number","exclusiveMinimum":0}},{"name":"inputDecimals","in":"query","schema":{"type":"integer","minimum":0,"maximum":18}},{"name":"slippageBps","in":"query","schema":{"type":"integer","minimum":1,"maximum":1000,"default":50}},{"name":"intervalMs","in":"query","schema":{"type":"integer","minimum":250,"maximum":60000,"default":1000},"description":"Re-quote cadence."},{"name":"maxSeconds","in":"query","schema":{"type":"integer","minimum":1,"maximum":240,"default":240},"description":"Connection lifespan. We always close with a `close` event."},{"name":"onlyChanges","in":"query","schema":{"type":"boolean","default":false},"description":"Emit only when the proceeds or the chosen route actually move."}],"responses":{"200":{"description":"An SSE stream.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."}},"content":{"text/event-stream":{"schema":{"type":"string","description":"SSE frames; see the description."}}}},"400":{"description":"Failed validation before reaching the engine.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honour `Retry-After`.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."},"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The routing engine is unreachable or timed out. Retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/callouts/feed":{"get":{"operationId":"listCalloutFeed","tags":["Callouts"],"summary":"Global callout feed","description":"Live token callouts across the platform, newest first (or by attributed volume with `sort=top`). Requires `md.read`.","security":[{"bearerAuth":[]}],"parameters":[{"name":"sort","in":"query","schema":{"type":"string","enum":["recent","top"],"default":"recent"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Opaque cursor from the previous page's `nextCursor`."}],"responses":{"200":{"description":"A page of callouts.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalloutPage"}}}},"400":{"description":"Failed validation before reaching the engine.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honour `Retry-After`.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."},"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The routing engine is unreachable or timed out. Retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/callouts/token/{mint}":{"get":{"operationId":"listTokenCallouts","tags":["Callouts"],"summary":"Callouts for one token","description":"Active callouts targeting one mint, highest attributed volume first (or newest with `sort=recent`). Requires `md.read`.","security":[{"bearerAuth":[]}],"parameters":[{"name":"mint","in":"path","required":true,"schema":{"type":"string"},"description":"Base58 Solana mint address."},{"name":"sort","in":"query","schema":{"type":"string","enum":["top","recent"],"default":"top"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"A page of callouts for the mint.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalloutPage"}}}},"400":{"description":"Failed validation before reaching the engine.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honour `Retry-After`.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."},"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The routing engine is unreachable or timed out. Retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}