{
  "openapi": "3.1.0",
  "info": {
    "title": "Stryke API",
    "version": "v2",
    "description": "Market intelligence and execution across 74 chains with live market data — plus holder and security analysis on 29, and non-custodial quotes on 59."
  },
  "servers": [
    {
      "url": "https://api.stryke.gg"
    }
  ],
  "components": {
    "securitySchemes": {
      "ApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "v2 market-data API (/api/v2/*). Send your key in the X-API-Key header."
      },
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "v1 trading & account API (/v1/*). Send your key as Authorization: Bearer <key>."
      }
    }
  },
  "tags": [
    {
      "name": "Tokens",
      "description": "Token data endpoints under /api/v2/tokens. Read-through layer over the market-data layer (market details, price history, recent trades, wallet labels), the metadata service (token metadata, largest accounts), the DEX index (pairs, search, boosts/trending, embeddable charts), and Stryke's on-chain indexer, fronted by an in-process memo cache (Stryke's engine). Also exposes two heavy on-chain analysis engines: Deep Scan (Stryke's engine — a 0-100 higher=safer rug/safety verdict folding ~16 own on-chain layers plus multiple external safety providers) and the Bubble Map entity graph (Stryke's engine — weighted union-find holder/funder graph). All endpoints require the X-API-Key header (validateApiKey) and count against the per-key rate limit (apiLimiter); only the sibling /api/v2/health route is unauthenticated. Mints are validated against base58 regex ^[1-9A-HJ-NP-Za-km-z]{32,44}$. Every successful response is JSON with a top-level success:true; handler errors return success:false with an error string (most upstream failures surface as HTTP 502)."
    },
    {
      "name": "Wallets",
      "description": "Wallet data endpoints — the core of the v2 API for portfolio dashboards, tax tools, and wallet explorers. Mounted at /api/v2/wallets (router built in the API layer, mounted via app.use('/api/v2',...) in the API layer). All endpoints require a valid X-API-Key header (validateApiKey middleware) and count against a per-key rate limit (apiLimiter); only the sibling /api/v2/health route is unauthenticated. Telemetry middleware (Stryke's engine) logs every request — including failed-auth attempts — before auth runs. Address params are validated against a base58 regex /^[1-9A-HJ-NP-Za-km-z]{32,44}$/; invalid addresses return 400 {success:false,error:'invalid wallet'}. Provider-not-configured states return 503. Upstream provider failures are caught and returned as 502 {success:false,error:<msg>}. Data sources: the market-data layer (portfolio, history, trades, activity) and Stryke's node layer (enhanced/parsed transactions, DAS metadata, RPC). The heavy /profile, /wrapped, and /roast endpoints share a 5-minute server-side cache keyed by depth+wallet(+since), set public Cache-Control with stale-while-revalidate, and build on profile.the assembler (≤5 Stryke's node layer enhanced-tx pages + 1 the market-data layer portfolio on a cold cache)."
    },
    {
      "name": "Market & Charts",
      "description": "Macro Solana market data plus every price-history and candle (OHLCV) endpoint. Aggregate 24h DEX activity across Solana (lighthouse), the canonical SOL/USD spot price and its history, and OHLCV / chart data at the token, pool, and market level. Lighter than the per-token intel endpoints — fewer upstream round-trips, longer cache TTLs. Every route is a read-only GET under /api/v2, requires an X-API-Key header, counts against your per-key rate limit, and is served from an in-process TTL+LRU cache with in-flight de-duplication (lighthouse ~5 min, sol-price ~30 s)."
    },
    {
      "name": "Whales",
      "description": "Smart-money / \"whale\" intelligence endpoints under /api/v2/whales. Two operations: (1) bulk-classify a list of wallets into smart-money label tags and known-entity metadata (the market-data layer-derived), and (2) discover whale wallets among a token's on-chain top holders by resolving the top-20 token accounts to owner wallets (the node RPC) and enriching them with the market-data layer labels. No curated/featured list is served — callers supply their own wallet seed lists. Both endpoints require an X-API-Key header (validateApiKey) and count against the shared v2 per-key rate limit (10 requests / 10 seconds, keyed on the X-API-Key header). The /discover/:mint result is memoized in-process for 5 minutes per mint. Both depend on upstream providers (the market-data layer for labels, Stryke's node layer for on-chain data); when a provider key is unconfigured the handler returns 503, and upstream/provider failures surface as 502."
    },
    {
      "name": "Trading",
      "description": "Swap, limit-order, and DCA endpoints backed by Jupiter's lite-api (lite-api.jup.ag). Two API routers — `swap` (mounted at /api/v2/swap) for quote + build, and `orders` (mounted at /api/v2/orders) for limit orders and dollar-cost-average (DCA) positions. Every endpoint returns UNSIGNED base64 transactions where applicable; the caller signs locally with the user's wallet and broadcasts themselves — the API never sees or holds private keys. All responses are wrapped in `{ success: true,... }` on success (the Jupiter upstream payload is spread in, or nested under `quote` for the quote endpoint). Validation failures return HTTP 400 `{ success:false, error }`; any Jupiter upstream non-2xx or timeout is surfaced as HTTP 502 `{ success:false, error }`. All endpoints require the `X-API-Key` header (validateApiKey) and count against the per-key rate limit (apiLimiter: 10 requests / 10s window, keyed by API key). Address fields are validated against a base58 Solana address regex (32-44 chars). Note: the response field names below are Jupiter lite-api passthrough shapes (swap/v1, limit/v2, dca/v1) — they are not remapped by this service."
    },
    {
      "name": "Launches",
      "description": "Recent Solana token launches, proxied through Stryke's on-chain indexer (HTTP GET /v1/indexer/recent-pools on Stryke-trading-api, real-time gRPC-fed). The router exposes a single read endpoint that returns the most recently indexed liquidity pools / launches, optionally filtered by DEX. Results are sorted indexed_at DESC and briefly memoized (5s) per DEX bucket. Mounted at /api/v2/launches."
    },
    {
      "name": "RPC",
      "description": "Generic, read-only Solana JSON-RPC passthrough to Stryke's node layer mainnet, exposed under /api/v2/rpc. It replaces Stryke's previously client-exposed /api/node-rpc proxy: the same allow-list of safe, read-only RPC methods (no transaction submission, signing, or subscriptions), with per-API-key cost attribution of the upstream Stryke's node layer spend via trackedFetch. Accepts a single JSON-RPC call or a batch (max 25), forwards the body verbatim to https://mainnet.node-rpc.com, and pipes back Stryke's node layer's raw status, content-type, and body unchanged. There is exactly one route in the API layer (POST /). The unauthenticated GET /health lives in the API layer, not in this group."
    },
    {
      "name": "Streaming",
      "description": "Realtime WebSocket gateway at wss://api.stryke.gg/api/v2/stream (Stryke's engine), attached to the same HTTP server as the REST API. PAID-TIER-ONLY (the stream gatekeeper in the API layer): a paid Trading-API key (rt_ on tier builder/scale/enterprise) or an operator-granted Data-API key is required; the free/self-registered tier and the public builder key are DENIED at the WS upgrade with 401. One shared reference-counted poller/feed per distinct topic fans live data to every subscriber, so backend load scales with distinct topics, not client count. Two channels: launches (new pools, optional dex filter — free) and token+mint (live per-mint trade tape — counts against the plan topic cap). Per-tier caps: builder 2 conns/2 topics, scale 20/15, enterprise 50/50, internal/data-grant 20/30 (all env-tunable). Global backstops: 500 concurrent connections, 300 distinct topics, 2048-byte messages, 30s heartbeat. All frames are JSON text: welcome / snapshot / update / pong / unsubscribed / error."
    },
    {
      "name": "Account & Keys",
      "description": "Issue and manage API keys via a Solana wallet: register, regenerate, the SIWS sign-in challenge/login, and the developer dashboard (usage, fee-wallet, allowed domains, white-label license)."
    },
    {
      "name": "Recovery (v1)",
      "description": "The v1 token-account recovery API: scan a wallet for closeable/rent-bearing SPL accounts, build a close transaction, confirm it, plus wallet analysis, token info, and aggregate stats."
    },
    {
      "name": "Direct RPC",
      "description": "Solana RPC passthrough: send a signed transaction, check its status, and simulate before sending."
    },
    {
      "name": "System",
      "description": "Service health and status. Unauthenticated — use it for uptime monitoring."
    },
    {
      "name": "Trading API: Trade & Execution",
      "description": "Auth: send your key as `Authorization: Bearer <key>` (the trading API uses Bearer, NOT the X-API-Key header used by the data API). Build, sign, and broadcast swaps across all supported DEXes plus the on-chain refund/recovery flow. trade scope; per-tenant; supports an idempotency key."
    },
    {
      "name": "Trading API: Wallets",
      "description": "Auth: send your key as `Authorization: Bearer <key>` (the trading API uses Bearer, NOT the X-API-Key header used by the data API). Custodial trading wallets — create, import, list, rename, switch, withdraw, and migrate. wallet scope; per-tenant."
    },
    {
      "name": "Trading API: Keys & Sessions",
      "description": "Auth: send your key as `Authorization: Bearer <key>` (the trading API uses Bearer, NOT the X-API-Key header used by the data API). Self-serve API key issuance and wallet sessions. Public surface: a Solana wallet signature is the auth (no bearer key required)."
    },
    {
      "name": "Trading API: Billing & Tiers",
      "description": "Auth: send your key as `Authorization: Bearer <key>` (the trading API uses Bearer, NOT the X-API-Key header used by the data API). Paid tiers with live SOL quotes, on-chain SOL payment redemption (anti-replay), and stake checks."
    },
    {
      "name": "Trading API: Token Verification",
      "description": "Auth: send your key as `Authorization: Bearer <key>` (the trading API uses Bearer, NOT the X-API-Key header used by the data API). The paid 'Verified by Stryke' token badge — status reads (public) and badge purchase."
    },
    {
      "name": "Trading API: Quests",
      "description": "Auth: send your key as `Authorization: Bearer <key>` (the trading API uses Bearer, NOT the X-API-Key header used by the data API). Multi-tenant quest / engagement campaigns, tasks, verification, status, and leaderboards. quests scope."
    },
    {
      "name": "Trading API: Account & Profile",
      "description": "Auth: send your key as `Authorization: Bearer <key>` (the trading API uses Bearer, NOT the X-API-Key header used by the data API). User settings, rewards/XP, invite codes, and support tickets. read scope; per-tenant."
    },
    {
      "name": "Trading API: Fees, PnL & Positions",
      "description": "Auth: send your key as `Authorization: Bearer <key>` (the trading API uses Bearer, NOT the X-API-Key header used by the data API). Fee accounting, live and historical PnL, and position/trade history. read scope; per-tenant."
    },
    {
      "name": "Trading API: Indexer",
      "description": "Auth: send your key as `Authorization: Bearer <key>` (the trading API uses Bearer, NOT the X-API-Key header used by the data API). Read-only on-chain token + pool index — metadata, pool params, recent tokens/pools, search, and per-DEX stats."
    },
    {
      "name": "Trading API: Limit Orders & DCA",
      "description": "Auth: send your key as `Authorization: Bearer <key>` (the trading API uses Bearer, NOT the X-API-Key header used by the data API). Automated limit orders and dollar-cost-averaging schedules. automation scope; per-tenant; supports an idempotency key."
    },
    {
      "name": "Trading API: Copy Trade",
      "description": "Auth: send your key as `Authorization: Bearer <key>` (the trading API uses Bearer, NOT the X-API-Key header used by the data API). Copy-trading configs, sources, filters, blacklists, and execution stats. automation scope; per-tenant."
    },
    {
      "name": "Trading API: AFK Auto-Buy",
      "description": "Auth: send your key as `Authorization: Bearer <key>` (the trading API uses Bearer, NOT the X-API-Key header used by the data API). Hands-off auto-buy configs with mint/deployer whitelists, blacklists, sell stages, and smart-wallet rules. automation scope."
    },
    {
      "name": "Trading API: Sniper & Auto-Sell",
      "description": "Auth: send your key as `Authorization: Bearer <key>` (the trading API uses Bearer, NOT the X-API-Key header used by the data API). New-launch sniping plus automated take-profit / stop-loss auto-sell. automation scope; per-tenant."
    },
    {
      "name": "Trading API: System",
      "description": "Auth: send your key as `Authorization: Bearer <key>` (the trading API uses Bearer, NOT the X-API-Key header used by the data API). Service health and a per-key usage / quota snapshot."
    },
    {
      "name": "Programs",
      "description": "On-chain program (smart-contract) intel — account, upgrade state, activity, type mix."
    },
    {
      "name": "Positions",
      "description": "DeFi position aggregation across Kamino, Drift, MarginFi, Jupiter Perps."
    },
    {
      "name": "Webhooks",
      "description": "Push delivery the other way round: instead of holding a connection open, you give us an https endpoint and we POST to it when a trade happens. Same tape as the streaming and REST trade endpoints, read through the same function with the same cursor, so all three agree. THE GUARANTEE IS AT-LEAST-ONCE AND UNORDERED, said plainly because it is what you have to build against: every event carries a stable `eventId` that does not change across retries, so dedupe on it, and every event carries its block and log index, so order on those. Every delivery is signed — X-Stryke-Signature is HMAC-SHA256 over `${t}.${rawBody}` under a secret shown exactly once, at creation. The timestamp is inside the signature, so a captured request cannot be replayed; reject anything more than 300 seconds old. Sign the RAW bytes: re-encoding the parsed JSON changes key order and makes valid signatures fail intermittently. Failed deliveries retry at 10s, 1m, 5m, 30m, 2h and 6h and then dead-letter, and 20 consecutive failures switch the subscription off rather than letting a queue grow behind a dead endpoint — GET /{id}/deliveries shows every attempt and why it failed. Targets must be public https: private, loopback, link-local and cloud-metadata addresses are refused at creation and re-checked before every attempt, and redirects are never followed. A new subscription starts from the moment you created it measured in BLOCK time, so the first event arrives once the index has followed past that instant — up to about 90 seconds on Ethereum, because the follower writes in bursts. That opening silence is expected, not a failure. POST /{id}/test queues a synthetic event through the real path, so you can prove your signature verification works immediately, without waiting for a real trade. Like streaming, this is produced from Stryke's own index, so it covers the chains the index follows — GET /api/v2/stream/chains lists them."
    },
    {
      "name": "Streaming (SSE)",
      "description": "Push delivery over Server-Sent Events, fed by Stryke's OWN index rather than by a reseller. That is the whole design: the tape and the candles are already ours, written continuously by the followers, so there is no per-token subscription ceiling and — because the events are stored — a reconnect REPLAYS what was missed instead of jumping to now. Send Last-Event-ID (a browser EventSource does this by itself) or ?cursor= to resume; a cursor older than the resume window answers with a `truncated` event naming the gap rather than silently skipping it. The cost of reading our own tables is that streaming only covers the chains the index follows: GET /api/v2/stream/chains says which, whether each is serving, and how far behind it is. Everywhere else answers 501 with the reason. The candle channel builds the OPEN bar on demand through the same function the roll-up uses, so a forming bar is live rather than waiting for the next roll-up pass."
    },
    {
      "name": "Chain-generic market data",
      "description": "One set of 26 endpoints that works on every chain in the catalog, under /api/v2/chain/{chain}/*. The chain is a required path segment and is never defaulted — pass the Stryke key (eth), an alias (ethereum), an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses. Which endpoints answer on a given chain depends on that chain's measured capabilities: GET /api/v2/chains/{chain} lists them, and an endpoint a chain cannot serve answers 501 with the evidence — never a 200 with empty data. Every 200 carries the same envelope, including a `freshness` block with the upstream data's own age, so a chain whose indexer has fallen behind is visible rather than silently served as current. The existing Solana endpoints under /api/v2/tokens/* and /api/v2/wallets/* are unchanged."
    },
    {
      "name": "Chains (catalog)",
      "description": "The public chain catalog. 118 chains are recognised (106 EVM, 12 non-EVM); 74 carry live market data, 29 add holder and security analysis, and 59 can be quoted (measured 2026-10-04T04:17:00Z). Tiers are MEASURED every six hours, never declared: L0 recognised — the chain is in the catalog seed: identifiers, native asset and explorer are known; L1 priced — a fresh USD price for a known token on this chain — the newest trade observed is under 24 h old; L2 market — a live tape: the newest trade is under 1 h old, and the chain reports 24 h trade activity or a pool that traded within the hour; L3 forensics — tier 2, and a holder-distribution and token-security analysis completed for the probe token; L4 tradeable — tier 1 or better, and a non-custodial swap route can be quoted — through the aggregator layer or a first-party trade service configured for this chain; L5 services — a first-party trade service is configured for this chain and a paid product on it is live. These endpoints need no API key — they are what an integrator reads before deciding whether to integrate."
    },
    {
      "name": "Screener (pairs)",
      "description": "Every DEX pair the index follows, ranked. Price, 5m/1h/6h/24h change, volume, transactions, liquidity, FDV and age — plus the pair's own candles and tape. Served from Stryke's first-party index; no third-party price feed is involved. Ranked lists require a pool whose depth was actually measured, because volume from an unmeasured pool is not trustworthy — see minLiquidityUsd and the volumeTrusted flag on every row."
    },
    {
      "name": "Wallets (first-party)",
      "description": "What an address has actually traded, read from Stryke’s own tape. Positions, current value and average-cost PnL across Ethereum, Base and Solana. Read-only: nothing here holds a key, signs, or moves a balance. Every figure is window-scoped — the raw tape retains 14 days — and each row says whether its position is complete within the window and what share of its trades were priced."
    },
    {
      "name": "Tokens (first-party)",
      "description": "One token across every market it trades in — identity, the price its deepest market sets, cross-pool totals and the market list. Read from Stryke’s own index on Ethereum, Base and Solana; no third-party price feed is involved. The quoted price comes from the deepest pool whose depth was actually MEASURED, and is null when there is none — a price from an unmeasured pool is the exact failure the liquidity floor exists to stop. Read-only: nothing here holds a key, signs, or moves a balance."
    }
  ],
  "paths": {
    "/api/v2/tokens/metadata": {
      "post": {
        "summary": "Batch token metadata",
        "description": "Returns enriched metadata (name/symbol/image/decimals/supply/ownership) for up to 100 SPL mints in one call. Lookup chain: in-process cache -> local the on-chain indexer -> the metadata service for indexer misses.",
        "tags": [
          "Tokens"
        ],
        "operationId": "post-api-v2-tokens-metadata",
        "parameters": [],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "mints": {
                    "type": "string",
                    "description": "Array of SPL mint addresses (base58). Invalid mints are filtered out and the list is capped to the first 100 valid mints. If zero valid mints, 400 'mints[] required (max 100 valid SPL mints)'."
                  }
                },
                "required": [
                  "mints"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v2/tokens/prices": {
      "post": {
        "summary": "Batch token prices",
        "description": "Current price + core market stats for up to 50 mints in a single call. Each mint is fetched (and cached) independently, so a partial set still returns. Cached 30s per mint.",
        "tags": [
          "Tokens"
        ],
        "operationId": "post-api-v2-tokens-prices",
        "parameters": [],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "mints": {
                    "type": "string",
                    "description": "Array of SPL mint addresses (base58). Invalid mints are filtered out and the list is capped to the first 50 valid mints. 400 'mints[] required (max 50 valid SPL mints)' if zero valid mints."
                  }
                },
                "required": [
                  "mints"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v2/tokens/trending": {
      "get": {
        "summary": "Trending tokens feed",
        "description": "Accurate, self-policing multi-window trending from the official the DEX index REST API (boosts/profiles seed + live pair enrichment). Boost-rank primary, h24-volume tiebreak. The FULL ranked set is memoized 60s under a param-independent key; dex/minLiquidityUsd/limit are applied per-request. Carries a freshness stamp.",
        "tags": [
          "Tokens"
        ],
        "operationId": "get-api-v2-tokens-trending",
        "parameters": [],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/tokens/{mint}/intel": {
      "get": {
        "summary": "Token intel (safety verdict + holders + risk)",
        "description": "Combines market details (holders, supply, top10/insider %), the DEX index, and Stryke-resolved top-10 owners with entity labels into a heuristic 0+ risk score and verdict. Cached 60s.",
        "tags": [
          "Tokens"
        ],
        "operationId": "get-api-v2-tokens-mint-intel",
        "parameters": [
          {
            "name": "mint",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "SPL token mint address (base58). 400 'invalid mint' if it fails the base58 regex."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/tokens/{mint}/ath": {
      "get": {
        "summary": "All-time high / low",
        "description": "All-time-high and all-time-low USD price for a token, with the current price's signed % distance from each. Reads the market-data layer's native athUSD/atlUSD/athDate fields; if the market-data layer lacks them, derives ATH/ATL from the full price-history series. Cached 120s.",
        "tags": [
          "Tokens"
        ],
        "operationId": "get-api-v2-tokens-mint-ath",
        "parameters": [
          {
            "name": "mint",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "SPL token mint address (base58). 400 'invalid mint' if it fails ^[1-9A-HJ-NP-Za-km-z]{32,44}$."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/tokens/{mint}/trades": {
      "get": {
        "summary": "Recent trades (live tape)",
        "description": "Recent swaps on a mint's primary pair from the market-data layer, normalised into a compact trade-tape shape. Cached 30s per (mint,limit).",
        "tags": [
          "Tokens"
        ],
        "operationId": "get-api-v2-tokens-mint-trades",
        "parameters": [
          {
            "name": "mint",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "SPL token mint address (base58). 400 'invalid mint' if invalid."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Number of trades. Number(limit)||20, clamped to [1,100]."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/tokens/{mint}/deepscan": {
      "get": {
        "summary": "Deep Scan (token safety / rug verdict)",
        "description": "Runs the full Stryke Deep Scan engine: ~16 own on-chain layers (contract/holders/liquidity/bundle/creator/market/launch/holderstats/cohorts/lplock/honeypot/swapstats/devforensics/sniperforensics/programs/bubblemap) cross-validated by an external safety provider (always) plus an external safety provider/an external market provider/the holder-graph provider/an external market provider (when keyed), folded into one 0-100 higher=safer score, grade, verdict and flagged risks. Cached 120s.",
        "tags": [
          "Tokens"
        ],
        "operationId": "get-api-v2-tokens-mint-deepscan",
        "parameters": [
          {
            "name": "mint",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "SPL token mint address (base58). 400 'invalid mint' if invalid. Canonicalized (trimmed) internally."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/tokens/{mint}/bubblemap": {
      "get": {
        "summary": "Bubble Map entity graph",
        "description": "Returns the unified holder/funder entity graph (weighted union-find entity resolution) — nodes, links (typed + weighted with evidence), clusters, plus decentralization/concentration summary. Replaces the holder-graph provider + InsightX Atlas + an external safety provider insider graph. Cached 120s.",
        "tags": [
          "Tokens"
        ],
        "operationId": "get-api-v2-tokens-mint-bubblemap",
        "parameters": [
          {
            "name": "mint",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "SPL token mint address (base58). 400 'invalid mint' if invalid. Canonicalized internally."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/tokens/{mint}/safety": {
      "get": {
        "summary": "Safety chip (canonical, list-cheap)",
        "description": "Compact per-token safety summary (0-100 HIGHER=SAFER) cheap enough to fan out across a whole list (Radar/Oracle/cards). Derives from a warm deepscan (status complete) else a cheap intel chip (status partial); never runs a fresh full deepscan. Cached 60s. A batch form GET /api/v2/tokens/safety?mints=a,b,c (<=30) returns {success,results:{<mint>:chip}}.",
        "tags": [
          "Tokens"
        ],
        "operationId": "get-api-v2-tokens-mint-safety",
        "parameters": [
          {
            "name": "mint",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "SPL mint (base58). 400 'invalid mint' if invalid."
          },
          {
            "name": "flags",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Max topGreen and topRed each (clamped 1-5)."
          },
          {
            "name": "refresh",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Bust ONLY the 60s safety memo (never triggers a full deepscan)."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/tokens/search": {
      "get": {
        "summary": "Token search (superset)",
        "description": "Autocomplete token search by name/symbol/address. SUPERSET of the old search entry — each result now carries full card data: image/header/description, decimals, socials_list, websites_list, multi-window priceChange/volume/txns, buy/sell counts, marketCap/fdv/liquidityUsd, pairAddress/dexId, boosts, age, base/quote tokens and DEX labels. Replaces any prior /tokens/search entry.",
        "tags": [
          "Tokens"
        ],
        "operationId": "tokens-search",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Search query (name, symbol, or mint). Minimum 2 chars; shorter returns an empty results array."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/tokens/trending/raw": {
      "get": {
        "summary": "Trending tokens (raw, tagged)",
        "description": "Merged, deduped and enriched trending feed built from the DEX index boosts/top + boosts/latest + profiles/latest, resolved to full pairs. Each token carries source tags, dex_rank, raw (un-neutralized) image, rich price/volume/txn windows and boost amount — so a consumer can build gainers/losers/new/trending/promoted lists itself.",
        "tags": [
          "Tokens"
        ],
        "operationId": "tokens-trending-raw",
        "parameters": [],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/tokens/pairs-batch": {
      "post": {
        "summary": "Pairs batch (full the DEX index)",
        "description": "Returns the full, glitch-sanitized primary the DEX index pair object for up to 50 mints in one call — every price/volume/txn window plus liquidity, marketCap/fdv and info{imageUrl,header,description,socials,websites}. For consumers that build their own cards. Per-mint 30s cache.",
        "tags": [
          "Tokens"
        ],
        "operationId": "tokens-pairs-batch",
        "parameters": [],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "mints": {
                    "type": "string",
                    "description": "Array of SPL mint addresses. Invalid entries are dropped; capped at the first 50 valid mints."
                  }
                },
                "required": [
                  "mints"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v2/tokens/{mint}/metadata-full": {
      "get": {
        "summary": "Token metadata (enriched)",
        "description": "Off-chain enriched metadata for a Solana token: categories/tags, VC investors, supply allocation %, global rank, and a richer socials block. Curated off-chain (the market-data layer Metacore) — best for established tokens; sparse for fresh mints.",
        "tags": [
          "Tokens"
        ],
        "operationId": "get-api-v2-tokens-mint-metadata-full",
        "parameters": [
          {
            "name": "mint",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Solana token mint (base58). Validated; invalid returns 400."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/tokens/screener": {
      "get": {
        "summary": "Token screener / search",
        "description": "Search Solana tokens sortable by trendingScore24h, volume24h, liquidity, holdersCount, createdAt, or organicVolume1h (bot-filtered volume). A screener view over the token universe.",
        "tags": [
          "Tokens"
        ],
        "operationId": "get-api-v2-tokens-screener",
        "parameters": [
          {
            "name": "input",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Search term (symbol / name fragment)."
          },
          {
            "name": "sortBy",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Sort field: trendingScore24h, volume24h, liquidity, holdersCount, createdAt, organicVolume1h."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Results to return. Max 20."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/tokens/{mint}/dev-history": {
      "get": {
        "summary": "Dev / deployer history",
        "description": "The creator/deployer wallet behind a mint plus its track record: prior launches, rug-rate, serial-/fast-rugger verdicts, dev-sold class, and funding-origin forensics (terminal funder / CEX, privacy-peel hops, operator ring). Thin wrapper over the dev-forensics engine that is also folded into /deepscan; self-resolves the deployer, so it is standalone-safe. Route memoized 2 min.",
        "tags": [
          "Tokens"
        ],
        "operationId": "get-api-v2-tokens-mint-dev-history",
        "parameters": [
          {
            "name": "mint",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "SPL mint (base58). 400 \"invalid mint\" if invalid."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/tokens/{mint}/snipers": {
      "get": {
        "summary": "Launch sniper cohort",
        "description": "The launch-sniper cohort for a mint: how many wallets sniped the launch, what share of supply they took, slot-0 vs cohort counts, their exit distribution (still holding / sold partial / sold full / bought more), bundle concentration, and a sampled per-sniper farming profile (serial-sniper / heavy-farmer flags). Combines the launch-tape analysis with sniper forensics (which reads the same tape). Route memoized 2 min.",
        "tags": [
          "Tokens"
        ],
        "operationId": "get-api-v2-tokens-mint-snipers",
        "parameters": [
          {
            "name": "mint",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "SPL mint (base58). 400 \"invalid mint\" if invalid."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/tokens/safety": {
      "get": {
        "summary": "Safety chips (batch)",
        "description": "Batch form of the per-token safety chip (0-100 HIGHER=SAFER): fan a comma-separated mint list (max 30) into one call and get a map of chips keyed by mint. Each chip derives from a warm deepscan (status complete) else a cheap intel chip (status partial); it NEVER runs a fresh full deepscan. Per-mint degrade — a failing mint returns a pending/error chip instead of failing the batch. Sibling of GET /api/v2/tokens/{mint}/safety (single).",
        "tags": [
          "Tokens"
        ],
        "operationId": "get-api-v2-tokens-safety-batch",
        "parameters": [
          {
            "name": "mints",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated SPL mints (base58). Invalid mints are dropped; the list is capped to the first 30 valid mints. 400 \"mints required …\" if none are valid."
          },
          {
            "name": "flags",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Max topGreen and topRed each per chip (clamped 1-5)."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/wallets/{wallet}/portfolio": {
      "get": {
        "summary": "Wallet portfolio (token holdings)",
        "description": "Returns the wallet's live token holdings with USD values, prices, 24h change and allocation. Primary source is the market-data layer's portfolio endpoint; falls back to the metadata service getAssetsByOwner (including native SOL) when the market-data layer isn't configured.",
        "tags": [
          "Wallets"
        ],
        "operationId": "get-api-v2-wallets-wallet-portfolio",
        "parameters": [
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Solana wallet address (base58, 32-44 chars). Validated by SOL_ADDR_RE; invalid returns 400."
          },
          {
            "name": "fresh",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Pass fresh=true to bypass the 30s server-side cache and force a live provider fetch. Any other value (or absent) serves from cache (cache.memo key 'port:<wallet>', 30000ms TTL)."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/wallets/{wallet}/nfts": {
      "get": {
        "summary": "Wallet NFTs",
        "description": "Non-fungible holdings for a wallet — standard, compressed, and MPL-Core assets — resolved via the metadata/asset index. Fungible token balances are filtered out (use /portfolio for those). Paginated. Cached 60s.",
        "tags": [
          "Wallets"
        ],
        "operationId": "get-api-v2-wallets-wallet-nfts",
        "parameters": [
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Owner wallet address (base58). 400 'invalid wallet address' if invalid."
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "DAS page number (1-based)."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Assets per page. Clamped to 1–100."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/wallets/{wallet}/history": {
      "get": {
        "summary": "Portfolio balance history",
        "description": "Returns a time series of the wallet's total balance (USD value) over time from the market-data layer's wallet/history endpoint, normalized to {t,v} points.",
        "tags": [
          "Wallets"
        ],
        "operationId": "get-api-v2-wallets-wallet-history",
        "parameters": [
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Solana wallet address (base58). Validated; invalid returns 400."
          },
          {
            "name": "period",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "One of 1h, 1d, 7d, 30d, 90d, 365d. Any other value falls back to 30d."
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Start timestamp; passed through to the market-data layer as 'from'. Parsed via Number()."
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "End timestamp; passed through to the market-data layer as 'to'. Parsed via Number()."
          },
          {
            "name": "asset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Restrict the history to a single asset/token; passed through to the market-data layer as 'asset'."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/wallets/{wallet}/trades": {
      "get": {
        "summary": "Wallet trades (swap history)",
        "description": "Returns the wallet's the market-data layer-derived swap/trade history, passed through largely verbatim from the market-data layer's wallet/trades endpoint.",
        "tags": [
          "Wallets"
        ],
        "operationId": "get-api-v2-wallets-wallet-trades",
        "parameters": [
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Solana wallet address (base58). Validated; invalid returns 400."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Number of trades. Clamped to 1..500 via Math.max(1, Math.min(500, Number(limit) || 100))."
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Start timestamp; passed to the market-data layer as 'from'."
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "End timestamp; passed to the market-data layer as 'to'."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/wallets/{wallet}/activity": {
      "get": {
        "summary": "Wallet activity feed",
        "description": "Returns recent on-chain wallet events (swaps, transfers, liquidations, etc.) from the market-data layer's v2 wallet/activity endpoint with spam filtering and unlisted assets enabled.",
        "tags": [
          "Wallets"
        ],
        "operationId": "get-api-v2-wallets-wallet-activity",
        "parameters": [
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Solana wallet address (base58). Validated; invalid returns 400."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Number of activity items. Clamped to 1..200 via Math.max(1, Math.min(200, Number(limit) || 50))."
          },
          {
            "name": "order",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Sort order. 'asc' or 'desc' — anything other than 'asc' becomes 'desc'."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/wallets/{wallet}/transactions": {
      "get": {
        "summary": "Decoded transactions (Stryke's node layer enhanced)",
        "description": "Returns parsed, human-readable transactions for the wallet via Stryke's node layer's Enhanced Transactions REST API — each with a type, source, description, tokenTransfers and nativeTransfers. Supports keyset pagination and type/source filters.",
        "tags": [
          "Wallets"
        ],
        "operationId": "get-api-v2-wallets-wallet-transactions",
        "parameters": [
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Solana wallet address (base58). Validated; invalid returns 400."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Number of transactions. Clamped to 1..100 via Math.max(1, Math.min(100, Number(limit) || 50))."
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Paginate: return txs before this signature. Only applied if it matches the signature regex /^[a-zA-Z0-9]{43,128}$/."
          },
          {
            "name": "until",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Paginate: return txs until this signature. Only applied if it passes signature validation."
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by Stryke's node layer transaction type (e.g. SWAP, TRANSFER, NFT_SALE). Truncated to 40 chars and passed to Stryke's node layer."
          },
          {
            "name": "source",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by Stryke's node layer source (e.g. JUPITER, RAYDIUM, MAGIC_EDEN). Truncated to 40 chars and passed to Stryke's node layer."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/wallets/{wallet}/funding": {
      "get": {
        "summary": "Funding source (genesis)",
        "description": "Traces a wallet's first-ever transaction to surface who funded it and with how much SOL. Uses an archival genesis-forward (oldest-first) lookup when available, else falls back to the oldest signature in the recent window. Genesis is immutable, so the result is cached 1h.",
        "tags": [
          "Wallets"
        ],
        "operationId": "get-api-v2-wallets-wallet-funding",
        "parameters": [
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Wallet address to trace (base58). 400 'invalid wallet address' if invalid."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/wallets/decode-tx": {
      "post": {
        "summary": "Bulk decode transactions",
        "description": "Bulk-decodes arbitrary transaction signatures into Stryke's node layer's parsed/enhanced format. Send a signatures array; up to 100 valid signatures are decoded via Stryke's node layer's /v0/transactions parser.",
        "tags": [
          "Wallets"
        ],
        "operationId": "post-api-v2-wallets-decode-tx",
        "parameters": [],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "signatures": {
                    "type": "string",
                    "description": "Array of base58 transaction signatures. Filtered by the signature regex /^[a-zA-Z0-9]{43,128}$/ and capped at the first 100 valid entries. If zero valid signatures remain, returns 400 'signatures[] required (max 100 valid sigs)'."
                  }
                },
                "required": [
                  "signatures"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v2/wallets/{wallet}/profile": {
      "get": {
        "summary": "Deep wallet profile",
        "description": "The heavy aggregation endpoint. Walks up to 5 Stryke's node layer enhanced-tx pages plus 1 the market-data layer portfolio and computes a structured WalletProfile: identity/classification, biography, activity rhythm, per-token cohorts with rough realised PnL, behavioral fingerprint (sniper/paperhand/diamond/gambler/night-owl/discipline), velocity, sizing, risk, DEX breakdown, counterparty graph, holdings, trader tags and dozens of derived sections.",
        "tags": [
          "Wallets"
        ],
        "operationId": "get-api-v2-wallets-wallet-profile",
        "parameters": [
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Solana wallet address (base58). Validated; invalid returns 400."
          },
          {
            "name": "depth",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "'fast' walks 2 Stryke's node layer pages (~200 txs); anything else (default) is 'deep' = 5 pages (~500 txs)."
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter txs to timestamp >= since. Snapped to the nearest day (floor(since/86400)*86400) so cache keys converge. Used by /wrapped to scope to a one-year window. Non-finite or <=0 is ignored (null)."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/wallets/{wallet}/wrapped": {
      "get": {
        "summary": "Wallet wrapped (year-in-review)",
        "description": "The interpretive 'wrapped' layer built on top of profile.the assembler. Maps the deep profile onto a WrappedStats object, a WalletDiagnostics object, and a wallet classification — the gentle year-in-review (no roast verdict). Reuses the same profile cache so a /profile -> /wrapped burst hits cache.",
        "tags": [
          "Wallets"
        ],
        "operationId": "get-api-v2-wallets-wallet-wrapped",
        "parameters": [
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Solana wallet address (base58). Validated; invalid returns 400."
          },
          {
            "name": "depth",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "'fast' (2 Stryke's node layer pages) or 'deep' (5 pages, default). Same semantics as /profile."
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "One-year-window scoping. Snapped to nearest day (floor(since/86400)*86400). Non-finite/<=0 ignored. Used to build both the profile and wrapped cache keys."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/wallets/{wallet}/roast": {
      "get": {
        "summary": "Wallet roast (wrapped + verdict)",
        "description": "Everything /wrapped returns PLUS a roast verdict object (headline, burns, receipts, actions, lScore, tweetText) — the full output Stryke's /roast page assembles. Same cache/cost profile as /wrapped.",
        "tags": [
          "Wallets"
        ],
        "operationId": "get-api-v2-wallets-wallet-roast",
        "parameters": [
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Solana wallet address (base58). Validated; invalid returns 400."
          },
          {
            "name": "depth",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "'fast' (2 Stryke's node layer pages) or 'deep' (5 pages, default)."
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "One-year-window scoping. Snapped to nearest day. Non-finite/<=0 ignored. Builds both profile and roast cache keys."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/wallets/{wallet}/transfers": {
      "get": {
        "summary": "Wallet transfers / fund-flow",
        "description": "Raw token + native-SOL transfer edges decoded from Stryke's node layer enhanced transactions, for fund-flow tracing. Filterable by mint, counterparty, and direction. With ?synthetic=1, instead returns SYNTHESIZED swap trade rows (sanitized) in the same shape /:wallet/trades emits — for wallets a market provider misses.",
        "tags": [
          "Wallets"
        ],
        "operationId": "wallets-transfers",
        "parameters": [
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Solana wallet address (base58)."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Number of enhanced txs to scan (1-100, default 100)."
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Signature to paginate before (older txs)."
          },
          {
            "name": "mint",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only return transfer edges for this mint (transfer mode only)."
          },
          {
            "name": "counterparty",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only edges where this address is the sender or receiver (transfer mode only)."
          },
          {
            "name": "direction",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter edges by direction: 'in' or 'out' (transfer mode only)."
          },
          {
            "name": "synthetic",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Set to '1' or 'true' to return synthesized swap trade rows instead of raw transfer edges."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/wallets/{wallet}/stake": {
      "get": {
        "summary": "Wallet native stake accounts",
        "description": "Native (SOL) stake accounts where the wallet is the withdrawer authority, read via Stake program getProgramAccounts (memcmp at offset 44). Returns per-account lamports/SOL, delegation state, vote account, active stake and rent-exempt flag, plus a total.",
        "tags": [
          "Wallets"
        ],
        "operationId": "wallets-stake",
        "parameters": [
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Solana wallet address (withdrawer authority)."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/wallets/{wallet}/tx-stats": {
      "get": {
        "summary": "Wallet transaction stats",
        "description": "True lifetime-ish transaction and FAILED-tx counts from raw getSignaturesForAddress (the enhanced-tx feed omits failed txs and undercounts). Bounded pagination with a `capped` flag, plus age and failure-rate derived fields.",
        "tags": [
          "Wallets"
        ],
        "operationId": "wallets-tx-stats",
        "parameters": [
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Solana wallet address (base58)."
          },
          {
            "name": "pages",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Max signature pages to scan, 1000 sigs each (1-50, default 10 = up to 10k sigs)."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/wallets/{wallet}/defi-positions": {
      "get": {
        "summary": "Wallet DeFi positions",
        "description": "Cross-protocol open DeFi positions for a Solana wallet — Kamino/Drift/Orca+Raydium LP, lending, and staking — each with USD value, deposits, borrows, and rewards. Complements /portfolio (spot holdings) and /stake (native stake) so net worth reflects money in DeFi, not just tokens.",
        "tags": [
          "Wallets"
        ],
        "operationId": "get-api-v2-wallets-wallet-defi-positions",
        "parameters": [
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Solana wallet address (base58). Validated; invalid returns 400."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/wallets/{wallet}/pnl": {
      "get": {
        "summary": "Wallet PnL ledger",
        "description": "Per-token profit-and-loss / cost-basis ledger for ANY Solana wallet (not just bot users): realized & unrealized PnL, average buy/sell price, buy/sell volume + counts, and fees paid. Use it to rank whales and vet copy-trade targets on hard numbers.",
        "tags": [
          "Wallets"
        ],
        "operationId": "get-api-v2-wallets-wallet-pnl",
        "parameters": [
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Solana wallet address (base58). Validated; invalid returns 400."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Positions to return. Clamped 1..200."
          },
          {
            "name": "onlyOpen",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "When true, only currently-held positions."
          },
          {
            "name": "sortBy",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Sort field (e.g. totalPnlUSD, realizedPnlUSD)."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/wallets/{wallet}/swaps": {
      "get": {
        "summary": "Wallet enriched swaps (MEV / fees)",
        "description": "Per-swap fee decomposition for a Solana wallet: total / gas / platform / MEV fee split plus the routing platform (e.g. axiom, gmgn, trojan). A forensics layer over the plain activity feed — surface sandwich exposure and where a wallet routes its trades.",
        "tags": [
          "Wallets"
        ],
        "operationId": "get-api-v2-wallets-wallet-swaps",
        "parameters": [
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Solana wallet address (base58). Validated; invalid returns 400."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Swaps to return. Clamped 1..200."
          },
          {
            "name": "order",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "'asc' or 'desc'."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/wallets/{wallet}/sandwich-rollup": {
      "get": {
        "summary": "MEV sandwich loss rollup",
        "description": "How much a wallet lost to MEV sandwich bots across its recent swaps. Scans the wallet's recent swaps, keeps only the provider-flagged SANDWICHED ones (cap 25), and quantifies each via the per-tx MEV forensics engine (self-memoized per signature 24h) — returning confirmed sandwich events with victim loss, attacker, and extra slippage, plus a total. Route memoized 60s.",
        "tags": [
          "Wallets"
        ],
        "operationId": "get-api-v2-wallets-wallet-sandwich-rollup",
        "parameters": [
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Solana wallet address (base58). 400 \"invalid wallet\" if invalid."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "How many recent swaps to scan (clamped 1-80). Only provider-flagged sandwiches among them are quantified (max 25 signatures)."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/wallets/{wallet}/informed": {
      "get": {
        "summary": "Informed-buyer timing analysis",
        "description": "Measures whether a wallet's ENTRIES are consistently well timed: for each recent buy, compares the executed price against the peak of the following window (default 3h) and reports how often that move cleared the pump threshold (default +50%). Flags a wallet only when BOTH a minimum number of well-timed entries AND a minimum hit rate are met, so a prolific trader who caught a few pumps by volume alone does not qualify. Correlation, not proof — a skilled momentum trader scores the same as someone acting on information. Coverage fields report how much of the wallet's history could actually be priced; a low `coverage` means the verdict is inconclusive rather than clean. Cached 30 min per wallet + threshold set.",
        "tags": [
          "Wallets"
        ],
        "operationId": "wallets-informed",
        "parameters": [
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Base58 wallet address."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/wallets/cohort": {
      "post": {
        "summary": "Wallet cohort analysis (submit)",
        "description": "Finds on-chain links between an ARBITRARY set of up to 100 wallets — no token mint involved. Traces each wallet's funding chain, direct transfers, shared funders, shared counterparties, common collectors and portfolio overlap, then clusters them into entities. Returns 202 with a jobId; poll GET /api/v2/wallets/cohort/{jobId} for progress and the result. A 100-wallet run typically completes in 15-60s. Identical address sets submitted within 10 minutes reuse the previous result (cached:true), and a concurrent identical submission joins the in-flight job instead of duplicating cost.",
        "tags": [
          "Wallets"
        ],
        "parameters": [],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "addresses": {
                    "type": "string",
                    "description": "The wallets to analyse. Either an array of base58 pubkeys, or a single string with one address per line / comma / semicolon / whitespace separated (so a pasted CSV column or spreadsheet cell works). Duplicates are removed, unreadable entries are reported back in parseInfo rather than silently dropped, and the list is capped at COHORT_MAX_WALLETS (default 100). Minimum 2 valid addresses."
                  },
                  "refresh": {
                    "type": "string",
                    "description": "Set true to bypass the 10-minute result reuse and force a fresh analysis of the same address set."
                  }
                },
                "required": [
                  "addresses"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v2/wallets/cohort/{jobId}": {
      "get": {
        "summary": "Wallet cohort analysis (result)",
        "description": "Polls a cohort analysis. While running, returns status + progress (stage, done/total, pct). When status is 'done', includes the full result: a verdict (plain-language headline + tone), a cohesion score with its three components, the node/edge graph, clusters, BRIDGES (external addresses that connect wallets you supplied but did not include), the funding timeline, and coverage. Wallets whose history could not be read are returned in `unknown` — NOT in `isolated` — so unreadable data is never presented as evidence of independence. Returns 404 if the job expired (20min TTL) or the service restarted; resubmit in that case.",
        "tags": [
          "Wallets"
        ],
        "parameters": [
          {
            "name": "jobId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The jobId returned by POST /api/v2/wallets/cohort."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/market/lighthouse": {
      "get": {
        "summary": "Market lighthouse (24h Solana DEX stats)",
        "description": "Returns aggregate 24h trading activity across Solana DEXs — total USD volume (and its 24h change), trade/buy/sell counts, and total fees paid. Sourced from the market-data layer's market/lighthouse endpoint, reshaped into a flat object and cached 5 minutes.",
        "tags": [
          "Market & Charts"
        ],
        "operationId": "get-api-v2-market-lighthouse",
        "parameters": [],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/market/sol-price": {
      "get": {
        "summary": "Canonical SOL/USD price",
        "description": "Returns the current SOL/USD spot price with a multi-source fallback chain: 30s in-memory cache → the price store DB table (accepted up to 10 min old) → Jupiter lite price API → $120 hard fallback. Always resolves to a price.",
        "tags": [
          "Market & Charts"
        ],
        "operationId": "get-api-v2-market-sol-price",
        "parameters": [],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/market/sol-price/history": {
      "get": {
        "summary": "SOL/USD price history",
        "description": "SOL/USD price time-series for charting, over a chosen range. Returns an array of [timestamp_ms, priceUsd] points (ascending), downsampled to at most 300 points. Range-specific cache TTLs.",
        "tags": [
          "Market & Charts"
        ],
        "operationId": "get-api-v2-market-sol-price-history",
        "parameters": [
          {
            "name": "range",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "One of: 1h, 24h, 7d, 30d. Any other value falls back to 24h. Determines lookback + native candle period (1h→5m, 24h/7d→1h, 30d→1d) and cache TTL (1h→60s, 24h→5m, 7d→15m, 30d→30m)."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/tokens/{mint}/chart": {
      "get": {
        "summary": "Token price chart (OHLCV / price history)",
        "description": "Returns a time-series of {t,v} price points for a mint from the market-data layer market history, suitable for candle/line charts. Cached 30s per (mint,period,from,to).",
        "tags": [
          "Market & Charts"
        ],
        "operationId": "get-api-v2-tokens-mint-chart",
        "parameters": [
          {
            "name": "mint",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "SPL token mint address (base58). 400 'invalid mint' if invalid."
          },
          {
            "name": "period",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Time bucket. Allowed: 1h, 1d, 7d, 30d, 90d, 365d. Any other value silently falls back to 1d."
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Start timestamp (ms epoch, passed via Number()). Optional."
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "End timestamp (ms epoch, passed via Number()). Optional."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/tokens/{mint}/ohlcv": {
      "get": {
        "summary": "OHLCV candles",
        "description": "Open/high/low/close price candles, resampled from the price series into a fixed number of equal-width time buckets over the requested period. Use this for charting libraries that expect candle arrays (the /chart endpoint returns a raw price line). Cached 30s.",
        "tags": [
          "Market & Charts"
        ],
        "operationId": "get-api-v2-tokens-mint-ohlcv",
        "parameters": [
          {
            "name": "mint",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "SPL token mint address (base58). 400 'invalid mint' if invalid."
          },
          {
            "name": "period",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Look-back window. Allowed: 1h, 1d, 7d, 30d, 90d, 365d. Any other value falls back to 1d."
          },
          {
            "name": "buckets",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Number of candles to resample the window into. Clamped to 10–300."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/market/pool-ohlcv": {
      "get": {
        "summary": "Per-pool OHLCV candles",
        "description": "OHLCV candles for a SPECIFIC liquidity pool address (not the token aggregate). For a token live on several pools (e.g. a graduated pump.fun token on both PumpSwap and Raydium), chart the exact venue a user trades.",
        "tags": [
          "Market & Charts"
        ],
        "operationId": "get-api-v2-market-pool-ohlcv",
        "parameters": [
          {
            "name": "pool",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Pool / pair address (base58). Get one from a token markets lookup."
          },
          {
            "name": "period",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Candle period: 1m,5m,1h,1d,1w."
          },
          {
            "name": "amount",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Candles to return. Max 2000."
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Start time (ms epoch)."
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "End time (ms epoch)."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/tokens/{mint}/chart-source": {
      "get": {
        "summary": "Chart embed source resolver",
        "description": "Resolves a ready-to-embed iframe src for a mint's chart, with provider failover: the DEX index (established DEX pools) first, then the pool index (pre-migration pump.fun bonding curves). Cached 10 min.",
        "tags": [
          "Market & Charts"
        ],
        "operationId": "get-api-v2-tokens-mint-chart-source",
        "parameters": [
          {
            "name": "mint",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "SPL token mint address (base58). 400 'invalid mint' if invalid."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/whales/labels": {
      "post": {
        "summary": "Bulk classify wallet labels",
        "description": "Bulk-classifies up to 100 wallet addresses, returning the market-data layer-derived smart-money flag tags (e.g. insider, dev, sniper, smart, fresh, bundler) plus known-entity name/type/logo and platform when available.",
        "tags": [
          "Whales"
        ],
        "operationId": "post-api-v2-whales-labels",
        "parameters": [],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "wallets": {
                    "type": "string",
                    "description": "Array of Solana wallet base58 addresses to classify. Invalid addresses (must match base58 32-44 chars) are filtered out, and the list is truncated to the first 100 valid addresses. If zero valid addresses remain after filtering, the request is rejected with 400."
                  }
                },
                "required": [
                  "wallets"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v2/whales/discover/{mint}": {
      "get": {
        "summary": "Discover whales in a token's top holders",
        "description": "Finds whale wallets among a token's largest holders: fetches the top-20 token accounts via the node RPC, resolves them to owner wallets, dedupes, then (if the market-data layer is configured) enriches and keeps only owners that carry smart-money flags or a known entity name. Result is cached in-process for 5 minutes per mint.",
        "tags": [
          "Whales"
        ],
        "operationId": "get-api-v2-whales-discover-mint",
        "parameters": [
          {
            "name": "mint",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Solana token mint address (base58, 32-44 chars). Validated with isAddr; an invalid value returns 400 'invalid mint'."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/whales/featured": {
      "get": {
        "summary": "Featured whales directory",
        "description": "Curated smart-money / whale directory, live-enriched via the market-data layer labels + portfolio. Returns net worth, asset count, top holdings and entity/flag metadata per wallet, filterable by category. Default category 'trader' so institutional CEX vaults don't dominate.",
        "tags": [
          "Whales"
        ],
        "operationId": "whales-featured",
        "parameters": [
          {
            "name": "category",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter: 'trader' (default), 'cex', 'mm', 'validator', or 'all'."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/leaderboard/featured": {
      "get": {
        "summary": "Featured leaderboard",
        "description": "Curated smart-money leaderboard ranking the same the market-data layer-enriched whale set as /whales/featured by net worth, reshaped into ranking rows. pnl30d/winRate are 0 placeholders — the market-data layer does not expose per-wallet realized PnL / win-rate here.",
        "tags": [
          "Whales"
        ],
        "operationId": "leaderboard-featured",
        "parameters": [
          {
            "name": "category",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter: 'trader' (default), 'cex', 'mm', 'validator', or 'all'."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/swap/quote": {
      "get": {
        "summary": "Get swap quote",
        "description": "Returns the best Jupiter swap route/quote for swapping `amount` base units of `inputMint` into `outputMint`. The returned quote object is required as input to POST /api/v2/swap/build.",
        "tags": [
          "Trading"
        ],
        "operationId": "get-api-v2-swap-quote",
        "parameters": [
          {
            "name": "inputMint",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mint address of the input (sell) token. Must be a valid base58 Solana address (32-44 chars). E.g. So11111111111111111111111111111111111111112 for SOL."
          },
          {
            "name": "outputMint",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mint address of the output (buy) token. Must be a valid base58 Solana address."
          },
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Input amount in the token's smallest base units (e.g. lamports for SOL). Parsed with Number(); must be finite and > 0."
          },
          {
            "name": "slippageBps",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Allowed slippage in basis points. Coerced via Number() then clamped to [1, 10000]; falsy/NaN falls back to 50 (0.5%)."
          },
          {
            "name": "platformFeeBps",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Optional platform fee in basis points to embed in the quote. When provided, clamped to [0, 2500]; omitted from the upstream request when absent."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/swap/build": {
      "post": {
        "summary": "Build swap transaction",
        "description": "Builds an UNSIGNED base64 swap transaction from a quote (from /swap/quote) and the user's public key. The caller signs and broadcasts it themselves; the API never holds keys.",
        "tags": [
          "Trading"
        ],
        "operationId": "post-api-v2-swap-build",
        "parameters": [],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "quoteResponse": {
                    "type": "string",
                    "description": "The full quote object returned by GET /swap/quote (the value of its `quote` field). Must be a non-null object."
                  },
                  "userPublicKey": {
                    "type": "string",
                    "description": "The wallet public key that will sign and own the swap. Must be a valid base58 Solana address."
                  },
                  "feeAccount": {
                    "type": "string",
                    "description": "Optional token account to collect the platform fee (must correspond to the platformFeeBps used in the quote). If present, must be a valid base58 address (else 400)."
                  },
                  "computeUnitPriceMicroLamports": {
                    "type": "string",
                    "description": "Optional priority fee (compute unit price) in micro-lamports. Forwarded to Jupiter only when truthy."
                  }
                },
                "required": [
                  "quoteResponse",
                  "userPublicKey"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v2/orders/limit/create": {
      "post": {
        "summary": "Create limit order",
        "description": "Creates a Jupiter limit order and returns the UNSIGNED transaction to open it. Caller signs and broadcasts.",
        "tags": [
          "Trading"
        ],
        "operationId": "post-api-v2-orders-limit-create",
        "parameters": [],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "inputMint": {
                    "type": "string",
                    "description": "Mint to sell. Valid base58 Solana address."
                  },
                  "outputMint": {
                    "type": "string",
                    "description": "Mint to buy. Valid base58 Solana address."
                  },
                  "makingAmount": {
                    "type": "string",
                    "description": "Amount of inputMint to sell, in base units. Validated with Number() (must be finite)."
                  },
                  "takingAmount": {
                    "type": "string",
                    "description": "Amount of outputMint to receive, in base units (defines the limit price). Validated with Number() (must be finite)."
                  },
                  "maker": {
                    "type": "string",
                    "description": "Wallet that owns the order. If provided, must be a valid base58 address (else 400). Forwarded to Jupiter."
                  },
                  "payer": {
                    "type": "string",
                    "description": "Wallet that pays rent/fees for creating the order. Forwarded to Jupiter as-is (not address-validated by this service)."
                  }
                },
                "required": [
                  "inputMint",
                  "outputMint",
                  "makingAmount",
                  "takingAmount"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v2/orders/limit": {
      "get": {
        "summary": "List open limit orders",
        "description": "Lists a wallet's currently open Jupiter limit orders.",
        "tags": [
          "Trading"
        ],
        "operationId": "get-api-v2-orders-limit",
        "parameters": [
          {
            "name": "wallet",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Wallet address whose open limit orders to fetch. Must be a valid base58 Solana address."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/orders/limit/history": {
      "get": {
        "summary": "Limit order history",
        "description": "Returns a wallet's historical (filled/cancelled/expired) Jupiter limit orders.",
        "tags": [
          "Trading"
        ],
        "operationId": "get-api-v2-orders-limit-history",
        "parameters": [
          {
            "name": "wallet",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Wallet address whose limit-order history to fetch. Must be a valid base58 Solana address."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/orders/limit/cancel": {
      "post": {
        "summary": "Cancel limit order",
        "description": "Builds an UNSIGNED transaction to cancel an existing Jupiter limit order. Caller signs and broadcasts.",
        "tags": [
          "Trading"
        ],
        "operationId": "post-api-v2-orders-limit-cancel",
        "parameters": [],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "order": {
                    "type": "string",
                    "description": "The limit order to cancel — the order account public key (or order object) returned by /limit/create or /limit. Required; missing -> 400. Forwarded to Jupiter as the request body field `order`."
                  },
                  "maker": {
                    "type": "string",
                    "description": "The order maker / owner wallet. Forwarded to Jupiter as-is (not address-validated by this service)."
                  }
                },
                "required": [
                  "order"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v2/orders/dca/create": {
      "post": {
        "summary": "Create DCA position",
        "description": "Creates a Jupiter dollar-cost-average (DCA) position and returns the UNSIGNED transaction to open it. Caller signs and broadcasts.",
        "tags": [
          "Trading"
        ],
        "operationId": "post-api-v2-orders-dca-create",
        "parameters": [],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "inputMint": {
                    "type": "string",
                    "description": "Mint to spend each cycle. Valid base58 Solana address."
                  },
                  "outputMint": {
                    "type": "string",
                    "description": "Mint to accumulate. Valid base58 Solana address."
                  },
                  "inAmount": {
                    "type": "string",
                    "description": "Total input amount to DCA across all cycles, in base units. Validated with Number() (must be finite)."
                  },
                  "cycleSecondsApart": {
                    "type": "string",
                    "description": "Seconds between each buy cycle. Validated with Number() (must be finite)."
                  },
                  "numberOfCycles": {
                    "type": "string",
                    "description": "Number of buy cycles to execute. Validated with Number() (must be finite)."
                  },
                  "user": {
                    "type": "string",
                    "description": "Wallet that owns the DCA position. If provided, must be a valid base58 address (else 400). Forwarded to Jupiter."
                  }
                },
                "required": [
                  "inputMint",
                  "outputMint",
                  "inAmount",
                  "cycleSecondsApart",
                  "numberOfCycles"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v2/orders/dca": {
      "get": {
        "summary": "List DCA positions",
        "description": "Lists a wallet's Jupiter DCA positions.",
        "tags": [
          "Trading"
        ],
        "operationId": "get-api-v2-orders-dca",
        "parameters": [
          {
            "name": "wallet",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Wallet address whose DCA positions to fetch. Must be a valid base58 Solana address."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/orders/dca/close": {
      "post": {
        "summary": "Close DCA position",
        "description": "Builds an UNSIGNED transaction to close an existing Jupiter DCA position and withdraw remaining funds. Caller signs and broadcasts.",
        "tags": [
          "Trading"
        ],
        "operationId": "post-api-v2-orders-dca-close",
        "parameters": [],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "dca": {
                    "type": "string",
                    "description": "The DCA position to close — the position account public key (or object) returned by /dca/create or /dca. Required; missing -> 400. Forwarded to Jupiter as the request body field `dca`."
                  },
                  "user": {
                    "type": "string",
                    "description": "The DCA position owner wallet. Forwarded to Jupiter as-is (not address-validated by this service)."
                  }
                },
                "required": [
                  "dca"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v2/launches/recent": {
      "get": {
        "summary": "List recent launches",
        "description": "Returns the most recently indexed token launches (newly created liquidity pools) sorted by indexed_at descending, optionally filtered to a single DEX. Backed by the trading-bot indexer's /v1/indexer/recent-pools, cached in-process for 5 seconds per DEX bucket.",
        "tags": [
          "Launches"
        ],
        "operationId": "get-api-v2-launches-recent",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Number of launches to return. Coerced via Number(); non-numeric / missing falls back to 50, then clamped to the inclusive range [1, 200] (Math.max(1, Math.min(200,...))). The upstream is always queried at the max (200) and the result is sliced on read, so e.g. limit=49 and limit=50 share one upstream call/cache entry."
          },
          {
            "name": "dex",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter to a single DEX. Lowercased before validation and must be one of an allow-list: pumpfun, pumpswap, raydium, raydium_cpmm, meteora, meteora_damm_v2, orca, bonk. Any other non-empty value returns 400. Omitted/empty means all DEXes (cache bucket 'all'). Sent upstream as dex_type."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/rpc": {
      "post": {
        "summary": "JSON-RPC passthrough (Stryke's node layer mainnet)",
        "description": "Forwards a single or batched (max 25) read-only Solana JSON-RPC request to Stryke's node layer mainnet and returns the upstream response verbatim. Only allow-listed read-only methods are permitted (no transaction submission, signing, or subscriptions).",
        "tags": [
          "RPC"
        ],
        "operationId": "post-api-v2-rpc",
        "parameters": [],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "(root)": {
                    "type": "string",
                    "description": "The JSON body is EITHER a single JSON-RPC 2.0 call object OR an array of such objects (batch). An array must contain 1..25 calls (MAX_BATCH=25); empty or >25 → 400. A null/absent body → 400 'json body required'. The whole body is JSON.stringify'd and forwarded verbatim to Stryke's node layer — Stryke's node layer returns results in the same single-vs-array shape as the request."
                  },
                  "method": {
                    "type": "string",
                    "description": "Per-call: the JSON-RPC method name. Must be a string (else 400 'each call needs a string method') and must be in the read-only allow-list (else 400 'method <m> not allowed'). Allowed: getAccountInfo, getMultipleAccounts, getProgramAccounts, getBalance, getTokenAccountBalance, getTokenAccountsByOwner, getTokenAccountsByDelegate, getTokenLargestAccounts, getTokenSupply, getSlot, getBlockHeight, getBlock, getEpochInfo, getLatestBlockhash, getRecentBlockhash, getMinimumBalanceForRentExemption, getSignatureStatuses, getTransaction, getTransactionCount, getInflationReward, getStakeActivation, getVoteAccounts, getClusterNodes, getHealth, getVersion, getGenesisHash, getIdentity, getAsset, getAssetBatch, getAssetsByOwner, getAssetsByGroup, getAssetsByAuthority, getAssetsByCreator, getAssetProof, getAssetProofBatch, searchAssets, getTokenAccounts, getNftEditions, getSignaturesForAsset, getSignaturesForAddress, simulateTransaction, getPriorityFeeEstimate, getTransfersByAddress."
                  },
                  "jsonrpc": {
                    "type": "string",
                    "description": "Per-call: JSON-RPC version, e.g. \"2.0\". Not validated by the handler (only `method` is checked) but forwarded verbatim to Stryke's node layer, which expects \"2.0\". Recommended to set it."
                  },
                  "id": {
                    "type": "string",
                    "description": "Per-call: client-chosen request id echoed back by Stryke's node layer in the matching response object. Forwarded verbatim; not validated."
                  },
                  "params": {
                    "type": "string",
                    "description": "Per-call: method-specific JSON-RPC params, forwarded verbatim to Stryke's node layer (shape depends on the method — e.g. [address, {encoding}] for getAccountInfo, or {id: mint} for getAsset). Not validated by this handler."
                  }
                },
                "required": [
                  "(root)",
                  "method"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v2/stream": {
      "get": {
        "summary": "Realtime stream (WebSocket)",
        "description": "WebSocket gateway at wss://api.stryke.gg/api/v2/stream (also reachable as /stream). Opened via an HTTP GET Upgrade — NOT a normal request/response. PAID-TIER-ONLY: authenticate with a paid Trading-API key (rt_… on tier builder/scale/enterprise) or an operator-granted Data-API key; the free/self-registered tier and the public builder key are DENIED at upgrade (401). Subscribe to two channels — launches (new pools, optional dex filter) and token+mint (live per-mint trade tape). One shared reference-counted poller/feed per distinct topic fans out to all subscribers, so backend load scales with distinct topics, not client count. Per-connection topic caps and per-key connection caps are enforced from the caller's tier.",
        "tags": [
          "Streaming"
        ],
        "operationId": "get-api-v2-stream",
        "parameters": [
          {
            "name": "key",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "API key for auth when headers are unavailable (browsers). Precedence at upgrade: Authorization: Bearer <key> → ?key= → X-API-Key header → Sec-WebSocket-Protocol. A paid rt_ Trading-API key or an operator-granted Data-API key is required; the public builder key is always denied."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "op": {
                    "type": "string",
                    "description": "Client→server message op (JSON text frame): \"subscribe\" | \"unsubscribe\" | \"ping\". ping replies {type:\"pong\"} (app-level keepalive; separate from the 30s WS protocol ping/pong heartbeat)."
                  },
                  "channel": {
                    "type": "string",
                    "description": "Required for subscribe/unsubscribe: \"launches\" or \"token\"."
                  },
                  "dex": {
                    "type": "string",
                    "description": "launches channel only. Optional DEX filter; one of: pumpfun, pumpswap, raydium, raydium_cpmm, meteora, meteora_damm_v2, orca, bonk. Omit for all DEXes. Creates topic launches:<dex>."
                  },
                  "mint": {
                    "type": "string",
                    "description": "token channel only (REQUIRED there). Base58 SPL mint. Creates topic token:<mint> and counts against your plan's token-topic cap. launches subscriptions are free (do not count)."
                  }
                },
                "required": [
                  "op",
                  "channel"
                ]
              }
            }
          }
        }
      }
    },
    "/api/register": {
      "post": {
        "summary": "Register for API Key",
        "description": "Creates a new API key for a Solana wallet that has no existing active key. The plaintext key is returned exactly once and cannot be retrieved later (only a hash is stored). The fee_wallet defaults to the owner wallet. Rate-limited to 5 attempts per hour per IP.",
        "tags": [
          "Account & Keys"
        ],
        "operationId": "post-api-register",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "walletAddress": {
                    "type": "string",
                    "description": "The owner's Solana wallet address (base58). Validated by constructing a PublicKey; also used as the default fee wallet."
                  },
                  "email": {
                    "type": "string",
                    "description": "Contact email. If provided, must match a basic email regex or the request is rejected with 400."
                  },
                  "websiteUrl": {
                    "type": "string",
                    "description": "The integrator's website URL, stored on the key record. No format validation."
                  }
                },
                "required": [
                  "walletAddress"
                ]
              }
            }
          }
        }
      }
    },
    "/api/auth/challenge": {
      "post": {
        "summary": "Request Wallet Signature Challenge",
        "description": "Step 1 of wallet ownership verification. Generates a unique nonce + human-readable message that the wallet must sign off-chain. The challenge is stored server-side keyed by wallet address and expires after 5 minutes. Used as the prerequisite for /api/regenerate-key and /api/auth/wallet-login.",
        "tags": [
          "Account & Keys"
        ],
        "operationId": "post-api-auth-challenge",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "walletAddress": {
                    "type": "string",
                    "description": "The Solana wallet address (base58) to issue a challenge for. Validated via PublicKey construction."
                  }
                },
                "required": [
                  "walletAddress"
                ]
              }
            }
          }
        }
      }
    },
    "/api/auth/wallet-login": {
      "post": {
        "summary": "Wallet Login (Session Token)",
        "description": "Verifies a signature against the wallet's pending challenge and, if a matching active API key exists, issues a 1-hour dashboard session token. The session token authorizes /api/dashboard-session and /api/update-domains without exposing the API key. Returns key metadata and stats but never the plaintext API key.",
        "tags": [
          "Account & Keys"
        ],
        "operationId": "post-api-auth-wallet-login",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "walletAddress": {
                    "type": "string",
                    "description": "The wallet address that requested the challenge. Validated via PublicKey."
                  },
                  "signature": {
                    "type": "string",
                    "description": "Base58-encoded ed25519 signature of the challenge `message`, verified with tweetnacl sign.detached.verify against the wallet's public key."
                  }
                },
                "required": [
                  "walletAddress",
                  "signature"
                ]
              }
            }
          }
        }
      }
    },
    "/api/regenerate-key": {
      "post": {
        "summary": "Regenerate API Key",
        "description": "Step 2 (key rotation): verifies the wallet signature against its pending challenge, then issues a brand-new API key for the wallet's existing active key record, invalidating the old key. The new plaintext key is returned exactly once. Rate-limited to 5 attempts/hour/IP.",
        "tags": [
          "Account & Keys"
        ],
        "operationId": "post-api-regenerate-key",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "walletAddress": {
                    "type": "string",
                    "description": "The owner wallet that requested the challenge. Validated via PublicKey."
                  },
                  "signature": {
                    "type": "string",
                    "description": "Base58-encoded ed25519 signature of the challenge `message`, verified with tweetnacl against the wallet pubkey."
                  }
                },
                "required": [
                  "walletAddress",
                  "signature"
                ]
              }
            }
          }
        }
      }
    },
    "/api/dashboard/{wallet}": {
      "get": {
        "summary": "Get Public Dashboard by Wallet",
        "description": "Returns all API key records (active and inactive) owned by a wallet, with per-key stats and metadata. Public and unauthenticated — no signature or API key required — so it exposes only non-sensitive fields (no plaintext key, no session). Intended for a basic dashboard lookup before login.",
        "tags": [
          "Account & Keys"
        ],
        "operationId": "get-api-dashboard-wallet",
        "parameters": [
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The owner's Solana wallet address (base58). Validated via PublicKey; invalid input returns 400."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/dashboard-session": {
      "get": {
        "summary": "Get Dashboard via Session Token",
        "description": "Returns the authenticated dashboard for the key tied to a valid wallet-login session token, including key metadata, stats, fee wallet balance, and the 20 most recent recovery transactions. Authenticated by the X-Session-Token header (issued by /api/auth/wallet-login), not by X-API-Key.",
        "tags": [
          "Account & Keys"
        ],
        "operationId": "get-api-dashboard-session",
        "parameters": [],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/update-domains": {
      "post": {
        "summary": "Update Allowed Domains (Session)",
        "description": "Sets the allowed-domain allowlist for the session's API key. Authenticated by the X-Session-Token header. Domains are normalized (trimmed, lowercased) and validated against a hostname regex (supports a leading wildcard like *.example.com); an empty/invalid list clears the restriction so the key works on any domain.",
        "tags": [
          "Account & Keys"
        ],
        "operationId": "post-api-update-domains",
        "parameters": [],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "domains": {
                    "type": "string",
                    "description": "Array of domain strings to allow (e.g. ['example.com','*.app.example.com']). Each is trimmed, lowercased, and filtered by a hostname regex permitting an optional leading '*.'. If the array is empty, missing, or all entries are invalid, the domain restriction is removed (key allowed on all domains)."
                  }
                },
                "required": []
              }
            }
          }
        }
      }
    },
    "/api/dashboard/update-fee-wallet": {
      "post": {
        "summary": "Update Fee Wallet",
        "description": "Changes the destination (fee) wallet that receives the integrator's share of recovery fees for a specific API key. Authorization is by ownership match: the UPDATE only succeeds when the supplied apiKeyId belongs to ownerWallet. No signature or session token is verified.",
        "tags": [
          "Account & Keys"
        ],
        "operationId": "post-api-dashboard-update-fee-wallet",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "ownerWallet": {
                    "type": "string",
                    "description": "The wallet that owns the API key. Validated via PublicKey and matched against the key's owner_wallet in the WHERE clause."
                  },
                  "newFeeWallet": {
                    "type": "string",
                    "description": "The new Solana wallet (base58) to receive fee payouts. Validated via PublicKey."
                  },
                  "apiKeyId": {
                    "type": "string",
                    "description": "The numeric id of the API key to update. Must belong to ownerWallet or the update affects 0 rows (404)."
                  }
                },
                "required": [
                  "ownerWallet",
                  "newFeeWallet",
                  "apiKeyId"
                ]
              }
            }
          }
        }
      }
    },
    "/api/branding-license": {
      "get": {
        "summary": "Get Branding License Info",
        "description": "Returns static information about the white-label branding license: its cost in SOL, the payment recipient wallet, and the list of unlocked features. Public, no parameters, no DB access — purely informational for the purchase flow.",
        "tags": [
          "Account & Keys"
        ],
        "operationId": "get-api-branding-license",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/verify-branding-payment": {
      "post": {
        "summary": "Verify Branding License Payment",
        "description": "Validates an on-chain SOL payment for the branding license and, if valid, activates the white-label license on the specified API key. Confirms the transaction on-chain, checks it is recent (<1 hour), and verifies the license wallet received at least ~0.5 SOL (1% fee tolerance). Authorization is by ownerWallet/apiKeyId ownership match.",
        "tags": [
          "Account & Keys"
        ],
        "operationId": "post-api-verify-branding-payment",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "ownerWallet": {
                    "type": "string",
                    "description": "The wallet that owns the API key. Matched against owner_wallet for the given apiKeyId."
                  },
                  "transactionSignature": {
                    "type": "string",
                    "description": "The Solana transaction signature of the 0.5 SOL payment to the branding license wallet. Fetched on-chain (commitment 'confirmed') and inspected for the payment to BRANDING_LICENSE_WALLET."
                  },
                  "apiKeyId": {
                    "type": "string",
                    "description": "The numeric id of the API key to activate branding on. Must belong to ownerWallet."
                  }
                },
                "required": [
                  "ownerWallet",
                  "transactionSignature",
                  "apiKeyId"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v1/check": {
      "post": {
        "summary": "Check Wallets for Recoverable Rent",
        "description": "Scans one or more Solana wallets for empty and balance-holding token accounts and returns the estimated SOL rent that could be recovered by closing/burning them, without producing or submitting any transactions.",
        "tags": [
          "Recovery (v1)"
        ],
        "operationId": "post-api-v1-check",
        "parameters": [],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "walletAddresses": {
                    "type": "string",
                    "description": "Array of base58 Solana wallet addresses to scan. Must be a non-empty array with at most 20 entries. Invalid addresses are returned per-wallet with an `error` field rather than failing the whole request."
                  },
                  "includeAccounts": {
                    "type": "string",
                    "description": "When true, each wallet result also includes an `accounts` object with `empty` and `burnable` arrays of formatted token-account details (account, mint, displayName, owner, program, decimals, uiAmount, amountRaw, state, isFrozen, type). Defaults to false."
                  }
                },
                "required": [
                  "walletAddresses"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v1/close": {
      "post": {
        "summary": "Build Close/Burn Transactions",
        "description": "Builds unsigned (base64-serialized) Solana transactions that close empty token accounts (and optionally burn + close balance-holding accounts) to reclaim rent, chunked to fit transaction size limits. The client signs and submits them; nothing is broadcast server-side.",
        "tags": [
          "Recovery (v1)"
        ],
        "operationId": "post-api-v1-close",
        "parameters": [],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "walletAddresses": {
                    "type": "string",
                    "description": "Array of base58 wallet addresses (the account owners) to build transactions for. Non-empty, max 20 entries."
                  },
                  "refundWallet": {
                    "type": "string",
                    "description": "Optional base58 address that should receive the reclaimed rent (close-account destination). Defaults to each wallet's own address when omitted."
                  },
                  "burnAccounts": {
                    "type": "string",
                    "description": "When true, also burns tokens in non-empty accounts (then closes them) to reclaim their rent. Uses a smaller chunk size and higher compute budget per account. Defaults to false."
                  },
                  "selectedTokens": {
                    "type": "string",
                    "description": "Optional whitelist of mint addresses to burn. Only applied when burnAccounts is true; when non-empty, only accounts whose mint is in this set are burned. Defaults to [] (burn all non-empty accounts)."
                  }
                },
                "required": [
                  "walletAddresses"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v1/confirm": {
      "post": {
        "summary": "Confirm Transaction (Log Stats)",
        "description": "Records a completed close/burn transaction for tracking and per-API-key statistics (accounts closed, SOL recovered, owner fee earned). Does not verify the transaction on-chain.",
        "tags": [
          "Recovery (v1)"
        ],
        "operationId": "post-api-v1-confirm",
        "parameters": [],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "walletAddress": {
                    "type": "string",
                    "description": "The wallet address the transaction was executed for."
                  },
                  "signature": {
                    "type": "string",
                    "description": "The on-chain transaction signature to log (stored as transaction_signature)."
                  },
                  "accountsClosed": {
                    "type": "string",
                    "description": "Number of token accounts closed/burned in the transaction. Defaults to 0 when omitted; added to the key's running total."
                  },
                  "solRecovered": {
                    "type": "string",
                    "description": "SOL reclaimed by the transaction. Defaults to 0; drives the platform-fee / owner-fee split and the key's running totals."
                  }
                },
                "required": [
                  "walletAddress",
                  "signature"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v1/stats": {
      "get": {
        "summary": "Get API Key Stats",
        "description": "Returns lifetime usage statistics for the calling API key plus its 10 most recent logged transactions.",
        "tags": [
          "Recovery (v1)"
        ],
        "operationId": "get-api-v1-stats",
        "parameters": [],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/token-info": {
      "post": {
        "summary": "Token Metadata (Proxy)",
        "description": "Fetches token metadata for a batch of mint addresses by proxying to the public Stryke.com token-info service. Pass-through endpoint with permissive CORS.",
        "tags": [
          "Recovery (v1)"
        ],
        "operationId": "post-api-token-info",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "mints": {
                    "type": "string",
                    "description": "Array of base58 token mint addresses to look up metadata for. Must be a non-empty array; otherwise 400."
                  }
                },
                "required": [
                  "mints"
                ]
              }
            }
          }
        }
      }
    },
    "/api/rpc/send": {
      "post": {
        "summary": "Send Transaction (RPC proxy)",
        "description": "Server-side proxy that forwards a signed, base64-encoded transaction to the the node RPC `sendTransaction` method and returns the raw JSON-RPC response. Exists so the paid Stryke's node layer key never leaves the server; defaults skipPreflight=false and preflightCommitment=confirmed, which the caller can override via `options`.",
        "tags": [
          "Direct RPC"
        ],
        "operationId": "post-api-rpc-send",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "transaction": {
                    "type": "string",
                    "description": "Base64-encoded, fully-signed serialized transaction. Required — a falsy value returns 400."
                  },
                  "options": {
                    "type": "string",
                    "description": "Optional overrides spread onto the Stryke's node layer sendTransaction config object. Defaults applied before spread: { encoding: 'base64', skipPreflight: false, preflightCommitment: 'confirmed' }. Anything here (e.g. skipPreflight, maxRetries, preflightCommitment) overrides those defaults. Defaults to {}."
                  }
                },
                "required": [
                  "transaction"
                ]
              }
            }
          }
        }
      }
    },
    "/api/rpc/status": {
      "post": {
        "summary": "Get Signature Statuses (RPC proxy)",
        "description": "Server-side proxy to the node RPC `getSignatureStatuses`. Accepts either a single `signature` or an array of `signatures`, normalizes to an array, and returns the raw JSON-RPC response. Defaults searchTransactionHistory=false (overridable via `options`).",
        "tags": [
          "Direct RPC"
        ],
        "operationId": "post-api-rpc-status",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "signatures": {
                    "type": "string",
                    "description": "Array of base58 transaction signatures to look up. Takes precedence over `signature`. Either this or `signature` must be supplied and resolve to a non-empty array, or the request 400s."
                  },
                  "signature": {
                    "type": "string",
                    "description": "A single base58 transaction signature; wrapped into a one-element array if `signatures` is not provided. Either this or `signatures` is required."
                  },
                  "options": {
                    "type": "string",
                    "description": "Optional overrides spread onto the getSignatureStatuses config. Default applied before spread: { searchTransactionHistory: false }. Set { searchTransactionHistory: true } to search older confirmed transactions. Defaults to {}."
                  }
                },
                "required": []
              }
            }
          }
        }
      }
    },
    "/api/rpc/simulate": {
      "post": {
        "summary": "Simulate Transaction (debug)",
        "description": "Debug endpoint that deserializes a base64 transaction (tries VersionedTransaction, falls back to legacy Transaction) and simulates it against the live connection with sigVerify=false and replaceRecentBlockhash=true. Returns a custom summary of the simulation rather than a raw RPC envelope.",
        "tags": [
          "Direct RPC"
        ],
        "operationId": "post-api-rpc-simulate",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "transaction": {
                    "type": "string",
                    "description": "Base64-encoded serialized transaction (signed or unsigned — signatures are not verified during simulation). Required; falsy returns 400. Parsed as a VersionedTransaction first, then legacy Transaction.from() as fallback."
                  },
                  "options": {
                    "type": "string",
                    "description": "Optional overrides spread onto connection.simulateTransaction config. Defaults applied before spread: { sigVerify: false, replaceRecentBlockhash: true }. Can override these or add fields like { accounts: { addresses: [...] }, commitment }. Defaults to {}."
                  }
                },
                "required": [
                  "transaction"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v2/health": {
      "get": {
        "summary": "Health check",
        "description": "Liveness probe. Returns ok + the API version + a server timestamp. No API key required. (The root /health alias returns the same.)",
        "tags": [
          "System"
        ],
        "operationId": "get-api-v2-health",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/stats": {
      "get": {
        "summary": "Per-key usage stats",
        "description": "Usage dashboard for the calling API key over a time range: total calls, error/failure rates, latency, provider spend, a top-routes breakdown, and a daily series for charts. Scoped to the authenticated key only (reads the caller's own call log). Defaults to 7d.",
        "tags": [
          "System"
        ],
        "operationId": "get-api-v2-stats",
        "parameters": [
          {
            "name": "range",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Window: 24h, 7d, 30d, or 90d. Any other value falls back to 7d."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/trade/buy": {
      "post": {
        "summary": "Buy token",
        "description": "Buy a token with the caller's per-user wallet using the same TradeExecutor as the Telegram bot. Auto-detects DEX (or honors dex/pool_address hints), injects the app's atomic platform fee, and supports SOL or USDC/USDT settlement (pay_with_mint). Two modes: custodial (server signs+sends, returns signature) or client_signs:true (returns an unsigned base64 tx for the caller to sign+broadcast). Idempotent via the Idempotency-Key header.",
        "tags": [
          "Trading API: Trade & Execution"
        ],
        "operationId": "trade-buy",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "mint": {
                    "type": "string",
                    "description": "Token mint to buy (base58)."
                  },
                  "amount_in": {
                    "type": "string",
                    "description": "Amount to SPEND — SOL by default, or whole pay_with_mint units (e.g. USDC). Must be 0.00001–100. Aliases: amount_sol, amount."
                  },
                  "dex": {
                    "type": "string",
                    "description": "DEX to trade on (auto-detected if omitted): pumpfun, pumpswap, raydium_cpmm, etc. Alias: dex_type."
                  },
                  "pool_address": {
                    "type": "string",
                    "description": "Specific pool/pair address, skips detection. Alias: pair_address."
                  },
                  "slippage_bps": {
                    "type": "string",
                    "description": "Slippage tolerance in bps (default 1000 = 10%). Max 100000."
                  },
                  "mev_protect": {
                    "type": "string",
                    "description": "Route via Jito bundle for MEV protection (default false)."
                  },
                  "tip_lamports": {
                    "type": "string",
                    "description": "MEV/priority tip in lamports (default 1500000 = 0.0015 SOL)."
                  },
                  "compute_unit_price": {
                    "type": "string",
                    "description": "Priority fee, micro-lamports per CU (default V1_DEFAULT_CU_PRICE, 500000). Alias: cu_price."
                  },
                  "priority_micro_lamports": {
                    "type": "string",
                    "description": "Priority fee µL/CU; takes precedence over compute_unit_price. Clamped to V1_MAX_PRIORITY_FEE_LAMPORTS. Aliases: priorityFee, priority_fee."
                  },
                  "pay_with_mint": {
                    "type": "string",
                    "description": "Settlement/input currency mint to pay with (default SOL). Accepts SOL/WSOL/USDC/USDT only; token must be in a pool quoted in that currency. Alias: input_mint."
                  },
                  "client_signs": {
                    "type": "string",
                    "description": "If true, return an unsigned base64 tx instead of executing (caller signs + broadcasts). Requires wallet pubkey."
                  },
                  "wallet": {
                    "type": "string",
                    "description": "Trading wallet pubkey (required for client_signs payer). Alias: trading_wallet."
                  },
                  "use_router": {
                    "type": "string",
                    "description": "Route swap through the on-chain Stryke Router (default false = direct DEX). Only honored on client_signs builds. Aliases: useRouter, route_via_program."
                  },
                  "mev_tip_lamports": {
                    "type": "string",
                    "description": "Jito tip (total lamports) baked into a client_signs build; omit → 100000 default, 0 → opt-out. Aliases: mevTipLamports, mevTip, jitoTip."
                  },
                  "mev_tip_bps": {
                    "type": "string",
                    "description": "Jito tip as bps of quoted trade value (resolved server-side). Overridden by mev_tip_lamports. Alias: mevTipBps."
                  },
                  "fee_bps": {
                    "type": "string",
                    "description": "Per-trade platform fee bps override — only honored with the fee_routing scope (else 403). Alias: fee_bps_override."
                  },
                  "fee_wallet": {
                    "type": "string",
                    "description": "Override destination wallet for this trade's platform fee — only with fee_routing scope (else 403). Alias: feeWallet."
                  },
                  "nonce_account": {
                    "type": "string",
                    "description": "Durable nonce account pubkey (Turbo Mode); pass with nonce_value."
                  },
                  "nonce_value": {
                    "type": "string",
                    "description": "Current nonce hash (base58); required with nonce_account."
                  },
                  "simulate": {
                    "type": "string",
                    "description": "Simulate only — runs full pipeline via simulateTransaction, no on-chain submit (default false)."
                  }
                },
                "required": [
                  "mint",
                  "amount_in"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/trade/sell": {
      "post": {
        "summary": "Sell token",
        "description": "Sell a token from the caller's per-user wallet via the same TradeExecutor as the bot. Sell by percent (default 100) or exact amount_in (base units, converted to a percent of the ATA balance). Injects the app's platform fee (deducted from output), supports SOL or USDC/USDT settlement (receive_mint), and offers custodial or client_signs unsigned-tx modes. Closes/records the position on a 100% sell.",
        "tags": [
          "Trading API: Trade & Execution"
        ],
        "operationId": "trade-sell",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "mint": {
                    "type": "string",
                    "description": "Token mint to sell (base58)."
                  },
                  "percent": {
                    "type": "string",
                    "description": "Percent of balance to sell, 1–100 (default 100 when amount_in omitted)."
                  },
                  "amount_in": {
                    "type": "string",
                    "description": "Exact token amount (base units) to sell; converted to a percent of the ATA balance. Alias: amount_tokens."
                  },
                  "dex": {
                    "type": "string",
                    "description": "DEX to trade on (auto-detected if omitted). Alias: dex_type."
                  },
                  "pool_address": {
                    "type": "string",
                    "description": "Specific pool/pair address, skips detection. Alias: pair_address."
                  },
                  "slippage_bps": {
                    "type": "string",
                    "description": "Slippage tolerance in bps (default 1000). Max 100000."
                  },
                  "mev_protect": {
                    "type": "string",
                    "description": "Route via Jito bundle (default false)."
                  },
                  "close_token_account": {
                    "type": "string",
                    "description": "Close the token ATA after a full sell to reclaim rent. Alias: close_ata."
                  },
                  "tip_lamports": {
                    "type": "string",
                    "description": "MEV/priority tip in lamports (default 1500000)."
                  },
                  "compute_unit_price": {
                    "type": "string",
                    "description": "Priority fee µL/CU (default 500000). Alias: cu_price."
                  },
                  "priority_micro_lamports": {
                    "type": "string",
                    "description": "Priority fee µL/CU; precedence over compute_unit_price; clamped. Aliases: priorityFee, priority_fee."
                  },
                  "receive_mint": {
                    "type": "string",
                    "description": "Currency to RECEIVE (default SOL); accepts SOL/WSOL/USDC/USDT; token must be in a pool quoted in it. Alias: output_mint."
                  },
                  "client_signs": {
                    "type": "string",
                    "description": "If true, return an unsigned base64 tx instead of executing."
                  },
                  "wallet": {
                    "type": "string",
                    "description": "Trading wallet pubkey (client_signs payer). Alias: trading_wallet."
                  },
                  "use_router": {
                    "type": "string",
                    "description": "Route through the on-chain Stryke Router (default false = direct DEX). client_signs only. Aliases: useRouter, route_via_program."
                  },
                  "mev_tip_lamports": {
                    "type": "string",
                    "description": "Jito tip (total lamports) for a client_signs build; omit → 100000, 0 → opt-out. Aliases: mevTipLamports, mevTip, jitoTip."
                  },
                  "mev_tip_bps": {
                    "type": "string",
                    "description": "Jito tip as bps of estimated SOL proceeds (resolved server-side). Overridden by mev_tip_lamports. Alias: mevTipBps."
                  },
                  "fee_bps": {
                    "type": "string",
                    "description": "Per-trade platform fee bps override — fee_routing scope only (else 403). Alias: fee_bps_override."
                  },
                  "fee_wallet": {
                    "type": "string",
                    "description": "Override platform-fee destination — fee_routing scope only (else 403). Alias: feeWallet."
                  },
                  "nonce_account": {
                    "type": "string",
                    "description": "Durable nonce account pubkey (Turbo Mode)."
                  },
                  "nonce_value": {
                    "type": "string",
                    "description": "Current nonce hash; required with nonce_account."
                  },
                  "simulate": {
                    "type": "string",
                    "description": "Simulate only, no on-chain submit (default false)."
                  }
                },
                "required": [
                  "mint"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/trade/buy-multi-hop": {
      "post": {
        "summary": "Buy token (multi-hop alias)",
        "description": "Convenience alias that delegates to /v1/trade/buy with SOL settlement (the executor handles SOL↔USDC bridging automatically). Accepts a slim multi-hop body; bridge_slippage_bps and intermediate_mint are accepted but ignored (routing is automatic).",
        "tags": [
          "Trading API: Trade & Execution"
        ],
        "operationId": "trade-buy-multi-hop",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "mint": {
                    "type": "string",
                    "description": "Token mint to buy."
                  },
                  "amount_sol": {
                    "type": "string",
                    "description": "SOL to spend."
                  },
                  "dex_type": {
                    "type": "string",
                    "description": "Optional DEX hint."
                  },
                  "pair_address": {
                    "type": "string",
                    "description": "Optional pool/pair address hint."
                  },
                  "slippage_bps": {
                    "type": "string",
                    "description": "Slippage tolerance in bps (default 1000)."
                  },
                  "mev_protect": {
                    "type": "string",
                    "description": "Route via Jito bundle (default false)."
                  },
                  "bridge_slippage_bps": {
                    "type": "string",
                    "description": "Accepted but ignored — multi-hop routing/bridging is automatic."
                  },
                  "intermediate_mint": {
                    "type": "string",
                    "description": "Accepted but ignored — bridge currency is chosen automatically."
                  }
                },
                "required": [
                  "mint",
                  "amount_sol"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/trade/sell-multi-hop": {
      "post": {
        "summary": "Sell token (multi-hop alias)",
        "description": "Convenience alias that delegates to /v1/trade/sell with SOL settlement (the executor handles SOL↔USDC bridging automatically). bridge_slippage_bps and intermediate_mint are accepted but ignored.",
        "tags": [
          "Trading API: Trade & Execution"
        ],
        "operationId": "trade-sell-multi-hop",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "mint": {
                    "type": "string",
                    "description": "Token mint to sell."
                  },
                  "percent": {
                    "type": "string",
                    "description": "Percent of balance to sell, 1–100 (default 100)."
                  },
                  "amount_tokens": {
                    "type": "string",
                    "description": "Exact token amount (base units) to sell."
                  },
                  "dex_type": {
                    "type": "string",
                    "description": "Optional DEX hint."
                  },
                  "pair_address": {
                    "type": "string",
                    "description": "Optional pool/pair address hint."
                  },
                  "slippage_bps": {
                    "type": "string",
                    "description": "Slippage tolerance in bps (default 1000)."
                  },
                  "mev_protect": {
                    "type": "string",
                    "description": "Route via Jito bundle (default false)."
                  },
                  "close_ata": {
                    "type": "string",
                    "description": "Close the token ATA after a full sell."
                  },
                  "bridge_slippage_bps": {
                    "type": "string",
                    "description": "Accepted but ignored — routing/bridging is automatic."
                  },
                  "intermediate_mint": {
                    "type": "string",
                    "description": "Accepted but ignored — bridge currency is chosen automatically."
                  }
                },
                "required": [
                  "mint"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/trade/pool-params": {
      "get": {
        "summary": "Pool params",
        "description": "Resolve and return the on-chain pool parameters for a mint (DEX type, quote mint, SOL-quoted flag) using the executor's cached pool-param fetch. Useful for verifying routing before a trade. Read-only, no wallet needed.",
        "tags": [
          "Trading API: Trade & Execution"
        ],
        "operationId": "trade-pool-params",
        "parameters": [
          {
            "name": "mint",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Token mint (base58)."
          },
          {
            "name": "dex_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Optional DEX hint to skip detection."
          },
          {
            "name": "pair_address",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Optional pool/pair address hint."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/trade/estimate": {
      "get": {
        "summary": "Estimate output",
        "description": "Estimate the output and price impact for a buy or sell of a given amount, using live (best-effort on-chain refreshed) reserves from the resolved pool. Same path as /v1/trade/quote's underlying estimate but with simple query params and no fee accounting.",
        "tags": [
          "Trading API: Trade & Execution"
        ],
        "operationId": "trade-estimate",
        "parameters": [
          {
            "name": "mint",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Token mint (base58)."
          },
          {
            "name": "amount",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Input amount in raw base units (lamports for a SOL buy, token base units for a sell)."
          },
          {
            "name": "side",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "buy or sell (default buy)."
          },
          {
            "name": "dex_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Optional DEX hint."
          },
          {
            "name": "pair_address",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Optional pool/pair address hint."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/trade/quote": {
      "post": {
        "summary": "Trade quote",
        "description": "Pre-trade preview WITHOUT building a transaction. One side of input_mint/output_mint must be a quote currency (SOL/WSOL/USDC/USDT), the other the token; buy = spend quote→receive token, sell = sell token→receive quote. Returns gross + net (after platform fee) outputs, the slippage floor the built tx will enforce, price impact, and the route/DEX. Rejects token↔token and cross-currency mismatches.",
        "tags": [
          "Trading API: Trade & Execution"
        ],
        "operationId": "trade-quote",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "input_mint": {
                    "type": "string",
                    "description": "Mint being spent (base58). For a buy this is the quote currency; for a sell it is the token."
                  },
                  "output_mint": {
                    "type": "string",
                    "description": "Mint being received (base58). For a buy this is the token; for a sell it is the quote currency."
                  },
                  "amount": {
                    "type": "string",
                    "description": "Amount of input_mint in raw base units."
                  },
                  "slippage_bps": {
                    "type": "string",
                    "description": "Slippage tolerance in bps (default 1000), used to compute min_out_amount."
                  },
                  "dex_type": {
                    "type": "string",
                    "description": "Optional DEX hint to skip detection."
                  },
                  "pair_address": {
                    "type": "string",
                    "description": "Optional pool/pair address hint."
                  }
                },
                "required": [
                  "input_mint",
                  "output_mint",
                  "amount"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/trade/bundle-status": {
      "get": {
        "summary": "Bundle / landing status",
        "description": "Report the ACTUAL landing of an MEV broadcast so a client can honestly badge 'MEV protected' only when the Jito bundle itself landed. Pass bundle_id (from the broadcast response) for Jito getBundleStatuses attribution and/or signature for definitive on-chain landing (incl. the RPC-fallback leg). At least one is required.",
        "tags": [
          "Trading API: Trade & Execution"
        ],
        "operationId": "trade-bundle-status",
        "parameters": [
          {
            "name": "bundle_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Bundle id from the broadcast response (Jito attribution). Preferred for MEV badging."
          },
          {
            "name": "signature",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Tx signature for definitive on-chain landing (catches the RPC-fallback leg)."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/trade/balance": {
      "get": {
        "summary": "Token balance",
        "description": "Return the token balance for the requesting user's wallet, split across the seed-derived and standard ATAs. Resolves the per-user wallet from the authenticated session/X-User-Ref.",
        "tags": [
          "Trading API: Trade & Execution"
        ],
        "operationId": "trade-balance",
        "parameters": [
          {
            "name": "mint",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Token mint (base58)."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/trade/sol-balance": {
      "get": {
        "summary": "SOL balance",
        "description": "Return the SOL balance (lamports + SOL) for the requesting user's wallet, resolved from the authenticated session/X-User-Ref. No params.",
        "tags": [
          "Trading API: Trade & Execution"
        ],
        "operationId": "trade-sol-balance",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/trade/detect": {
      "get": {
        "summary": "Detect DEX",
        "description": "Auto-detect the DEX/pool for a mint without executing a trade, using the same token-info path the bot uses when a user pastes an address (the DEX index + indexer). Returns DEX type, pair address, and basic name/symbol.",
        "tags": [
          "Trading API: Trade & Execution"
        ],
        "operationId": "trade-detect",
        "parameters": [
          {
            "name": "mint",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Token mint (base58)."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/trade/broadcast": {
      "post": {
        "summary": "Broadcast signed tx",
        "description": "Relay a client-signed base64 VersionedTransaction to the network through the executor's SWQOS-aware submit pipeline (same endpoints/pool as custodial trades). Auto-detects an embedded Jito tip and offers the tx via sendBundle first (with public-RPC fallback). submitted_via reflects the attempted strategy, NOT a landing guarantee — poll /v1/trade/bundle-status.",
        "tags": [
          "Trading API: Trade & Execution"
        ],
        "operationId": "trade-broadcast",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "signed_tx_base64": {
                    "type": "string",
                    "description": "Base64-encoded signed VersionedTransaction (max 2 KiB on the wire)."
                  },
                  "tip_lamports": {
                    "type": "string",
                    "description": "Informational only — tip already embedded in the signed tx; the submit path adds no tip instructions."
                  }
                },
                "required": [
                  "signed_tx_base64"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/token/info": {
      "get": {
        "summary": "Token info",
        "description": "Full token info (price, market cap, liquidity, 24h volume, DEX/pair, bonding-curve and authority flags) using the same fetch path the bot uses when a user pastes an address. No wallet needed.",
        "tags": [
          "Trading API: Trade & Execution"
        ],
        "operationId": "token-info",
        "parameters": [
          {
            "name": "mint",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Token mint (base58)."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/test/discover": {
      "get": {
        "summary": "Discover pools on-chain",
        "description": "Diagnostic: directly run on-chain pool discovery for a mint (PDA batch + GPA scan), bypassing the indexer DB. Returns every pool found with its DEX, quote mint, and program id, plus discovery latency. Intended for routing/debugging.",
        "tags": [
          "Trading API: Trade & Execution"
        ],
        "operationId": "test-discover",
        "parameters": [
          {
            "name": "mint",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Token mint (base58)."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/refund/scan": {
      "get": {
        "summary": "Scan wallet for reclaimable rent",
        "description": "Scans the caller's per-user active wallet for empty token accounts (ATAs) and dust-balance accounts, reporting the SOL rent reclaimable from each. Read-only (no on-chain tx); resolves the wallet from the tenant's X-User-Ref context.",
        "tags": [
          "Trading API: Trade & Execution"
        ],
        "operationId": "refund-scan",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/refund/close-empty": {
      "post": {
        "summary": "Close empty token accounts",
        "description": "Scans then closes all empty (zero-balance) token accounts for the caller's wallet in a single batch on-chain transaction, reclaiming their SOL rent. Idempotency-key supported (trade-scope idempotency layer). Frozen (honeypot) accounts are skipped and reported.",
        "tags": [
          "Trading API: Trade & Execution"
        ],
        "operationId": "refund-close-empty",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/refund/burn-and-close": {
      "post": {
        "summary": "Burn dust and close accounts",
        "description": "Scans for token accounts holding dust balances, burns the remaining tokens, and closes the accounts to reclaim SOL rent — in one on-chain batch. Optional max_accounts caps how many are processed this call. Frozen accounts are skipped and reported.",
        "tags": [
          "Trading API: Trade & Execution"
        ],
        "operationId": "refund-burn-and-close",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "max_accounts": {
                    "type": "string",
                    "description": "Maximum number of dust accounts to burn+close in this call. Defaults to all if omitted."
                  }
                },
                "required": []
              }
            }
          }
        }
      }
    },
    "/v1/refund/close-nonce": {
      "post": {
        "summary": "Close nonce accounts",
        "description": "Closes durable-nonce accounts for the caller's wallet and reclaims their rent. Pass specific nonce_pubkeys to close those, or omit/empty to close ALL nonce (pro) accounts looked up from the DB for this wallet. Closes in one on-chain batch.",
        "tags": [
          "Trading API: Trade & Execution"
        ],
        "operationId": "refund-close-nonce",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "nonce_pubkeys": {
                    "type": "string",
                    "description": "Specific nonce account pubkeys to close. If omitted or empty, closes ALL nonce accounts for this wallet (resolved from DB pro_accounts)."
                  }
                },
                "required": []
              }
            }
          }
        }
      }
    },
    "/v1/wallet/list": {
      "get": {
        "summary": "List wallets",
        "description": "Lists all wallets owned by the requesting tenant user (resolved from X-User-Ref). Returns each wallet's id, name, public key, active flag, generated flag, and migration timestamp.",
        "tags": [
          "Trading API: Wallets"
        ],
        "operationId": "wallet-list",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/wallet/create": {
      "post": {
        "summary": "Create wallet",
        "description": "Generates a brand-new Solana keypair server-side, stores it encrypted, and associates it with the tenant user. Optionally makes it the active wallet.",
        "tags": [
          "Trading API: Wallets"
        ],
        "operationId": "wallet-create",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Display name for the wallet. Defaults to \"Wallet\" if omitted."
                  },
                  "set_active": {
                    "type": "string",
                    "description": "If true, marks the new wallet as the user's active wallet. Defaults to false."
                  }
                },
                "required": []
              }
            }
          }
        }
      }
    },
    "/v1/wallet/import": {
      "post": {
        "summary": "Import wallet",
        "description": "Imports an existing wallet from a base58-encoded 64-byte secret key, stores it encrypted, and associates it with the tenant user. Key is validated without panicking; malformed keys are rejected.",
        "tags": [
          "Trading API: Wallets"
        ],
        "operationId": "wallet-import",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "private_key": {
                    "type": "string",
                    "description": "Base58-encoded full 64-byte secret key."
                  },
                  "name": {
                    "type": "string",
                    "description": "Display name for the wallet. Defaults to \"Imported Wallet\" if omitted."
                  },
                  "set_active": {
                    "type": "string",
                    "description": "If true, marks the imported wallet as active. Defaults to false."
                  }
                },
                "required": [
                  "private_key"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/wallet/rename": {
      "post": {
        "summary": "Rename wallet",
        "description": "Renames an existing wallet owned by the tenant user. The rename is ownership-scoped — only wallets belonging to the caller can be renamed.",
        "tags": [
          "Trading API: Wallets"
        ],
        "operationId": "wallet-rename",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "wallet_id": {
                    "type": "string",
                    "description": "ID of the wallet to rename (must belong to the caller)."
                  },
                  "name": {
                    "type": "string",
                    "description": "New display name. Cannot be empty/whitespace."
                  }
                },
                "required": [
                  "wallet_id",
                  "name"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/wallet/switch": {
      "post": {
        "summary": "Switch active wallet",
        "description": "Sets the given wallet as the tenant user's active wallet. Scoped to the caller — only the user's own wallets can be activated.",
        "tags": [
          "Trading API: Wallets"
        ],
        "operationId": "wallet-switch",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "wallet_id": {
                    "type": "string",
                    "description": "ID of the wallet to make active (must belong to the caller)."
                  }
                },
                "required": [
                  "wallet_id"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/wallet/withdraw": {
      "post": {
        "summary": "Withdraw SOL",
        "description": "Sends SOL from the user's active wallet to an external address on-chain. Validates the destination, amount bounds, active-wallet presence, and self-send. Requires an executor/RPC deployment.",
        "tags": [
          "Trading API: Wallets"
        ],
        "operationId": "wallet-withdraw",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "to_address": {
                    "type": "string",
                    "description": "Destination Solana address (base58 pubkey)."
                  },
                  "amount_sol": {
                    "type": "string",
                    "description": "Amount of SOL to send. Must be > 0 and ≤ 1,000,000."
                  }
                },
                "required": [
                  "to_address",
                  "amount_sol"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/wallet/{id}": {
      "delete": {
        "summary": "Delete wallet",
        "description": "Deletes a wallet by ID for the tenant user. Refuses to delete the user's last remaining wallet.",
        "tags": [
          "Trading API: Wallets"
        ],
        "operationId": "wallet-delete",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID of the wallet to delete (must belong to the caller)."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/wallet/migrate": {
      "post": {
        "summary": "Migrate wallet from legacy app",
        "description": "Imports a wallet from a legacy app's base58 64-byte secret key, stores it encrypted, and stamps migrated_at=NOW() plus source_app_id (the calling API app) so the terminal can track migrations. Optionally sets it active.",
        "tags": [
          "Trading API: Wallets"
        ],
        "operationId": "wallet-migrate",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "secret_key_base58": {
                    "type": "string",
                    "description": "Base58-encoded full 64-byte secret key from the legacy app."
                  },
                  "name": {
                    "type": "string",
                    "description": "Display name for the migrated wallet."
                  },
                  "set_active": {
                    "type": "string",
                    "description": "If true, atomically makes this the user's active wallet. Defaults to false."
                  }
                },
                "required": [
                  "secret_key_base58",
                  "name"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/keys/challenge": {
      "post": {
        "summary": "Request key-issuance challenge",
        "description": "Mints a single-use, TTL-bound nonce and a human-readable message for a Solana wallet to sign (Phantom signMessage). The signed message later proves wallet ownership for self-serve key issuance/login. Public — no bearer auth; the wallet signature is the auth. Per-IP rate limited and optionally allowlist-gated.",
        "tags": [
          "Trading API: Keys & Sessions"
        ],
        "operationId": "keys-challenge",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "wallet": {
                    "type": "string",
                    "description": "Base58 Solana wallet address to issue/own the key."
                  }
                },
                "required": [
                  "wallet"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/keys/issue": {
      "post": {
        "summary": "Issue (or rotate) API key via signed challenge",
        "description": "Verifies the ed25519 signature over the exact challenge message, atomically consumes the single-use nonce, then issues a fresh API key bound to the wallet — or rotates the wallet's existing key (one key per wallet). The full key is returned ONCE; an encrypted recoverable copy is stored so it can be re-revealed later via the session. Also returns a wallet session token. Public — the wallet signature is the auth.",
        "tags": [
          "Trading API: Keys & Sessions"
        ],
        "operationId": "keys-issue",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "wallet": {
                    "type": "string",
                    "description": "Base58 Solana wallet address; must match the challenge's wallet."
                  },
                  "nonce": {
                    "type": "string",
                    "description": "Nonce returned by /v1/keys/challenge."
                  },
                  "signature": {
                    "type": "string",
                    "description": "ed25519 signature over the challenge message — base64 (preferred) or base58."
                  }
                },
                "required": [
                  "wallet",
                  "nonce",
                  "signature"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/keys/login": {
      "post": {
        "summary": "Wallet login (start session)",
        "description": "Proves wallet ownership once via a signed challenge and returns a session token (default 7 days) without issuing a key. Reports whether the wallet already has a key and whether it is revealable, so a portal can show Reveal/Reset vs Generate. Public — the wallet signature is the auth.",
        "tags": [
          "Trading API: Keys & Sessions"
        ],
        "operationId": "keys-login",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "wallet": {
                    "type": "string",
                    "description": "Base58 Solana wallet address; must match the challenge's wallet."
                  },
                  "nonce": {
                    "type": "string",
                    "description": "Nonce returned by /v1/keys/challenge."
                  },
                  "signature": {
                    "type": "string",
                    "description": "ed25519 signature over the challenge message — base64 or base58."
                  }
                },
                "required": [
                  "wallet",
                  "nonce",
                  "signature"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/keys/reveal": {
      "post": {
        "summary": "Reveal full API key (session)",
        "description": "Returns the FULL API key for the session wallet, decrypted server-side from the stored recoverable copy. Requires a valid session token (obtained via /v1/keys/issue or /v1/keys/login) — no new signature needed. Public route; the session token is the auth.",
        "tags": [
          "Trading API: Keys & Sessions"
        ],
        "operationId": "keys-reveal",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "session_token": {
                    "type": "string",
                    "description": "Wallet session token from /v1/keys/login or /v1/keys/issue."
                  }
                },
                "required": [
                  "session_token"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/keys/reset": {
      "post": {
        "summary": "Reset (rotate) API key (session)",
        "description": "Rotates — or first-time generates — the session wallet's API key. The previous key stops working immediately and a fresh full key is returned once. Requires a valid session token; no new signature needed. Public route; the session token is the auth.",
        "tags": [
          "Trading API: Keys & Sessions"
        ],
        "operationId": "keys-reset",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "session_token": {
                    "type": "string",
                    "description": "Wallet session token from /v1/keys/login or /v1/keys/issue."
                  }
                },
                "required": [
                  "session_token"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/tiers": {
      "get": {
        "summary": "List paid tiers",
        "description": "Public pricing list: every tier from the operator-editable api_tiers table with USD price, a live SOL-lamports quote (price_usd / live SOL price), credits, rate limits, stake eligibility, plus the payment treasury address. Drives the pricing page so a client can build the exact SOL payment.",
        "tags": [
          "Trading API: Billing & Tiers"
        ],
        "operationId": "billing-tiers",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/billing/status": {
      "post": {
        "summary": "Billing status for session key",
        "description": "Returns the current tier, credit quota/usage, rate limit, and tier expiry for the API key owned by the wallet behind the session token. Resolves session -> wallet -> self-serve app id in-handler.",
        "tags": [
          "Trading API: Billing & Tiers"
        ],
        "operationId": "billing-status",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "session_token": {
                    "type": "string",
                    "description": "Wallet session token from POST /v1/keys/login. Verified server-side (HMAC) to resolve the owner wallet and its self-serve API key."
                  }
                },
                "required": [
                  "session_token"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/billing/pay": {
      "post": {
        "summary": "Pay (SOL) and apply tier",
        "description": "Verifies an on-chain SOL payment and applies the chosen paid tier to the session wallet's API key. Confirms the tx succeeded, was sent from the session wallet (fee payer / account index 0), and credited the treasury >= the tier price (priced in USD, converted at live SOL price with a drift tolerance). Records the signature single-use (atomic redeem) so it can't be replayed.",
        "tags": [
          "Trading API: Billing & Tiers"
        ],
        "operationId": "billing-pay",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "session_token": {
                    "type": "string",
                    "description": "Wallet session token from POST /v1/keys/login; binds the payment to the owner wallet."
                  },
                  "tier": {
                    "type": "string",
                    "description": "Tier name to purchase (must be a paid tier with price_usd > 0)."
                  },
                  "currency": {
                    "type": "string",
                    "description": "Payment currency. Defaults to \"sol\"; only \"sol\" is accepted (USDC reserved for later)."
                  },
                  "tx_signature": {
                    "type": "string",
                    "description": "Signature of the on-chain SOL transfer to the treasury. Must be confirmed, successful, sent from the session wallet, and credit the treasury >= the (tolerance-adjusted) tier price."
                  }
                },
                "required": [
                  "session_token",
                  "tier",
                  "tx_signature"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/billing/stake-check": {
      "post": {
        "summary": "Stake-check ($STRYKE) tier grant",
        "description": "Checks the session wallet's $STRYKE balance (held in its ATA) and grants the highest-priced tier whose stake_min it meets. Re-checkable; does not reset the credit window unless the tier actually changes, and the tier lapses at window end if the holder drops below the threshold.",
        "tags": [
          "Trading API: Billing & Tiers"
        ],
        "operationId": "billing-stake-check",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "session_token": {
                    "type": "string",
                    "description": "Wallet session token from POST /v1/keys/login; identifies the wallet whose $STRYKE balance is checked."
                  }
                },
                "required": [
                  "session_token"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/tokens/verified": {
      "get": {
        "summary": "List verified tokens",
        "description": "Public list of all mints that currently hold an active paid 'Verified by Stryke' badge. Reads the verified-token table directly (the deepscan engine uses this as a warm cache); always works regardless of whether badge granting is enabled.",
        "tags": [
          "Trading API: Token Verification"
        ],
        "operationId": "tokens-verified-list",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/tokens/{mint}/verification": {
      "get": {
        "summary": "Get token verification status",
        "description": "Public per-token verification lookup. Returns whether a single mint holds an active 'Verified by Stryke' badge; the deepscan engine polls this (fail-open, cached) to decide whether to render the badge. Score-neutral — never affects the token's safety score.",
        "tags": [
          "Trading API: Token Verification"
        ],
        "operationId": "tokens-verification-get",
        "parameters": [
          {
            "name": "mint",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Token mint address to look up (trimmed)."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/tokens/verify": {
      "post": {
        "summary": "Verify token (grant badge)",
        "description": "Wallet-session + on-chain SOL payment + Deep Scan score gate that grants a paid 'Verified by Stryke' badge to a mint. Requires a valid HMAC wallet session, a confirmed SOL payment from that wallet to the verify/billing treasury (live SOL pricing with drift tolerance), and a current Deep Scan score >= the configured bar. Atomic grant with anti-replay (one tx signature can verify exactly one token). Revenue routes to the trEnD treasury.",
        "tags": [
          "Trading API: Token Verification"
        ],
        "operationId": "tokens-verify",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "session_token": {
                    "type": "string",
                    "description": "HMAC wallet session token from the keys/billing wallet-sig flow; identifies the paying wallet."
                  },
                  "mint": {
                    "type": "string",
                    "description": "Token mint address to verify (must be a valid pubkey)."
                  },
                  "tx_signature": {
                    "type": "string",
                    "description": "Signature of the on-chain SOL payment tx (payer must equal the session wallet; treasury must receive >= the SOL-priced fee minus tolerance). Single-use."
                  }
                },
                "required": [
                  "session_token",
                  "mint",
                  "tx_signature"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/quests/projects": {
      "post": {
        "summary": "Create quest project",
        "description": "Creates a quest project in the Node quests engine. Thin metered proxy: the Rust layer authenticates the app key + `quests` scope, charges credits, then forwards the body verbatim with the authenticated `app.id` as `x-stryke-app-id`, which the engine uses to enforce per-tenant ownership (a project's `stryke_app_id` must match the calling app).",
        "tags": [
          "Trading API: Quests"
        ],
        "operationId": "quests-create-project",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "<engine fields>": {
                    "type": "string",
                    "description": "Free-form JSON forwarded verbatim to the quests engine's POST /quests/projects (e.g. project name/config). Body shape is owned by the Node quests-engine, not this proxy."
                  }
                },
                "required": [
                  "<engine fields>"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/quests/projects/{pid}/credentials": {
      "post": {
        "summary": "Set project credentials",
        "description": "Stores per-project verification credentials (e.g. X/Reddit/Discord API secrets) for project `pid` in the quests engine's encrypted vault. Forwards the body verbatim with the authenticated app id; engine rejects if `pid` is not owned by the calling app.",
        "tags": [
          "Trading API: Quests"
        ],
        "operationId": "quests-put-credentials",
        "parameters": [
          {
            "name": "pid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Quest project id (i64)."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "<engine fields>": {
                    "type": "string",
                    "description": "Free-form JSON of provider credentials forwarded verbatim to POST /quests/projects/{pid}/credentials. Shape owned by the quests-engine."
                  }
                },
                "required": [
                  "<engine fields>"
                ]
              }
            }
          }
        }
      },
      "get": {
        "summary": "Get project credentials",
        "description": "Returns the (redacted) credential configuration for project `pid` from the quests engine. Proxy forwards the authenticated app id; engine enforces project ownership.",
        "tags": [
          "Trading API: Quests"
        ],
        "operationId": "quests-get-credentials",
        "parameters": [
          {
            "name": "pid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Quest project id (i64)."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/quests/campaigns": {
      "post": {
        "summary": "Create campaign",
        "description": "Creates a campaign (a grouping of tasks under a project) in the quests engine. Body forwarded verbatim with the authenticated app id for per-tenant ownership.",
        "tags": [
          "Trading API: Quests"
        ],
        "operationId": "quests-create-campaign",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "<engine fields>": {
                    "type": "string",
                    "description": "Free-form JSON forwarded verbatim to POST /quests/campaigns (e.g. project_id, name, schedule). Shape owned by the quests-engine."
                  }
                },
                "required": [
                  "<engine fields>"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/quests/tasks": {
      "post": {
        "summary": "Create task",
        "description": "Creates a verifiable task (e.g. follow/retweet/join/on-chain action) under a campaign in the quests engine. Body forwarded verbatim with the authenticated app id.",
        "tags": [
          "Trading API: Quests"
        ],
        "operationId": "quests-create-task",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "<engine fields>": {
                    "type": "string",
                    "description": "Free-form JSON forwarded verbatim to POST /quests/tasks (e.g. campaign_id, type, target, reward). Shape owned by the quests-engine."
                  }
                },
                "required": [
                  "<engine fields>"
                ]
              }
            }
          }
        }
      },
      "get": {
        "summary": "List tasks",
        "description": "Lists tasks from the quests engine, scoped to the calling app. All query-string params are passed through verbatim (percent-encoded) to the engine's GET /quests/tasks.",
        "tags": [
          "Trading API: Quests"
        ],
        "operationId": "quests-list-tasks",
        "parameters": [
          {
            "name": "<engine filters>",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Arbitrary filter params (e.g. campaign_id, project_id, status) forwarded verbatim to the quests-engine. Accepted params are defined by the engine."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/quests/verify": {
      "post": {
        "summary": "Verify quest task",
        "description": "Submits a task completion attempt for verification (the billable unit of the Quests API). The engine performs the actual check (X/Reddit/Discord/on-chain). Charge-per-attempt: the credit reservation is kept on any 2xx success:true, including verified:false, since the upstream cost was incurred.",
        "tags": [
          "Trading API: Quests"
        ],
        "operationId": "quests-verify",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "<engine fields>": {
                    "type": "string",
                    "description": "Free-form JSON forwarded verbatim to POST /quests/verify (e.g. task_id, wallet/user identity, proof). Shape owned by the quests-engine."
                  }
                },
                "required": [
                  "<engine fields>"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/quests/status": {
      "get": {
        "summary": "Quest status",
        "description": "Returns task/campaign completion status for a participant from the quests engine, scoped to the calling app. Query params forwarded verbatim.",
        "tags": [
          "Trading API: Quests"
        ],
        "operationId": "quests-status",
        "parameters": [
          {
            "name": "<engine filters>",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Arbitrary params (e.g. wallet/user id, campaign_id, task_id) forwarded verbatim to the quests-engine's GET /quests/status."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/quests/leaderboard": {
      "get": {
        "summary": "Quest leaderboard",
        "description": "Returns the participant leaderboard for a campaign/project from the quests engine, scoped to the calling app. Query params forwarded verbatim.",
        "tags": [
          "Trading API: Quests"
        ],
        "operationId": "quests-leaderboard",
        "parameters": [
          {
            "name": "<engine filters>",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Arbitrary params (e.g. campaign_id, project_id, limit) forwarded verbatim to the quests-engine's GET /quests/leaderboard."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/quests/usage": {
      "get": {
        "summary": "Quests usage",
        "description": "Returns the quests engine's per-app usage/metering snapshot (verify counts, etc.), scoped to the calling app. Free — not credit-charged (paths ending in /usage cost 0). Query params forwarded verbatim.",
        "tags": [
          "Trading API: Quests"
        ],
        "operationId": "quests-usage",
        "parameters": [
          {
            "name": "<engine filters>",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Arbitrary params (e.g. window/period) forwarded verbatim to the quests-engine's GET /quests/usage."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/settings": {
      "get": {
        "summary": "Get user settings",
        "description": "Returns the full settings dump for the tenant user resolved from the X-User-Ref header (slippage, gas, MEV flags, quick buy/sell presets, PNL card prefs, withdraw address). Per-tenant: the user is resolved from X-User-Ref scoped to the calling app.",
        "tags": [
          "Trading API: Account & Profile"
        ],
        "operationId": "settings-get",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      },
      "put": {
        "summary": "Update user settings (batch)",
        "description": "Batch-updates any subset of user settings — only fields present in the JSON body are applied, omitted fields are left unchanged. Each field is validated and written independently; the response reports which fields were updated and any per-field errors. Per-tenant: user resolved from X-User-Ref.",
        "tags": [
          "Trading API: Account & Profile"
        ],
        "operationId": "settings-update",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "locale": {
                    "type": "string",
                    "description": "UI locale. Must be one of en, ru, zh-CN, es."
                  },
                  "buy_slippage_bps": {
                    "type": "string",
                    "description": "Buy slippage in bps, 0-10000."
                  },
                  "sell_slippage_bps": {
                    "type": "string",
                    "description": "Sell slippage in bps, 0-10000."
                  },
                  "priority_fee_lamports": {
                    "type": "string",
                    "description": "Priority fee in lamports, must be >= 0."
                  },
                  "gas_cu_price": {
                    "type": "string",
                    "description": "Compute-unit price, must be >= 0."
                  },
                  "gas_cu_limit": {
                    "type": "string",
                    "description": "Compute-unit limit, must be >= 0 (written via raw SQL)."
                  },
                  "gas_tip": {
                    "type": "string",
                    "description": "Gas tip in SOL, must be >= 0 (written via raw SQL)."
                  },
                  "mev_protect_buy": {
                    "type": "string",
                    "description": "Enable MEV protection on buys."
                  },
                  "mev_protect_sell": {
                    "type": "string",
                    "description": "Enable MEV protection on sells."
                  },
                  "sell_protection": {
                    "type": "string",
                    "description": "Enable sell protection."
                  },
                  "confirm_trades": {
                    "type": "string",
                    "description": "Require trade confirmation dialog."
                  },
                  "pnl_cards_enabled": {
                    "type": "string",
                    "description": "Enable PNL cards."
                  },
                  "pnl_cards_hide_losses": {
                    "type": "string",
                    "description": "Hide losing trades on PNL cards."
                  },
                  "pnl_cards_hide_amounts": {
                    "type": "string",
                    "description": "Hide amounts on PNL cards."
                  },
                  "pnl_cards_show_qr": {
                    "type": "string",
                    "description": "Show QR code on PNL cards."
                  },
                  "autosell_profile_id": {
                    "type": "string",
                    "description": "Autosell profile id. Nested-optional: omit = skip, null = clear, value = set."
                  },
                  "withdraw_address": {
                    "type": "string",
                    "description": "Withdraw destination. Nested-optional: omit = skip, null or empty string = clear, value = set."
                  }
                },
                "required": []
              }
            }
          }
        }
      }
    },
    "/v1/settings/buy-amounts": {
      "put": {
        "summary": "Set quick-buy amounts",
        "description": "Sets the 5 quick-buy preset amounts (in lamports) for the tenant user. Requires exactly 5 positive values; writes them to buy_amount_1..5 (1-based index). Per-tenant: user resolved from X-User-Ref.",
        "tags": [
          "Trading API: Account & Profile"
        ],
        "operationId": "settings-set-buy-amounts",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "amounts": {
                    "type": "string",
                    "description": "Exactly 5 buy amounts in lamports, each > 0."
                  }
                },
                "required": [
                  "amounts"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/settings/sell-percents": {
      "put": {
        "summary": "Set quick-sell percentages",
        "description": "Sets the 4 quick-sell preset percentages for the tenant user. Requires exactly 4 values each in 1-100; writes them to sell_percent_1..4 (1-based index). Per-tenant: user resolved from X-User-Ref.",
        "tags": [
          "Trading API: Account & Profile"
        ],
        "operationId": "settings-set-sell-percents",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "percents": {
                    "type": "string",
                    "description": "Exactly 4 sell percentages, each 1-100."
                  }
                },
                "required": [
                  "percents"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/settings/reset-buy": {
      "post": {
        "summary": "Reset buy settings",
        "description": "Resets the tenant user's buy settings (quick-buy amounts, default buy amount, buy slippage) to system defaults. Per-tenant: user resolved from X-User-Ref.",
        "tags": [
          "Trading API: Account & Profile"
        ],
        "operationId": "settings-reset-buy",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/settings/reset-sell": {
      "post": {
        "summary": "Reset sell settings",
        "description": "Resets the tenant user's sell settings (quick-sell percentages and sell slippage) to system defaults. Per-tenant: user resolved from X-User-Ref.",
        "tags": [
          "Trading API: Account & Profile"
        ],
        "operationId": "settings-reset-sell",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/rewards/profile": {
      "get": {
        "summary": "Get rewards profile",
        "description": "Returns the calling user's XP, level, daily streak, referral code, and unclaimed cashback/referral balances, plus computed progress toward the next level. Scoped to the authenticated user (resolved from X-User-Ref); auto-creates a rewards row on first access.",
        "tags": [
          "Trading API: Account & Profile"
        ],
        "operationId": "rewards-profile",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/rewards/achievements": {
      "get": {
        "summary": "List achievements",
        "description": "Returns the full achievement catalog merged with the calling user's unlock status and unlock timestamps. Scoped to the authenticated user (resolved from X-User-Ref).",
        "tags": [
          "Trading API: Account & Profile"
        ],
        "operationId": "rewards-achievements",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/rewards/referral-stats": {
      "get": {
        "summary": "Get referral stats",
        "description": "Returns the calling user's multi-level referral tree stats (per-depth commission earned and user counts) plus the direct (depth-1) referral count. Scoped to the authenticated user.",
        "tags": [
          "Trading API: Account & Profile"
        ],
        "operationId": "rewards-referral-stats",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/rewards/leaderboard": {
      "get": {
        "summary": "XP leaderboard",
        "description": "Returns the top users ranked by XP descending. PII-safe: raw telegram_id is never exposed — each entry gets a rank-derived anon handle (\"anon-1\", \"anon-2\",...). App-wide (not per-user).",
        "tags": [
          "Trading API: Account & Profile"
        ],
        "operationId": "rewards-leaderboard",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Max entries to return; defaults to 10, capped at 100."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/rewards/levels": {
      "get": {
        "summary": "List level definitions",
        "description": "Returns all reward level definitions with their XP thresholds and names. Static catalog — no user context.",
        "tags": [
          "Trading API: Account & Profile"
        ],
        "operationId": "rewards-levels",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/invite/create": {
      "post": {
        "summary": "Create invite code",
        "description": "Creates a new invite/referral code owned by the calling tenant user (resolved from X-User-Ref via the request context). The code, optional label, max_uses (default 1), and optional expiry are persisted under created_by = caller.",
        "tags": [
          "Trading API: Account & Profile"
        ],
        "operationId": "invite-create",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "code": {
                    "type": "string",
                    "description": "The invite code string to create. Required and must be non-empty."
                  },
                  "label": {
                    "type": "string",
                    "description": "Optional human label for the code."
                  },
                  "max_uses": {
                    "type": "string",
                    "description": "Max redemptions allowed. Defaults to 1 if omitted."
                  },
                  "expires_at": {
                    "type": "string",
                    "description": "Optional Unix epoch (seconds) expiry timestamp."
                  }
                },
                "required": [
                  "code"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/invite/list": {
      "get": {
        "summary": "List my invite codes",
        "description": "Lists the CALLER's invite codes with usage stats, scoped to created_by = caller (v0.7.221 fix; previously leaked every code system-wide). Returns each code with label, counts, active flag, and timestamps.",
        "tags": [
          "Trading API: Account & Profile"
        ],
        "operationId": "invite-list",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/invite/use": {
      "post": {
        "summary": "Redeem invite code",
        "description": "Validates and consumes an invite code for the calling user, then marks the user alpha-approved. Validation + consumption is atomic; on success the caller gains alpha access.",
        "tags": [
          "Trading API: Account & Profile"
        ],
        "operationId": "invite-use",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "code": {
                    "type": "string",
                    "description": "The invite code to redeem. Required and must be non-empty."
                  }
                },
                "required": [
                  "code"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/invite/revoke": {
      "post": {
        "summary": "Revoke invite code",
        "description": "Deactivates one of the CALLER's invite codes, scoped via WHERE created_by = caller (v0.7.221 fix). Non-owners get a generic 'not found or already revoked' message regardless of whether the code exists.",
        "tags": [
          "Trading API: Account & Profile"
        ],
        "operationId": "invite-revoke",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "code": {
                    "type": "string",
                    "description": "The invite code to revoke. Required and must be non-empty."
                  }
                },
                "required": [
                  "code"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/invite/alpha-users": {
      "get": {
        "summary": "List my codes' alpha redemptions",
        "description": "Lists recent alpha-approved redemptions of the CALLER's invite codes only (SQL JOIN scoped to creator, v0.7.223 fix #5). telegram_id is stripped from every row (PII leak fix); only the redeeming code and timestamp are returned.",
        "tags": [
          "Trading API: Account & Profile"
        ],
        "operationId": "invite-alpha-users",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Max rows to return. Defaults to 20, capped at 500."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/invite/stats": {
      "get": {
        "summary": "My invite stats",
        "description": "Returns aggregate invite stats scoped to the CALLER's codes only (v0.7.221 fix; previously exposed platform-wide user counts and the full code list). No platform-wide counts are exposed.",
        "tags": [
          "Trading API: Account & Profile"
        ],
        "operationId": "invite-stats",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/invite/check": {
      "get": {
        "summary": "Check alpha approval",
        "description": "Checks whether the current user is alpha-approved. Resolves the user id from the request extensions (require_user) rather than the tenancy ctx.",
        "tags": [
          "Trading API: Account & Profile"
        ],
        "operationId": "invite-check",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/tickets/create": {
      "post": {
        "summary": "Create support ticket",
        "description": "Opens a new support ticket for the authenticated tenant user. The active wallet address (if any) is auto-resolved and attached; username is null under API-key auth.",
        "tags": [
          "Trading API: Account & Profile"
        ],
        "operationId": "tickets-create",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "message": {
                    "type": "string",
                    "description": "Ticket body. Must be non-empty (trimmed)."
                  }
                },
                "required": [
                  "message"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/tickets/list": {
      "get": {
        "summary": "List my tickets",
        "description": "Returns the calling user's tickets, most recent first (capped at 10 by the DB layer). Scoped to the authenticated telegram_id; never returns other users' tickets.",
        "tags": [
          "Trading API: Account & Profile"
        ],
        "operationId": "tickets-list",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/tickets/stats": {
      "get": {
        "summary": "Ticket counts",
        "description": "Returns the calling user's ticket counts: total plus per-status buckets (open, replied, closed). All counts are scoped to the caller's telegram_id (platform-wide totals were removed in v0.7.251 to prevent cross-tenant volume leakage).",
        "tags": [
          "Trading API: Account & Profile"
        ],
        "operationId": "tickets-stats",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/tickets/{id}": {
      "get": {
        "summary": "Get ticket by id",
        "description": "Fetches a single ticket by id, ownership-enforced at the SQL layer. A request for another user's ticket returns 'Ticket not found' identically to a nonexistent id (no existence leak).",
        "tags": [
          "Trading API: Account & Profile"
        ],
        "operationId": "tickets-get",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Ticket id (i64). Must belong to the calling user."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/tickets/{id}/close": {
      "post": {
        "summary": "Close ticket",
        "description": "Closes one of the caller's tickets. Ownership is enforced in the WHERE clause; returns 'Ticket not found' for another user's id and 'already closed' if the caller's ticket is already inactive.",
        "tags": [
          "Trading API: Account & Profile"
        ],
        "operationId": "tickets-close",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Ticket id (i64) to close. Must belong to the calling user."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/fees/summary": {
      "get": {
        "summary": "Fee summary",
        "description": "Returns the calling app's total platform fees collected with a buy/sell breakdown and effective fee rate. Scoped per-tenant via api_app_users.app_id (platform-wide totals are not exposed).",
        "tags": [
          "Trading API: Fees, PnL & Positions"
        ],
        "operationId": "fees-summary",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/fees/by-source": {
      "get": {
        "summary": "Fees by source",
        "description": "Returns the calling app's fee revenue broken down by trade source (manual, dca, limit, copy_trade, tg_auto, x_auto, afk, etc.). Scoped to ctx.app_id; the legacy app_id query param is accepted but ignored.",
        "tags": [
          "Trading API: Fees, PnL & Positions"
        ],
        "operationId": "fees-by-source",
        "parameters": [
          {
            "name": "app_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Accepted for backward compat but IGNORED — scope is always the caller's own app_id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/fees/hourly": {
      "get": {
        "summary": "Fees hourly",
        "description": "Returns the calling app's fee collection bucketed by hour over a lookback window. Scoped per-tenant via api_app_users.app_id.",
        "tags": [
          "Trading API: Fees, PnL & Positions"
        ],
        "operationId": "fees-hourly",
        "parameters": [
          {
            "name": "hours",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Hours to look back (default 24, must be 1–720)."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/fees/rates": {
      "get": {
        "summary": "Fee rates",
        "description": "Returns the current platform fee BPS rates per trade source and the treasury wallet, read from server environment config. Not tenant-specific (global server config).",
        "tags": [
          "Trading API: Fees, PnL & Positions"
        ],
        "operationId": "fees-rates",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/pnl/positions": {
      "get": {
        "summary": "List open positions (PNL)",
        "description": "Returns all currently open positions for the caller's active wallet, each aggregated from its success trades (total buy/sell amounts, buy/sell counts, average entry price in USD and SOL, total tips). Tenant-scoped: resolves user_id from X-User-Ref to the active wallet_id; returns an empty list if the user has no wallet yet.",
        "tags": [
          "Trading API: Fees, PnL & Positions"
        ],
        "operationId": "pnl-open-positions",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/pnl/position": {
      "get": {
        "summary": "Open position detail (PNL)",
        "description": "Returns the single open position for a given mint on the caller's active wallet, with aggregated trade stats (total buys/sells in lamports, buy/sell counts) plus position metadata. Tenant-scoped via X-User-Ref → active wallet_id.",
        "tags": [
          "Trading API: Fees, PnL & Positions"
        ],
        "operationId": "pnl-position-detail",
        "parameters": [
          {
            "name": "mint",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Token mint address (required, non-empty)."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/pnl/history": {
      "get": {
        "summary": "Closed position history (realized PNL)",
        "description": "Returns closed positions for the caller's active wallet with realized PNL (SOL lamports + USD, percent returns, costs, proceeds, fees, tips), most recent first. Tenant-scoped via X-User-Ref → active wallet_id.",
        "tags": [
          "Trading API: Fees, PnL & Positions"
        ],
        "operationId": "pnl-closed-history",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Max results, default 50, clamped to 1..200."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/positions/list": {
      "get": {
        "summary": "List open positions",
        "description": "Returns all open positions for the authenticated user's active wallet, aggregated from the positions+trades join (total buys/sells in lamports, buy/sell counts, average entry price in USD and SOL, total tips). Tenant-scoped: resolves user_id from the request context and the wallet via the active wallet; if no wallet is found it returns an empty list rather than an error.",
        "tags": [
          "Trading API: Fees, PnL & Positions"
        ],
        "operationId": "positions-list",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/positions/{id}/trades": {
      "get": {
        "summary": "List trades for a position",
        "description": "Returns every trade belonging to a specific position id, ordered oldest-first. Ownership is enforced by joining trades to positions and filtering on the caller's resolved wallet_id, so a position id belonging to another tenant returns an empty trades list. If the caller has no active wallet it returns 404.",
        "tags": [
          "Trading API: Fees, PnL & Positions"
        ],
        "operationId": "positions-position-trades",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Position id (i32) to fetch trades for. Scoped to the caller's wallet via JOIN."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/positions/pnl-card": {
      "post": {
        "summary": "(Not yet available) Generate PNL card",
        "description": "Intended to render a PNL card PNG, but requires a separate image-rendering service not available in DB-only mode, so it always returns 501.",
        "tags": [
          "Trading API: Fees, PnL & Positions"
        ],
        "operationId": "positions-pnl-card",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "body": {
                    "type": "string",
                    "description": "Arbitrary JSON body (accepted but ignored; the handler returns 501 before reading it)."
                  }
                },
                "required": []
              }
            }
          }
        }
      }
    },
    "/v1/positions/trades": {
      "get": {
        "summary": "List trades by token mint",
        "description": "Returns all trades for a given token mint across the caller's active wallet (via db.get_trades_by_token). The ?mint= query parameter is required. If the caller has no active wallet it returns an empty trades list rather than an error.",
        "tags": [
          "Trading API: Fees, PnL & Positions"
        ],
        "operationId": "positions-trades-by-mint",
        "parameters": [
          {
            "name": "mint",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Token mint address to filter trades by. Required and must be non-empty."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/indexer/token": {
      "get": {
        "summary": "Get indexed token metadata",
        "description": "Looks up a single token in the in-process indexer by mint and returns its on-chain metadata (name/symbol/decimals/token_program/uri/supply/creator/source). Read-only the database query against the indexer's 460K+ token cache.",
        "tags": [
          "Trading API: Indexer"
        ],
        "operationId": "indexer-token",
        "parameters": [
          {
            "name": "mint",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Token mint address to look up"
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/indexer/pool": {
      "get": {
        "summary": "Get indexed pool by mint",
        "description": "Returns the latest indexed pool for a mint, or a specific DEX's pool when dex_type is supplied (synonyms normalized). Carries pool_address, vaults, token programs, raw dex_data, creator and launch slot/signature/block_time for fast pool-param lookups.",
        "tags": [
          "Trading API: Indexer"
        ],
        "operationId": "indexer-pool",
        "parameters": [
          {
            "name": "mint",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Token mint address"
          },
          {
            "name": "dex_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Optional DEX filter (canonical or synonym, e.g. pumpfun/pump, raydium_cpmm/raycpmm, orca/whirlpool). When omitted, returns the most recently indexed pool for the mint."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/indexer/pool-by-address": {
      "get": {
        "summary": "Get indexed pool by address",
        "description": "Looks up a single indexed pool directly by its on-chain pool/pair address and returns the same pool row shape as /indexer/pool.",
        "tags": [
          "Trading API: Indexer"
        ],
        "operationId": "indexer-pool-by-address",
        "parameters": [
          {
            "name": "address",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Pool/pair on-chain address"
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/indexer/recent-tokens": {
      "get": {
        "summary": "List recent indexed tokens",
        "description": "Returns the most recently indexed tokens, optionally filtered to one DEX. Sorted by indexed_at DESC. Returns lightweight token metadata rows (no price/metrics).",
        "tags": [
          "Trading API: Indexer"
        ],
        "operationId": "indexer-recent-tokens",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Max rows, default 20, clamped to 1..200"
          },
          {
            "name": "dex_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Optional DEX filter (canonical or synonym). When omitted, returns recent tokens across all DEXes."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/indexer/recent-by-dex": {
      "get": {
        "summary": "Recent tokens grouped by DEX (metrics-enriched)",
        "description": "Returns the most recent tokens for every supported DEX in one call, grouped by DEX name, each enriched with token_metrics (price/mcap/liquidity/rolling-window volume + swap counts) and resolved off-chain metadata (image/socials/description). USD values computed server-side from the cached SOL/USD price.",
        "tags": [
          "Trading API: Indexer"
        ],
        "operationId": "indexer-recent-by-dex",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Max rows per DEX, default 5, clamped to 1..50"
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/indexer/recent-pools": {
      "get": {
        "summary": "List recent pool launches",
        "description": "Pool launches sorted by indexer insertion time (DESC), LEFT JOIN'd with indexed_tokens so name/symbol/uri are included once enrichment lands. Each row has a launch tx signature to deep-link to Solscan. Optional DEX filter validated against the canonical allow-list.",
        "tags": [
          "Trading API: Indexer"
        ],
        "operationId": "indexer-recent-pools",
        "parameters": [
          {
            "name": "dex_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Optional DEX filter (canonical or synonym; validated against the allow-list). When omitted, returns launches across all DEXes."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Max rows (default 50; not clamped here, passed to the query)"
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/indexer/search": {
      "get": {
        "summary": "Search tokens",
        "description": "Case-insensitive LIKE search over indexed tokens by name/symbol/mint, returning DB-metric-enriched results (price_sol, volume_24h_usd, liquidity_usd, mcap_usd) sorted by the chosen key. USD values computed from the cached SOL/USD price.",
        "tags": [
          "Trading API: Indexer"
        ],
        "operationId": "indexer-search",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Search query (alias: query). Required and non-empty."
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Sort key, default 'mc' (market cap)"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Max rows, default 10, capped at 50"
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/indexer/stats": {
      "get": {
        "summary": "Indexer statistics",
        "description": "Returns aggregate indexer counters: total/enriched/pending/failed pools, total tokens, and a per-DEX pool-count breakdown.",
        "tags": [
          "Trading API: Indexer"
        ],
        "operationId": "indexer-stats",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/indexer/tokens/batch": {
      "post": {
        "summary": "Batch token lookup",
        "description": "Enriches up to 100 mints in one round-trip, returning a map of mint to its full token row. Mints not found are omitted from the map (not null-valued) so callers can detect coverage gaps cheaply.",
        "tags": [
          "Trading API: Indexer"
        ],
        "operationId": "indexer-tokens-batch",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "mints": {
                    "type": "string",
                    "description": "Token mint addresses to look up (max 100). Empty array returns an empty map."
                  }
                },
                "required": [
                  "mints"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/limit/create": {
      "post": {
        "summary": "Create limit order",
        "description": "Creates a limit/conditional order row in the limit_orders table for the calling tenant's active wallet (price/schedule/event trigger, buy or sell). DB-only write; no on-chain action — execution is handled later by the bot's PriceMonitor service. Scoped to the user resolved from the API key + X-User-Ref.",
        "tags": [
          "Trading API: Limit Orders & DCA"
        ],
        "operationId": "limit-create",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "mint": {
                    "type": "string",
                    "description": "Token mint address."
                  },
                  "amount_sol": {
                    "type": "string",
                    "description": "Order size in SOL (converted to lamports). Required — 422 if omitted."
                  },
                  "trigger_type": {
                    "type": "string",
                    "description": "One of price | schedule | event. Default 'price'."
                  },
                  "trigger_price_usd": {
                    "type": "string",
                    "description": "Target USD price for price triggers (stored as 0.0 if omitted)."
                  },
                  "trigger_time_seconds": {
                    "type": "string",
                    "description": "For trigger_type=schedule: seconds from now until trigger_at."
                  },
                  "event_type": {
                    "type": "string",
                    "description": "For trigger_type=event: event name (e.g. 'migration'). Stored as trigger_direction 'event:<event_type>'. Defaults to 'migration'."
                  },
                  "slippage_bps": {
                    "type": "string",
                    "description": "Slippage tolerance in bps. Default 1000."
                  },
                  "mev_protect": {
                    "type": "string",
                    "description": "Route via MEV-protected providers. Default true."
                  },
                  "expiry_seconds": {
                    "type": "string",
                    "description": "Seconds until the order expires. Default 86400 (24h)."
                  },
                  "side": {
                    "type": "string",
                    "description": "buy | sell. Default 'buy'. Determines trigger_direction (sell=below, buy=above) for price triggers."
                  },
                  "sell_percent": {
                    "type": "string",
                    "description": "For sell orders: percent of holdings to sell."
                  },
                  "trailing_pct": {
                    "type": "string",
                    "description": "Trailing stop percentage (optional)."
                  },
                  "max_retries": {
                    "type": "string",
                    "description": "Max execution retries. Default 0."
                  }
                },
                "required": [
                  "mint",
                  "amount_sol"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/limit/list": {
      "get": {
        "summary": "List pending limit orders",
        "description": "Returns all pending limit orders for the calling tenant's user. Read from the limit_orders table, scoped to the resolved user id.",
        "tags": [
          "Trading API: Limit Orders & DCA"
        ],
        "operationId": "limit-list",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/limit/monitor": {
      "get": {
        "summary": "(Not yet available) Limit monitor status",
        "description": "Intended to report PriceMonitor execution status. Not yet wired in the multi-tenant API — returns 501.",
        "tags": [
          "Trading API: Limit Orders & DCA"
        ],
        "operationId": "limit-monitor",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/limit/all": {
      "delete": {
        "summary": "Cancel all limit orders",
        "description": "Cancels every pending limit order for the calling tenant's user. Scoped to the resolved user id.",
        "tags": [
          "Trading API: Limit Orders & DCA"
        ],
        "operationId": "limit-cancel-all",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/limit/{id}": {
      "get": {
        "summary": "Get limit order",
        "description": "Fetches a single limit order by id, scoped to the calling tenant's user (cross-user access blocked by user_id filter).",
        "tags": [
          "Trading API: Limit Orders & DCA"
        ],
        "operationId": "limit-get-order",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Limit order id (i64)."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      },
      "delete": {
        "summary": "Cancel limit order",
        "description": "Cancels a single pending limit order by id, scoped to the calling tenant's user. Idempotent per order (cancelling an already-cancelled/unknown order returns success=false).",
        "tags": [
          "Trading API: Limit Orders & DCA"
        ],
        "operationId": "limit-cancel",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Limit order id (i64)."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/dca/create": {
      "post": {
        "summary": "(Not yet available) Create DCA order",
        "description": "Intended to create a recurring dollar-cost-average buy/sell order for the authenticated tenant. Currently a 501 stub: it requires rpc/indexer resources that are not yet wired into V1State (P1 Group C), so it always returns NOT_IMPLEMENTED.",
        "tags": [
          "Trading API: Limit Orders & DCA"
        ],
        "operationId": "dca-create",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "mint": {
                    "type": "string",
                    "description": "Token mint address to DCA into/out of."
                  },
                  "amount_sol": {
                    "type": "string",
                    "description": "SOL amount per interval (buy side)."
                  },
                  "interval_seconds": {
                    "type": "string",
                    "description": "Seconds between each DCA execution."
                  },
                  "total_orders": {
                    "type": "string",
                    "description": "Total number of orders to execute before the schedule completes."
                  },
                  "min_price": {
                    "type": "string",
                    "description": "Lower price guard (USD); skip execution below this."
                  },
                  "max_price": {
                    "type": "string",
                    "description": "Upper price guard (USD); skip execution above this."
                  },
                  "slippage_bps": {
                    "type": "string",
                    "description": "Slippage tolerance in basis points. Default 1000."
                  },
                  "mev_protect": {
                    "type": "string",
                    "description": "Route via MEV-protected providers. Default true."
                  },
                  "duration_seconds": {
                    "type": "string",
                    "description": "Overall lifetime of the schedule in seconds before it expires."
                  },
                  "side": {
                    "type": "string",
                    "description": "DCA direction: 'buy' or 'sell'. Default 'buy'."
                  },
                  "sell_percent": {
                    "type": "string",
                    "description": "Percent of holdings to sell each interval (sell side)."
                  }
                },
                "required": [
                  "mint",
                  "interval_seconds"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/dca/list": {
      "get": {
        "summary": "List DCA orders",
        "description": "Returns all active and paused DCA orders for the authenticated tenant (resolved from X-User-Ref via the tenancy layer). Active orders are listed first, then paused.",
        "tags": [
          "Trading API: Limit Orders & DCA"
        ],
        "operationId": "dca-list",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/dca/{id}": {
      "get": {
        "summary": "Get DCA order",
        "description": "Returns a single DCA order by id, scoped to the authenticated tenant (dca_get_by_id filters by user). Returns success:false with 'Order not found' if it does not exist or belongs to another tenant.",
        "tags": [
          "Trading API: Limit Orders & DCA"
        ],
        "operationId": "dca-get-order",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "DCA order id (i64)."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      },
      "delete": {
        "summary": "Cancel DCA order",
        "description": "Cancels a single DCA order owned by the authenticated tenant (dca_cancel filters by user). Idempotent at the data level — already-cancelled orders return not-found.",
        "tags": [
          "Trading API: Limit Orders & DCA"
        ],
        "operationId": "dca-cancel",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "DCA order id (i64)."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/dca/{id}/pause": {
      "post": {
        "summary": "Pause DCA order",
        "description": "Pauses an active DCA order owned by the authenticated tenant (dca_pause filters by user). No further executions occur until resumed.",
        "tags": [
          "Trading API: Limit Orders & DCA"
        ],
        "operationId": "dca-pause",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "DCA order id (i64)."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/dca/{id}/resume": {
      "post": {
        "summary": "Resume DCA order",
        "description": "Resumes a paused DCA order owned by the authenticated tenant (dca_resume filters by user). Re-enables scheduled executions.",
        "tags": [
          "Trading API: Limit Orders & DCA"
        ],
        "operationId": "dca-resume",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "DCA order id (i64)."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/dca/all": {
      "delete": {
        "summary": "Cancel all DCA orders",
        "description": "Cancels every DCA order for the authenticated tenant (dca_cancel_all scoped by user) and returns how many were cancelled.",
        "tags": [
          "Trading API: Limit Orders & DCA"
        ],
        "operationId": "dca-cancel-all",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/copy-trade/start": {
      "post": {
        "summary": "(Not yet available) Start copy-trade service",
        "description": "Intended to start the live copy-trading engine for the caller. Currently a 501 stub — the copy-trade runtime service is not wired into V1State in this deployment.",
        "tags": [
          "Trading API: Copy Trade"
        ],
        "operationId": "copytrade-start",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/copy-trade/stop": {
      "post": {
        "summary": "(Not yet available) Stop copy-trade service",
        "description": "Intended to stop the live copy-trading engine for the caller. Currently a 501 stub — the copy-trade runtime service is not wired into V1State.",
        "tags": [
          "Trading API: Copy Trade"
        ],
        "operationId": "copytrade-stop",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/copy-trade/status": {
      "get": {
        "summary": "(Not yet available) Copy-trade service status (caller)",
        "description": "Intended to report the caller's copy-trade engine status. Currently a 501 stub — requires the live copy-trade service not wired into V1State.",
        "tags": [
          "Trading API: Copy Trade"
        ],
        "operationId": "copytrade-status",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/copy-trade/system-status": {
      "get": {
        "summary": "(Not yet available) Copy-trade system status",
        "description": "Intended to report global copy-trade engine/system health. Currently a 501 stub — requires the live copy-trade service not wired into V1State.",
        "tags": [
          "Trading API: Copy Trade"
        ],
        "operationId": "copytrade-system-status",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/copy-trade/add-source": {
      "post": {
        "summary": "(Not yet available) Add copy-trade source wallet",
        "description": "Intended to register a source wallet to follow. Currently a 501 stub — requires the live copy-trade service not wired into V1State; the body is accepted but ignored.",
        "tags": [
          "Trading API: Copy Trade"
        ],
        "operationId": "copytrade-add-source",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "source_id": {
                    "type": "string",
                    "description": "Source id to attach."
                  },
                  "wallet_address": {
                    "type": "string",
                    "description": "Solana wallet address of the source to follow."
                  }
                },
                "required": [
                  "source_id",
                  "wallet_address"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/copy-trade/remove-source": {
      "post": {
        "summary": "(Not yet available) Remove copy-trade source wallet",
        "description": "Intended to unregister a source wallet. Currently a 501 stub — requires the live copy-trade service not wired into V1State; the body is accepted but ignored.",
        "tags": [
          "Trading API: Copy Trade"
        ],
        "operationId": "copytrade-remove-source",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "source_id": {
                    "type": "string",
                    "description": "Source id to remove."
                  }
                },
                "required": [
                  "source_id"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/copy-trade/create-config": {
      "post": {
        "summary": "Create copy-trade config",
        "description": "Creates a new copy-trade config for the caller's active wallet following the given source wallet, then activates it. Scoped to the X-User-Ref tenant; uses BuyMode::Fixed with buy_amount_sol.",
        "tags": [
          "Trading API: Copy Trade"
        ],
        "operationId": "copytrade-create-config",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "source_wallet": {
                    "type": "string",
                    "description": "Solana pubkey of the wallet to copy."
                  },
                  "buy_amount_sol": {
                    "type": "string",
                    "description": "Fixed SOL amount per copied buy. Must be between 0.001 and 100."
                  },
                  "buy_slippage_bps": {
                    "type": "string",
                    "description": "Buy slippage in bps. Defaults to 1000 (10%)."
                  },
                  "sell_slippage_bps": {
                    "type": "string",
                    "description": "Sell slippage in bps. Defaults to 1000 (10%)."
                  },
                  "name": {
                    "type": "string",
                    "description": "Config label. Defaults to 'API Config'."
                  },
                  "observe_only": {
                    "type": "string",
                    "description": "If true, config observes/logs without executing trades. Defaults to false."
                  }
                },
                "required": [
                  "source_wallet",
                  "buy_amount_sol"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/copy-trade/delete-config": {
      "post": {
        "summary": "Delete copy-trade config",
        "description": "Deletes one of the caller's copy-trade configs by id. Ownership-scoped to the X-User-Ref tenant (ct_delete_config filters by user).",
        "tags": [
          "Trading API: Copy Trade"
        ],
        "operationId": "copytrade-delete-config",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "config_id": {
                    "type": "string",
                    "description": "Id of the config to delete."
                  }
                },
                "required": [
                  "config_id"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/copy-trade/configs": {
      "get": {
        "summary": "List copy-trade configs",
        "description": "Lists all copy-trade configs owned by the caller (X-User-Ref tenant), each fully serialized via config_to_json.",
        "tags": [
          "Trading API: Copy Trade"
        ],
        "operationId": "copytrade-list-configs",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/copy-trade/config/{id}": {
      "get": {
        "summary": "Get copy-trade config",
        "description": "Returns one copy-trade config by id, fully serialized. Ownership-scoped to the X-User-Ref tenant (ct_get_config filters by user).",
        "tags": [
          "Trading API: Copy Trade"
        ],
        "operationId": "copytrade-get-config",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      },
      "put": {
        "summary": "Update copy-trade config",
        "description": "Partial update of a copy-trade config — every body field is optional and only provided fields are applied. Ownership-scoped; returns the full updated config.",
        "tags": [
          "Trading API: Copy Trade"
        ],
        "operationId": "copytrade-update-config",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "buy_mode": {
                    "type": "string",
                    "description": "One of: fixed, exact, percent."
                  },
                  "buy_amount_sol": {
                    "type": "string",
                    "description": "Fixed buy amount in SOL (converted to lamports)."
                  },
                  "buy_percent": {
                    "type": "string",
                    "description": "Percent buy size (used with buy_mode=percent)."
                  },
                  "max_buy_amount_sol": {
                    "type": "string",
                    "description": "Cap per buy in SOL."
                  },
                  "min_trigger_buy_sol": {
                    "type": "string",
                    "description": "Min source-buy size (SOL) to trigger a copy."
                  },
                  "max_trigger_buy_sol": {
                    "type": "string",
                    "description": "Max source-buy size (SOL) to trigger a copy."
                  },
                  "buy_slippage_bps": {
                    "type": "string",
                    "description": "Buy slippage in bps."
                  },
                  "sell_slippage_bps": {
                    "type": "string",
                    "description": "Sell slippage in bps."
                  },
                  "buy_priority_fee": {
                    "type": "string",
                    "description": "Buy priority fee (lamports)."
                  },
                  "sell_priority_fee": {
                    "type": "string",
                    "description": "Sell priority fee (lamports)."
                  },
                  "buy_tip": {
                    "type": "string",
                    "description": "Buy MEV tip (lamports)."
                  },
                  "sell_tip": {
                    "type": "string",
                    "description": "Sell MEV tip (lamports)."
                  },
                  "copy_buys": {
                    "type": "string",
                    "description": "Copy source buys."
                  },
                  "copy_sells": {
                    "type": "string",
                    "description": "Copy source sells."
                  },
                  "follow_sell_percent": {
                    "type": "string",
                    "description": "Mirror source sell percentages."
                  },
                  "buy_protection": {
                    "type": "string",
                    "description": "Enable buy-side protection."
                  },
                  "sell_protection": {
                    "type": "string",
                    "description": "Enable sell-side protection."
                  },
                  "first_interaction_only": {
                    "type": "string",
                    "description": "Only copy first interaction with a token."
                  },
                  "sell_only_copied": {
                    "type": "string",
                    "description": "Only sell tokens that were copy-bought."
                  },
                  "buy_only_once": {
                    "type": "string",
                    "description": "Buy each token at most once."
                  },
                  "skip_deploys": {
                    "type": "string",
                    "description": "Skip token deploy/creation events."
                  },
                  "reverse_mode": {
                    "type": "string",
                    "description": "Reverse-copy (sell when source buys, etc.)."
                  },
                  "sell_on_transfer": {
                    "type": "string",
                    "description": "Sell when source transfers out."
                  },
                  "auto_tip": {
                    "type": "string",
                    "description": "Auto-compute MEV tip."
                  },
                  "observe_only": {
                    "type": "string",
                    "description": "Observe/log without executing."
                  },
                  "reverse_min_sell_percent": {
                    "type": "string",
                    "description": "Min sell percent for reverse mode (u8)."
                  },
                  "start_time": {
                    "type": "string",
                    "description": "Active window start (unix seconds)."
                  },
                  "end_time": {
                    "type": "string",
                    "description": "Active window end (unix seconds)."
                  },
                  "max_buy_count": {
                    "type": "string",
                    "description": "Lifetime cap on buys."
                  },
                  "max_per_token": {
                    "type": "string",
                    "description": "Max buys per token."
                  },
                  "name": {
                    "type": "string",
                    "description": "Config label."
                  },
                  "notify_success": {
                    "type": "string",
                    "description": "Notify on successful copy."
                  },
                  "notify_failed": {
                    "type": "string",
                    "description": "Notify on failed copy."
                  },
                  "notify_skipped": {
                    "type": "string",
                    "description": "Notify on skipped copy."
                  },
                  "notify_filtered": {
                    "type": "string",
                    "description": "Notify on filtered copy."
                  },
                  "autosell_profile_id": {
                    "type": "string",
                    "description": "Attach an autosell profile id; <=0 clears it."
                  }
                },
                "required": []
              }
            }
          }
        }
      }
    },
    "/v1/copy-trade/config/{id}/toggle": {
      "post": {
        "summary": "Toggle copy-trade config active",
        "description": "Activates or deactivates a config. Body must contain the boolean `active`. Ownership-scoped to the X-User-Ref tenant.",
        "tags": [
          "Trading API: Copy Trade"
        ],
        "operationId": "copytrade-toggle-config",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "active": {
                    "type": "string",
                    "description": "true to activate, false to deactivate."
                  }
                },
                "required": [
                  "active"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/copy-trade/config/{id}/reset-count": {
      "post": {
        "summary": "Reset copy-trade buy count",
        "description": "Resets the lifetime buy counter (current_buy_count) for a config. Ownership-scoped to the X-User-Ref tenant.",
        "tags": [
          "Trading API: Copy Trade"
        ],
        "operationId": "copytrade-reset-count",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/copy-trade/config/{id}/blacklist": {
      "get": {
        "summary": "Get config blacklist",
        "description": "Returns the token-mint blacklist for a config. Ownership-scoped to the X-User-Ref tenant.",
        "tags": [
          "Trading API: Copy Trade"
        ],
        "operationId": "copytrade-get-blacklist",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      },
      "post": {
        "summary": "Add mint to config blacklist",
        "description": "Adds a token mint to the config's blacklist (validates the pubkey first). Ownership-scoped to the X-User-Ref tenant.",
        "tags": [
          "Trading API: Copy Trade"
        ],
        "operationId": "copytrade-add-blacklist",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "token_mint": {
                    "type": "string",
                    "description": "Token mint pubkey to blacklist."
                  }
                },
                "required": [
                  "token_mint"
                ]
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Remove mint from config blacklist",
        "description": "Removes a token mint from the config's blacklist. Ownership-scoped to the X-User-Ref tenant.",
        "tags": [
          "Trading API: Copy Trade"
        ],
        "operationId": "copytrade-remove-blacklist",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "token_mint": {
                    "type": "string",
                    "description": "Token mint pubkey to remove."
                  }
                },
                "required": [
                  "token_mint"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/copy-trade/config/{id}/blacklist/clear": {
      "post": {
        "summary": "Clear config blacklist",
        "description": "Removes all entries from the config's blacklist. Ownership-scoped to the X-User-Ref tenant.",
        "tags": [
          "Trading API: Copy Trade"
        ],
        "operationId": "copytrade-clear-blacklist",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/copy-trade/config/{id}/filters": {
      "get": {
        "summary": "Get config filters",
        "description": "Returns the token filter set (mcap, token_age, liquidity ranges + platform allow-list) for a config. Ownership-scoped to the X-User-Ref tenant.",
        "tags": [
          "Trading API: Copy Trade"
        ],
        "operationId": "copytrade-get-filters",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      },
      "put": {
        "summary": "Update config filters",
        "description": "Replaces the config's filter set from min/max bounds for mcap, token age, and liquidity plus a platform allow-list. A range is set only if its min or max is provided. Ownership-scoped to the X-User-Ref tenant.",
        "tags": [
          "Trading API: Copy Trade"
        ],
        "operationId": "copytrade-update-filters",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "mcap_min": {
                    "type": "string",
                    "description": "Min market cap."
                  },
                  "mcap_max": {
                    "type": "string",
                    "description": "Max market cap."
                  },
                  "age_min": {
                    "type": "string",
                    "description": "Min token age."
                  },
                  "age_max": {
                    "type": "string",
                    "description": "Max token age."
                  },
                  "liquidity_min": {
                    "type": "string",
                    "description": "Min liquidity."
                  },
                  "liquidity_max": {
                    "type": "string",
                    "description": "Max liquidity."
                  },
                  "platforms": {
                    "type": "string",
                    "description": "Allowed platforms/DEXes."
                  }
                },
                "required": []
              }
            }
          }
        }
      }
    },
    "/v1/copy-trade/config/{id}/executions": {
      "get": {
        "summary": "List config executions",
        "description": "Returns the copy-trade execution history for a config (source vs. our trade legs, signatures, latency, status). Ownership-scoped to the X-User-Ref tenant.",
        "tags": [
          "Trading API: Copy Trade"
        ],
        "operationId": "copytrade-config-executions",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Config id."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Max rows (default 50, capped at 200)."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Row offset for pagination (default 0)."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/copy-trade/config/{id}/stats": {
      "get": {
        "summary": "Get config stats",
        "description": "Returns aggregate execution stats for one config (totals by outcome, success rate, avg latency). Ownership-scoped to the X-User-Ref tenant.",
        "tags": [
          "Trading API: Copy Trade"
        ],
        "operationId": "copytrade-config-stats",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/copy-trade/config/{id}/metrics": {
      "get": {
        "summary": "(Not yet available) Get config live metrics",
        "description": "Intended to return live runtime metrics for a config. Currently a 501 stub — requires the live copy-trade service not wired into V1State.",
        "tags": [
          "Trading API: Copy Trade"
        ],
        "operationId": "copytrade-config-metrics",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/copy-trade/user-stats": {
      "get": {
        "summary": "Get user copy-trade stats",
        "description": "Returns the caller's aggregate copy-trade stats across all their configs (config counts + execution outcome totals + success rate). Scoped to the X-User-Ref tenant.",
        "tags": [
          "Trading API: Copy Trade"
        ],
        "operationId": "copytrade-user-stats",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/copy-trade/detection-stats": {
      "get": {
        "summary": "(Not yet available) Get copy-trade detection stats",
        "description": "Intended to return source-wallet detection metrics from the live engine. Currently a 501 stub — requires the live copy-trade service not wired into V1State.",
        "tags": [
          "Trading API: Copy Trade"
        ],
        "operationId": "copytrade-detection-stats",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/afk/create-config": {
      "post": {
        "summary": "Create AFK config",
        "description": "Creates a new AFK (auto-buy) config for the calling tenant with the given name. The config is created as a draft (is_saved/is_active default off) and scoped to the X-User-Ref tenant.",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-create-config",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Config display name. Must be non-empty."
                  }
                },
                "required": [
                  "name"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/afk/configs": {
      "get": {
        "summary": "List AFK configs",
        "description": "Returns all AFK configs owned by the calling tenant (resolved from X-User-Ref). Each config is the full serialized AfkConfig object with ~100 filter fields.",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-list-configs",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/afk/config/{id}": {
      "get": {
        "summary": "Get AFK config",
        "description": "Returns a single AFK config by id, scoped to the calling tenant (telegram_id ownership enforced in the DB query). Returns success:false if the config does not belong to the tenant.",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-get-config",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AFK config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      },
      "put": {
        "summary": "Update AFK config field",
        "description": "Updates a single field on an AFK config (one field per call) for the calling tenant. The field name is resolved against the config's column schema (f64/i32/i64/bool/str) plus special handlers for platforms, name, name_exact, name_contains, and time_window_start/end.",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-update-config",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AFK config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "field": {
                    "type": "string",
                    "description": "Column/filter name to update (e.g. buy_amount_sol, mcap_min_sol, platforms, name, time_window_start). Unknown names are rejected."
                  },
                  "value": {
                    "type": "string",
                    "description": "New value as a string; coerced to the column type. \"null\" or \"\" clears nullable filters. For platforms: comma-separated list. For time_window_*: HH:MM or HH:MM:SS."
                  }
                },
                "required": [
                  "field",
                  "value"
                ]
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Delete AFK config",
        "description": "Deletes an AFK config (and its associated lists/stages via DB cascade) for the calling tenant. Ownership enforced by telegram_id in the DB query.",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-delete-config",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AFK config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/afk/config/{id}/toggle": {
      "post": {
        "summary": "Toggle AFK config active",
        "description": "Activates or deactivates an AFK config for the calling tenant. Only configs with is_saved=true can be toggled active (drafts are rejected) — mirrors the UI auto-save-on-activate gate. The engine cache only picks up the flip on next bot restart or UI write.",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-toggle-config",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AFK config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "active": {
                    "type": "string",
                    "description": "Desired active state."
                  }
                },
                "required": [
                  "active"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/afk/executions": {
      "get": {
        "summary": "List AFK executions",
        "description": "Returns the calling tenant's AFK auto-buy execution log (most recent first), optionally filtered by config_id. Each row records the attempted buy, signature, success flag and market snapshot.",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-executions",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Max rows to return. Default 20, capped at 100."
          },
          {
            "name": "config_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter executions to a single config."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/afk/simulate": {
      "post": {
        "summary": "(Not yet available) Simulate AFK filters (stub)",
        "description": "Intended to evaluate a config's filters against a given mint. Currently not implemented in the multi-tenant API — RPC/indexer are not wired into V1State.",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-simulate",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "mint": {
                    "type": "string",
                    "description": "Token mint to simulate against."
                  },
                  "config_id": {
                    "type": "string",
                    "description": "AFK config id to evaluate."
                  }
                },
                "required": [
                  "mint",
                  "config_id"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/afk/config/{id}/whitelist-mints": {
      "get": {
        "summary": "List whitelist mints",
        "description": "Returns the mint-address whitelist for an AFK config (tenant-scoped). When set, only these mints are eligible for auto-buy.",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-get-whitelist-mints",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AFK config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      },
      "post": {
        "summary": "Add whitelist mint",
        "description": "Adds a mint address to an AFK config's whitelist (tenant-scoped).",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-add-whitelist-mint",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AFK config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "address": {
                    "type": "string",
                    "description": "Mint address to whitelist. Must be non-empty."
                  }
                },
                "required": [
                  "address"
                ]
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Clear whitelist mints",
        "description": "Removes all whitelist mint entries from an AFK config (tenant-scoped).",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-clear-whitelist-mints",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AFK config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/afk/config/{id}/whitelist-deployers": {
      "get": {
        "summary": "List whitelist deployers",
        "description": "Returns the deployer-address whitelist for an AFK config (tenant-scoped). When set, only tokens from these deployers are eligible.",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-get-whitelist-deployers",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AFK config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      },
      "post": {
        "summary": "Add whitelist deployer",
        "description": "Adds a deployer address (with optional label) to an AFK config's deployer whitelist (tenant-scoped).",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-add-whitelist-deployer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AFK config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "address": {
                    "type": "string",
                    "description": "Deployer wallet address. Must be non-empty."
                  },
                  "label": {
                    "type": "string",
                    "description": "Optional human label for the deployer."
                  }
                },
                "required": [
                  "address"
                ]
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Clear whitelist deployers",
        "description": "Removes all deployer whitelist entries from an AFK config (tenant-scoped).",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-clear-whitelist-deployers",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AFK config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/afk/config/{id}/blacklist": {
      "get": {
        "summary": "Get blacklist (tokens + devs)",
        "description": "Returns both the token-address and deployer-address blacklists for an AFK config (tenant-scoped) in a single response.",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-get-blacklist",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AFK config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      },
      "post": {
        "summary": "Add to blacklist",
        "description": "Adds a token or deployer address to an AFK config's blacklist (tenant-scoped). list_type selects which list.",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-add-to-blacklist",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AFK config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "list_type": {
                    "type": "string",
                    "description": "Which blacklist: must be \"token\" or \"dev\"."
                  },
                  "address": {
                    "type": "string",
                    "description": "Address to blacklist. Must be non-empty."
                  }
                },
                "required": [
                  "list_type",
                  "address"
                ]
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Clear blacklist",
        "description": "Clears both the token and deployer blacklists for an AFK config (tenant-scoped) in one call.",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-clear-blacklist",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AFK config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/afk/config/{id}/blacklist-words": {
      "get": {
        "summary": "List blacklist words",
        "description": "Returns the name/symbol blacklist words for an AFK config (tenant-scoped). Tokens whose name/symbol match a word are skipped.",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-get-blacklist-words",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AFK config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      },
      "post": {
        "summary": "Add blacklist words",
        "description": "Adds one or more words to an AFK config's name/symbol blacklist (tenant-scoped). Returns how many were newly added vs submitted (dedup).",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-add-blacklist-words",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AFK config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "words": {
                    "type": "string",
                    "description": "Array of words to blacklist. Must be non-empty."
                  }
                },
                "required": [
                  "words"
                ]
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Clear blacklist words",
        "description": "Removes all blacklist words from an AFK config (tenant-scoped).",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-clear-blacklist-words",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AFK config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/afk/config/{id}/sell-stages": {
      "get": {
        "summary": "List sell stages",
        "description": "Returns the laddered auto-sell stages for an AFK config (tenant-scoped). Each stage sells a percentage at a price multiplier.",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-get-sell-stages",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AFK config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      },
      "post": {
        "summary": "Add sell stage",
        "description": "Adds an auto-sell stage (sell_pct at a price multiplier) to an AFK config (tenant-scoped). Validates sell_pct in (0,100] and multiplier > 0.",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-add-sell-stage",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AFK config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "sell_pct": {
                    "type": "string",
                    "description": "Percent of holdings to sell at this stage. Must be > 0 and <= 100."
                  },
                  "multiplier": {
                    "type": "string",
                    "description": "Price multiplier (e.g. 2.0 = 2x) that triggers this stage. Must be > 0."
                  }
                },
                "required": [
                  "sell_pct",
                  "multiplier"
                ]
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Clear sell stages",
        "description": "Removes all auto-sell stages from an AFK config (tenant-scoped).",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-clear-sell-stages",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AFK config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/afk/config/{id}/remove-sell-stage": {
      "post": {
        "summary": "Remove sell stage",
        "description": "Removes a single auto-sell stage from an AFK config by its stage_order (tenant-scoped).",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-remove-sell-stage",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AFK config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "stage_order": {
                    "type": "string",
                    "description": "Order index of the stage to remove."
                  }
                },
                "required": [
                  "stage_order"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/afk/config/{id}/smart-wallets": {
      "get": {
        "summary": "List smart wallets",
        "description": "Returns the smart-wallet list for an AFK config (tenant-scoped). Used with smart_wallet_threshold to require buys from N tracked wallets before auto-buying.",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-get-smart-wallets",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AFK config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      },
      "post": {
        "summary": "Add smart wallet",
        "description": "Adds a smart wallet (with optional label) to an AFK config's tracked wallet list (tenant-scoped).",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-add-smart-wallet",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AFK config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "address": {
                    "type": "string",
                    "description": "Wallet address to track. Must be non-empty."
                  },
                  "label": {
                    "type": "string",
                    "description": "Optional human label for the wallet."
                  }
                },
                "required": [
                  "address"
                ]
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Clear smart wallets",
        "description": "Removes all smart wallets from an AFK config (tenant-scoped).",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-clear-smart-wallets",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AFK config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/afk/config/{id}/remove-smart-wallet": {
      "post": {
        "summary": "Remove smart wallet",
        "description": "Removes a single smart wallet from an AFK config by address (tenant-scoped).",
        "tags": [
          "Trading API: AFK Auto-Buy"
        ],
        "operationId": "afk-remove-smart-wallet",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AFK config id."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "address": {
                    "type": "string",
                    "description": "Wallet address to remove."
                  }
                },
                "required": [
                  "address"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/sniper/create-config": {
      "post": {
        "summary": "Create sniper config",
        "description": "Creates a new auto-sniper/TG-Auto config for the calling tenant and immediately marks it saved (is_saved=true). The target wallet is verified to belong to the caller before creation so a tenant cannot snipe-buy through another tenant's wallet.",
        "tags": [
          "Trading API: Sniper & Auto-Sell"
        ],
        "operationId": "sniper-create-config",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Display name for the config"
                  },
                  "wallet_id": {
                    "type": "string",
                    "description": "Wallet to buy with; must belong to caller. Defaults to the caller's most recent active wallet when omitted"
                  },
                  "buy_amount": {
                    "type": "string",
                    "description": "Buy size in lamports; must be positive"
                  }
                },
                "required": [
                  "name",
                  "buy_amount"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/sniper/configs": {
      "get": {
        "summary": "List sniper configs",
        "description": "Returns all sniper/TG-Auto/X-Auto configs owned by the calling tenant.",
        "tags": [
          "Trading API: Sniper & Auto-Sell"
        ],
        "operationId": "sniper-list-configs",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/sniper/config/{id}": {
      "get": {
        "summary": "Get sniper config",
        "description": "Returns one sniper config (scoped to the caller) plus its channel count and a human source summary. Returns not-found if the id does not belong to the caller.",
        "tags": [
          "Trading API: Sniper & Auto-Sell"
        ],
        "operationId": "sniper-get-config",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Sniper config ID (caller-owned)"
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      },
      "put": {
        "summary": "Update sniper config fields",
        "description": "Bulk-updates arbitrary config fields from a string-keyed map; each field is applied individually and the response reports which succeeded vs failed. Config ownership is verified before any update.",
        "tags": [
          "Trading API: Sniper & Auto-Sell"
        ],
        "operationId": "sniper-update-config",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Sniper config ID (caller-owned)"
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "fields": {
                    "type": "string",
                    "description": "Map of field name -> string value to apply (e.g. {\"buy_slippage_bps\":\"1500\",\"max_buy_count\":\"5\"}). Must be non-empty"
                  }
                },
                "required": [
                  "fields"
                ]
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Delete sniper config",
        "description": "Deletes a sniper config owned by the caller (ownership enforced at the SQL layer via telegram_id).",
        "tags": [
          "Trading API: Sniper & Auto-Sell"
        ],
        "operationId": "sniper-delete-config",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Sniper config ID (caller-owned)"
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/sniper/config/{id}/toggle": {
      "post": {
        "summary": "Toggle sniper config active",
        "description": "Activates or deactivates a sniper config (turns the snipe worker on/off for it). Ownership verified before toggle.",
        "tags": [
          "Trading API: Sniper & Auto-Sell"
        ],
        "operationId": "sniper-toggle-config",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Sniper config ID (caller-owned)"
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "active": {
                    "type": "string",
                    "description": "true to activate, false to deactivate"
                  }
                },
                "required": [
                  "active"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/sniper/config/{id}/reset-count": {
      "post": {
        "summary": "Reset sniper buy count",
        "description": "Resets the config's current_buy_count back to 0 (clears the lifetime buy cap counter so a capped config resumes buying). Ownership verified first.",
        "tags": [
          "Trading API: Sniper & Auto-Sell"
        ],
        "operationId": "sniper-reset-count",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Sniper config ID (caller-owned)"
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/sniper/config/{id}/channels": {
      "get": {
        "summary": "List sniper config channels",
        "description": "Lists the Telegram channels attached to a sniper config (the sources it monitors for token mints).",
        "tags": [
          "Trading API: Sniper & Auto-Sell"
        ],
        "operationId": "sniper-list-channels",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Sniper config ID (caller-owned)"
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      },
      "post": {
        "summary": "Add sniper config channel",
        "description": "Attaches a Telegram channel to a sniper config. The username is normalized (leading @ stripped, lowercased) before storage.",
        "tags": [
          "Trading API: Sniper & Auto-Sell"
        ],
        "operationId": "sniper-add-channel",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Sniper config ID (caller-owned)"
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "channel_username": {
                    "type": "string",
                    "description": "Telegram channel username to monitor (with or without leading @). Required, non-empty"
                  },
                  "is_preset": {
                    "type": "string",
                    "description": "Whether this is a curated preset channel. Defaults to false"
                  }
                },
                "required": [
                  "channel_username"
                ]
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Remove sniper config channel",
        "description": "Detaches a Telegram channel from a sniper config. Channel identified by username in the request body (normalized: @ stripped, lowercased).",
        "tags": [
          "Trading API: Sniper & Auto-Sell"
        ],
        "operationId": "sniper-remove-channel",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Sniper config ID (caller-owned)"
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "channel_username": {
                    "type": "string",
                    "description": "Channel username to remove (with or without leading @). Required, non-empty"
                  }
                },
                "required": [
                  "channel_username"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/sniper/executions": {
      "get": {
        "summary": "List sniper executions",
        "description": "Returns sniper execution history (detected/bought/filtered/failed events). With ?config_id it returns that config's history; without it, fans out across only the caller's own configs (user-scoped, never global).",
        "tags": [
          "Trading API: Sniper & Auto-Sell"
        ],
        "operationId": "sniper-executions",
        "parameters": [
          {
            "name": "config_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Restrict to a single config's executions. When omitted, returns recent executions across all of the caller's configs"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Max rows to return. Defaults to 20, capped at 100"
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/sniper/config/{id}/x-settings": {
      "put": {
        "summary": "Update sniper X-Auto settings",
        "description": "Updates X (Twitter) monitoring settings on a sniper config: sets/removes the X handle as a source, sets/clears x_user_id, and toggles monitor_posts/replies/reposts. Each provided field is applied individually with per-field success/error reporting. Ownership verified first.",
        "tags": [
          "Trading API: Sniper & Auto-Sell"
        ],
        "operationId": "sniper-update-x-settings",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Sniper config ID (caller-owned)"
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "x_handle": {
                    "type": "string",
                    "description": "X handle to monitor. Empty string removes the X source; non-empty sets it"
                  },
                  "x_user_id": {
                    "type": "string",
                    "description": "Numeric X user id. Empty string clears it; non-empty sets it"
                  },
                  "monitor_posts": {
                    "type": "string",
                    "description": "Whether to monitor original posts"
                  },
                  "monitor_replies": {
                    "type": "string",
                    "description": "Whether to monitor replies"
                  },
                  "monitor_reposts": {
                    "type": "string",
                    "description": "Whether to monitor reposts"
                  }
                },
                "required": []
              }
            }
          }
        }
      }
    },
    "/v1/autosell/create": {
      "post": {
        "summary": "Create AutoSell profile",
        "description": "Creates a new named AutoSell profile for the calling tenant. The user is resolved from the X-User-Ref header (tenancy); the new profile starts with default rules and returns its numeric id.",
        "tags": [
          "Trading API: Sniper & Auto-Sell"
        ],
        "operationId": "autosell-create",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Profile display name. Must be non-empty (trimmed)."
                  }
                },
                "required": [
                  "name"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/autosell/profiles": {
      "get": {
        "summary": "List AutoSell profiles",
        "description": "Lists all AutoSell profiles owned by the calling tenant (resolved from X-User-Ref). Returns a count plus the full serialized profile objects.",
        "tags": [
          "Trading API: Sniper & Auto-Sell"
        ],
        "operationId": "autosell-list-profiles",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/autosell/profile/{id}": {
      "get": {
        "summary": "Get AutoSell profile",
        "description": "Fetches a single AutoSell profile by id, scoped to the calling tenant (resolved from X-User-Ref). 404-equivalent when the profile does not exist or is not owned by the tenant.",
        "tags": [
          "Trading API: Sniper & Auto-Sell"
        ],
        "operationId": "autosell-get-profile",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AutoSell profile id (i32)."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      },
      "put": {
        "summary": "Update AutoSell profile",
        "description": "Partially updates an AutoSell profile (all body fields optional); only provided fields are written. Scoped to the calling tenant (X-User-Ref). Returns the full updated profile.",
        "tags": [
          "Trading API: Sniper & Auto-Sell"
        ],
        "operationId": "autosell-update-profile",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AutoSell profile id (i32)."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "New profile name. Must be non-empty (trimmed) if provided."
                  },
                  "fixed_rules": {
                    "type": "string",
                    "description": "Fixed TP/SL ladder rules (raw JSON, stored as-is)."
                  },
                  "trailing_enabled": {
                    "type": "string",
                    "description": "Enable/disable trailing stop. Triggers a trailing update if any trailing_* field is present."
                  },
                  "trailing_activation_pct": {
                    "type": "string",
                    "description": "Profit % at which the trailing stop activates."
                  },
                  "trailing_drawdown_pct": {
                    "type": "string",
                    "description": "Drawdown % from peak that triggers the sell."
                  },
                  "moonbag_pct": {
                    "type": "string",
                    "description": "Percent of position to retain as a moonbag (not sold)."
                  },
                  "expiry_seconds": {
                    "type": "string",
                    "description": "Seconds until the profile auto-expires (0 = no expiry)."
                  },
                  "sell_slippage_bps": {
                    "type": "string",
                    "description": "Sell slippage tolerance in basis points."
                  },
                  "mev_protect": {
                    "type": "string",
                    "description": "Route auto-sells through MEV-protected providers."
                  }
                },
                "required": []
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Delete AutoSell profile",
        "description": "Deletes an AutoSell profile by id, scoped to the calling tenant (X-User-Ref). Returns success:false if no matching owned profile was found.",
        "tags": [
          "Trading API: Sniper & Auto-Sell"
        ],
        "operationId": "autosell-delete-profile",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AutoSell profile id (i32) to delete."
          }
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/autosell/attach": {
      "post": {
        "summary": "Attach AutoSell profile",
        "description": "Attaches an AutoSell profile either as the tenant's global default (source=global) or to a specific AFK config (source=afk, requires source_config_id). All operations scoped to the calling tenant (X-User-Ref).",
        "tags": [
          "Trading API: Sniper & Auto-Sell"
        ],
        "operationId": "autosell-attach-profile",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "profile_id": {
                    "type": "string",
                    "description": "AutoSell profile id to attach."
                  },
                  "source": {
                    "type": "string",
                    "description": "Attach target. Valid values: \"global\" (set as tenant default) or \"afk\" (attach to an AFK config)."
                  },
                  "source_config_id": {
                    "type": "string",
                    "description": "Target AFK config id. Required when source=\"afk\"; ignored for source=\"global\"."
                  }
                },
                "required": [
                  "profile_id",
                  "source"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/health": {
      "get": {
        "summary": "Health check",
        "description": "Public, unauthenticated liveness/readiness probe. Returns DB reachability plus build/version markers; with ?deep=1 it also probes RPC reachability (cached ~5s) and treasury config. Returns 503 only when the DB is unreachable so load balancers drain the node.",
        "tags": [
          "Trading API: System"
        ],
        "operationId": "system-health",
        "parameters": [
          {
            "name": "deep",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "When set to 1/true/yes/on, also probes RPC reachability (rpc_ok, cached at most once per ~5s) and treasury_configured, and folds rpc_ok into status. Omit for the cheap single DB-ping path."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/usage": {
      "get": {
        "summary": "Usage / credit snapshot",
        "description": "App-level credit and quota snapshot for the calling X-API-Key. Free (0 credits), no X-User-Ref / tenancy — reports the key's plan, scopes, owner wallet, and credit window usage. Read scope.",
        "tags": [
          "Trading API: System"
        ],
        "operationId": "system-usage",
        "parameters": [],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/programs/{programId}": {
      "get": {
        "summary": "Program (smart-contract) intel",
        "description": "Program account + upgrade state, activity sampling (tx/min, fail%, last-active), a tx-type mix to label an unknown program, and recent decoded transactions. Consolidates a direct-Stryke's node layer program page into one allow-listed call.",
        "tags": [
          "Programs"
        ],
        "operationId": "programs-get",
        "parameters": [
          {
            "name": "programId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Program (smart-contract) address, base58."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/positions/{wallet}": {
      "get": {
        "summary": "DeFi positions",
        "description": "Aggregated DeFi positions across Kamino (lend/borrow), Drift (perp + spot), MarginFi (lend/borrow) and Jupiter Perps, flattened into one normalized position contract. Each protocol is fetched independently and isolated — one failing leg never sinks the others.",
        "tags": [
          "Positions"
        ],
        "operationId": "positions-get",
        "parameters": [
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Solana wallet address (base58)."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/webhooks": {
      "post": {
        "summary": "Create a webhook",
        "description": "Subscribe an https endpoint to a token's trades. Returns the signing secret ONCE.",
        "tags": [
          "Webhooks"
        ],
        "operationId": "webhooks-create",
        "parameters": [],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "chain": {
                    "type": "string",
                    "description": "A chain the index follows — see GET /api/v2/stream/chains."
                  },
                  "token": {
                    "type": "string",
                    "description": "Token address in the chain's own format."
                  },
                  "url": {
                    "type": "string",
                    "description": "https endpoint to POST to. Must resolve to a public address; private, loopback, link-local and cloud-metadata targets are refused."
                  },
                  "kind": {
                    "type": "string",
                    "description": "'trades' (default and currently the only kind)."
                  },
                  "filters": {
                    "type": "string",
                    "description": "Optional { minAmountUsd, side, commitment }. An unrecognised filter is a 400, never silently ignored. commitment 'confirmed' (Solana only, where enabled) delivers from the confirmed fast lane ~1–3 s after the block instead of the finalized tape (~15 s), with the same eventId the finalized delivery would carry — so dedupe on eventId as always — and sends a `trade.retracted` event (data.retractedEventId) if that trade does not finalize as delivered — data.finalizedEventId names the event that carries it when the same transaction finalized at another position. A token with more than 200,000 trades in 24 h cannot use 'confirmed'."
                  }
                },
                "required": [
                  "chain",
                  "token",
                  "url"
                ]
              }
            }
          }
        }
      },
      "get": {
        "summary": "List your webhooks",
        "description": "Every subscription on this API key. Secrets are never included.",
        "tags": [
          "Webhooks"
        ],
        "operationId": "webhooks-list",
        "parameters": [],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/webhooks/{id}": {
      "get": {
        "summary": "One webhook",
        "description": "A subscription plus its pending/delivered/dead delivery counts.",
        "tags": [
          "Webhooks"
        ],
        "operationId": "webhooks-get",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Webhook id."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      },
      "delete": {
        "summary": "Delete a webhook",
        "description": "Removes the subscription and everything still queued for it.",
        "tags": [
          "Webhooks"
        ],
        "operationId": "webhooks-delete",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Webhook id."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      },
      "patch": {
        "summary": "Enable or disable",
        "description": "Body { \"active\": true|false }. Re-enabling also clears the consecutive-failure count.",
        "tags": [
          "Webhooks"
        ],
        "operationId": "webhooks-patch",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Webhook id."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "active": {
                    "type": "string",
                    "description": "Whether the subscription should deliver."
                  }
                },
                "required": [
                  "active"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v2/webhooks/{id}/deliveries": {
      "get": {
        "summary": "Delivery log",
        "description": "The last attempts for this subscription: status, HTTP code, error, and when the next retry is due.",
        "tags": [
          "Webhooks"
        ],
        "operationId": "webhooks-deliveries",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Webhook id."
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "pending | delivered | dead"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1-200, default 50."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/webhooks/{id}/test": {
      "post": {
        "summary": "Send a test event",
        "description": "Queues one synthetic event with the same headers and signature as a real one.",
        "tags": [
          "Webhooks"
        ],
        "operationId": "webhooks-test",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Webhook id."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/webhooks/{id}/rotate": {
      "post": {
        "summary": "Rotate the signing secret",
        "description": "Issues a new secret and returns it once. The old one stops working immediately.",
        "tags": [
          "Webhooks"
        ],
        "operationId": "webhooks-rotate",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Webhook id."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/stream/chains": {
      "get": {
        "summary": "Which chains can be streamed",
        "description": "The chains the first-party index follows, whether each is currently serving, how far behind it is, and how far back its history reaches. No key required.",
        "tags": [
          "Streaming (SSE)"
        ],
        "operationId": "stream-chains",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/stream/{chain}/token/{address}/trades": {
      "get": {
        "summary": "Live trade tape (SSE)",
        "description": "Every swap touching this token, pushed as it lands, read from the first-party tape.",
        "tags": [
          "Streaming (SSE)"
        ],
        "operationId": "stream-trades",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "A chain the index follows — see GET /api/v2/stream/chains"
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Token address in the chain's own format"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Resume position, `<tsMs>-<block>-<logIndex>`. A browser EventSource sends this automatically as Last-Event-ID."
          },
          {
            "name": "side",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "buy or sell"
          },
          {
            "name": "minUsd",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only trades at or above this USD size"
          },
          {
            "name": "pool",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only this pool's trades"
          },
          {
            "name": "commitment",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "finalized (default) or confirmed. confirmed (Solana only, where enabled) pushes from the confirmed lane ~1–3 s after the block, at-most-once, with NO resume (Last-Event-ID is ignored) and `retract` events for trades that do not finalize."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/stream/{chain}/token/{address}/candles": {
      "get": {
        "summary": "Live OHLCV (SSE)",
        "description": "The token's candles, pushed as they form and again as the open bucket moves.",
        "tags": [
          "Streaming (SSE)"
        ],
        "operationId": "stream-candles",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "A chain the index follows"
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Token address in the chain's own format"
          },
          {
            "name": "interval",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Seconds: 60, 300, 900, 3600, 14400 or 86400. Default 60."
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Resume position; also accepted as Last-Event-ID."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chain/{chain}/token/{address}": {
      "get": {
        "summary": "Token summary (any chain)",
        "description": "Price, market cap, liquidity, 24h volume, holder count, logo and socials for a token on any chain the catalog serves. Requires the `market` capability.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_get_chain_token_address",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Token address in the chain's own format: 0x… on EVM, base58 on Solana, a Move coin type (0x…::module::Type) on Sui and Aptos. Validated before any provider is called; a mismatch is a 400 that names the expected format."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chain/{chain}/token/{address}/price": {
      "get": {
        "summary": "Token price (any chain)",
        "description": "USD price with 24h change, market cap and liquidity where the provider carries them. Requires the `price` capability.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_get_chain_token_address_price",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Token address in the chain's own format: 0x… on EVM, base58 on Solana, a Move coin type (0x…::module::Type) on Sui and Aptos. Validated before any provider is called; a mismatch is a 400 that names the expected format."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chain/{chain}/token/{address}/ohlcv": {
      "get": {
        "summary": "OHLCV candles (any chain)",
        "description": "Ascending [{t,o,h,l,c,v}] candles for the token's deepest pool. Requires the `ohlcv` capability.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_get_chain_token_address_ohlcv",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Token address in the chain's own format: 0x… on EVM, base58 on Solana, a Move coin type (0x…::module::Type) on Sui and Aptos. Validated before any provider is called; a mismatch is a 400 that names the expected format."
          },
          {
            "name": "period",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1m, 5m, 15m, 30m, 1h (default), 4h, 12h, 1d or 1w."
          },
          {
            "name": "timeframe",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "minute|hour|day, paired with aggregate. An alternative to period."
          },
          {
            "name": "aggregate",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Multiplier for timeframe (e.g. timeframe=minute&aggregate=5). 1-1000, default 1."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1-1000, default 100."
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Window start: unix seconds, unix ms or ISO-8601."
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Window end, same formats."
          },
          {
            "name": "pool",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Price a specific pool instead of the deepest one."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chain/{chain}/token/{address}/price-at": {
      "get": {
        "summary": "Price at a point in time",
        "description": "What this token was worth on a given day, or at a given instant. The question every tax tool, accounting integration and backtest asks first.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_get_chain_token_address_price_at",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Token address in the chain's own format: 0x… on EVM, base58 on Solana, a Move coin type (0x…::module::Type) on Sui and Aptos. Validated before any provider is called; a mismatch is a 400 that names the expected format."
          },
          {
            "name": "date",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "YYYY-MM-DD (UTC). Resolves to that calendar day's CLOSE."
          },
          {
            "name": "at",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "A unix timestamp in ms or an ISO-8601 instant. Resolves to the bar it falls in."
          },
          {
            "name": "interval",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "With `at`: 60 (default) or 3600 seconds."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chain/{chain}/token/{address}/trades": {
      "get": {
        "summary": "Recent trades (any chain)",
        "description": "The live tape for the token's deepest pool: [{ts,type,priceUsd,amountToken,amountUsd,trader,txHash,pool}]. Requires the `trades` capability.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_get_chain_token_address_trades",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Token address in the chain's own format: 0x… on EVM, base58 on Solana, a Move coin type (0x…::module::Type) on Sui and Aptos. Validated before any provider is called; a mismatch is a 400 that names the expected format."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1-500, default 50."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chain/{chain}/token/{address}/pools": {
      "get": {
        "summary": "Pools / pairs (any chain)",
        "description": "Every pool the token trades in, deepest first: [{pool,dex,quoteSymbol,liquidityUsd,volume24h,priceUsd,createdAt}]. Requires the `pools` capability.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_get_chain_token_address_pools",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Token address in the chain's own format: 0x… on EVM, base58 on Solana, a Move coin type (0x…::module::Type) on Sui and Aptos. Validated before any provider is called; a mismatch is a 400 that names the expected format."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1-100, default 20."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chain/{chain}/token/{address}/holders": {
      "get": {
        "summary": "Holder distribution (any chain)",
        "description": "Holder count, top holders and concentration (top10/50/100), plus sniper/bundler/insider counts where the provider computes them. Requires the `holders` capability.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_get_chain_token_address_holders",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Token address in the chain's own format: 0x… on EVM, base58 on Solana, a Move coin type (0x…::module::Type) on Sui and Aptos. Validated before any provider is called; a mismatch is a 400 that names the expected format."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1-500, default 50."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chain/{chain}/token/{address}/security": {
      "get": {
        "summary": "Token security (any chain)",
        "description": "Honeypot verdict, buy/sell tax, mint/freeze authority, ownership renouncement, proxy, LP lock/burn and a 0-100 score where HIGHER IS SAFER. Requires the `security` capability.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_get_chain_token_address_security",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Token address in the chain's own format: 0x… on EVM, base58 on Solana, a Move coin type (0x…::module::Type) on Sui and Aptos. Validated before any provider is called; a mismatch is a 400 that names the expected format."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chain/{chain}/token/{address}/metadata": {
      "get": {
        "summary": "Token metadata (any chain)",
        "description": "Name, symbol, decimals, logo, description, socials, categories, deployer and creation time. Requires the `metadata` capability.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_get_chain_token_address_metadata",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Token address in the chain's own format: 0x… on EVM, base58 on Solana, a Move coin type (0x…::module::Type) on Sui and Aptos. Validated before any provider is called; a mismatch is a 400 that names the expected format."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chain/{chain}/address/{address}": {
      "get": {
        "summary": "What is this address?",
        "description": "Classifies an address as a token mint, a market (pool) or a wallet, from Stryke's own index — no third-party call. Returns `kind` plus whichever of `token`, `pool` or `wallet` applies. `kind:\"unknown\"` means the address is not in the index, which is NOT a statement that it does not exist on chain; `checked` names the tables that were searched.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_get_chain_address_address",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Token address in the chain's own format: 0x… on EVM, base58 on Solana, a Move coin type (0x…::module::Type) on Sui and Aptos. Validated before any provider is called; a mismatch is a 400 that names the expected format."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chain/{chain}/token/{address}/allowances": {
      "get": {
        "summary": "ERC-20 approvals for a wallet",
        "description": "How much of this token an owner has approved each spender to move. The primitive behind every revoke tool.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_get_chain_token_address_allowances",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The ERC-20 token contract."
          },
          {
            "name": "owner",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The wallet whose approvals you are reading."
          },
          {
            "name": "spenders",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated spender addresses, at most 25. ERC-20 cannot be asked \"who holds an approval\" — allowance() answers about one pair and the token publishes no list — so the spenders come from you."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chain/{chain}/tokens/prices": {
      "post": {
        "summary": "Batch token prices — one chain, or a basket across several",
        "description": "Prices up to 50 tokens in one call. With a named chain the body is a plain array of addresses. With chain=all each entry names its own chain, so a portfolio spanning several chains is ONE request instead of one per chain.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_post_chain_tokens_prices",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "addresses": {
                    "type": "string",
                    "description": "Up to 50. On a named chain: addresses as strings. On chain=all: objects { chain, address }, spanning at most 10 distinct chains."
                  }
                },
                "required": [
                  "addresses"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v2/chain/{chain}/search": {
      "get": {
        "summary": "Search tokens on a chain",
        "description": "Token search scoped to one chain, or across every indexed chain with chain=all.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_get_chain_search",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          },
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "2-64 characters."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1-100, default 20."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chain/{chain}/trending": {
      "get": {
        "summary": "Trending tokens on a chain",
        "description": "Top tokens on the chain by recent volume.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_get_chain_trending",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1-100, default 20."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chain/{chain}/screener": {
      "get": {
        "summary": "Screen the chain's tokens",
        "description": "Rank every token on the chain by what it actually did over a window — volume, trade count and price change — with thresholds. This is the \"show me tokens over $50k of volume with more than 200 trades today\" question that /trending cannot answer, because /trending is a fixed ranking and this is a query.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_get_chain_screener",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          },
          {
            "name": "window",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1h, 4h, 24h, 1d or 7d. Default 24h. The window picks the bar size that tiles it: 1h/4h/24h read hourly bars, 1d/7d read daily ones."
          },
          {
            "name": "minVolumeUsd",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only tokens whose summed USD volume over the window is at least this."
          },
          {
            "name": "minTrades",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only tokens with at least this many trades over the window."
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "volume (default), trades, buckets or recent."
          },
          {
            "name": "order",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "desc (default) or asc."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1-500, default 50."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chain/{chain}/wallet/{wallet}/portfolio": {
      "get": {
        "summary": "Wallet portfolio (any chain, or all)",
        "description": "Token holdings and total USD value for an address. Use chain=all to fetch every chain the provider indexes in one call.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_get_chain_wallet_wallet_portfolio",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          },
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Wallet address in the chain's format."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chain/{chain}/wallet/{wallet}/trades": {
      "get": {
        "summary": "Wallet trades (any chain)",
        "description": "Every swap this wallet made on this chain, newest first: token in/out, amounts, USD value, price and transaction hash.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_get_chain_wallet_wallet_trades",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          },
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Wallet address."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1-500, default 50."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chain/{chain}/wallet/{wallet}/activity": {
      "get": {
        "summary": "Wallet activity (any chain)",
        "description": "The wallet's full on-chain activity on this chain — transfers in and out, swaps, approvals and contract interactions — with spam filtered out.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_get_chain_wallet_wallet_activity",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          },
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Wallet address."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1-500, default 50."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chain/{chain}/wallet/{wallet}/pnl": {
      "get": {
        "summary": "Wallet PnL (any chain)",
        "description": "Per-token profit and loss for this wallet on this chain: realised and unrealised PnL, average cost basis, amount still held and current value.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_get_chain_wallet_wallet_pnl",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          },
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Wallet address."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chain/{chain}/wallet/{wallet}/risk": {
      "get": {
        "summary": "Wallet risk flags",
        "description": "Whether this ADDRESS is known to be malicious — sanctioned, a phishing or theft address, a mixer, blacklisted, or the deployer of malicious contracts. The token security verb answers the same kind of question about a contract; this one is about the counterparty.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_get_chain_wallet_wallet_risk",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          },
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The address to screen, in the chain's format."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chain/{chain}/wallet/{wallet}/defi-positions": {
      "get": {
        "summary": "Wallet DeFi positions (any chain)",
        "description": "Liquidity-pool, lending and staking positions this wallet holds on this chain, with the protocol, the underlying assets and the position's USD value.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_get_chain_wallet_wallet_defi_positions",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          },
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Wallet address."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chain/{chain}/wallet/{wallet}/history": {
      "get": {
        "summary": "Wallet balance history (any chain)",
        "description": "Total USD value of this wallet on this chain over time, as a time series suitable for charting a portfolio curve.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_get_chain_wallet_wallet_history",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          },
          {
            "name": "wallet",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Wallet address."
          },
          {
            "name": "period",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1h, 1d, 7d, 30d, 90d or 365d."
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Window start."
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Window end."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chain/{chain}/quote": {
      "get": {
        "summary": "Swap quote — non-custodial (any chain)",
        "description": "An UNSIGNED swap quote from an aggregator (the routing layer) or, on registry chains, the chain's own Uniswap-family quoter. Returns amounts, price impact, gas estimate, the route and — where the aggregator provides one — an unsigned transactionRequest.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_get_chain_quote",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          },
          {
            "name": "from",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Input token address, or `native` for the chain's native asset."
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Output token address, or `native`."
          },
          {
            "name": "amount",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Input amount in the SMALLEST units of the input token; digits only, 1-78 of them (uint256 max is 78 decimal digits). Either this or amountHuman."
          },
          {
            "name": "amountHuman",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Input amount as a decimal (e.g. 0.01); converted exactly using the token's decimals. At most 78 integer and 36 fractional digits."
          },
          {
            "name": "slippageBps",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1-5000, default 100 (1%)."
          },
          {
            "name": "order",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Route preference: RECOMMENDED, FASTEST, CHEAPEST or SAFEST (case-insensitive). Anything else is a 400."
          },
          {
            "name": "fromAddress",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "The sender. Without it a placeholder is used and transactionRequest is omitted."
          },
          {
            "name": "toAddress",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Recipient, when it differs from the sender. Validated against the DESTINATION chain's address format (toChain when given, otherwise this chain); a mismatch is a 400."
          },
          {
            "name": "toChain",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Destination chain for a cross-chain quote; any identifier GET /api/v2/chains resolves. A destination whose measured `quote` capability is false answers 501 rather than silently becoming a same-chain quote."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chain/{chain}/gas": {
      "get": {
        "summary": "Gas price and L1 data fee (EVM chains)",
        "description": "gasPrice, base fee, priority fee and — on rollups that charge one — the L1 data fee, read from the chain's own JSON-RPC and the rollup's fee oracle.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_get_chain_gas",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          },
          {
            "name": "gas",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Gas units to cost out; the response multiplies the price by this. 1-30000000."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chain/{chain}/tx/{hash}": {
      "get": {
        "summary": "Transaction receipt (EVM chains)",
        "description": "Receipt, status, gas used and the L1 data fee where the chain charges one.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_get_chain_tx_hash",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          },
          {
            "name": "hash",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "0x-prefixed 32-byte transaction hash."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chain/{chain}/capabilities": {
      "get": {
        "summary": "What this chain can do",
        "description": "The catalog row for one chain: measured tier, per-capability booleans, the provider names covering it, address format, explorer templates and the prober's evidence.",
        "tags": [
          "Chain-generic market data"
        ],
        "operationId": "chain_get_chain_capabilities",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, a CAIP-2 id, or the id a provider uses (the market-data layer evm:1, the pool index eth, the DEX index ethereum). GET /api/v2/chains lists them all."
          }
        ],
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chains": {
      "get": {
        "summary": "List chains (public catalog)",
        "description": "Every chain in the catalog with its measured tier (0=recognised, 1=priced, 2=market, 3=forensics, 4=tradeable, 5=services), per-capability booleans, the provider NAMES that cover it, address format, explorer templates and aliases. Filters are ANDed. No API key required.",
        "tags": [
          "Chains (catalog)"
        ],
        "operationId": "get-api-v2-chains",
        "parameters": [
          {
            "name": "tier",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "EXACTLY this tier, 0-5 — not a minimum. The ladder is a class, not a rank: tier 4 (quotable) does not imply tier 2 (live tape), because a chain can be quotable through an aggregator without our having a live tape for it. To ask \"which chains can do X\", filter on capability instead."
          },
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Exact chain kind (evm, svm, move, ton, tron,...). 400 lists the kinds currently present when the value is unknown."
          },
          {
            "name": "capability",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "One of price, market, ohlcv, trades, pools, holders, security, metadata, portfolio, walletTrades, quote, rpc, services. Only rows where that capability is true."
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Case-insensitive substring match on key, displayName and aliases. At most 64 characters."
          },
          {
            "name": "measured",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1 = only rows the prober has measured; 0 = only rows it has not. Absent = all."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chains/summary": {
      "get": {
        "summary": "Catalog summary",
        "description": "Counts only: rows by tier, by kind and by capability, how many rows the prober has measured, how many are in the execution registry, plus the tier ladder and the evidence timestamp.",
        "tags": [
          "Chains (catalog)"
        ],
        "operationId": "get-api-v2-chains-summary",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chains/resolve": {
      "get": {
        "summary": "Resolve a chain identifier",
        "description": "Turns any chain identifier (key, alias, display name, EIP-155 id, evm:<id>, eip155:<id>, CAIP-2, or a provider's chain id) into the one catalog row it names, or 404.",
        "tags": [
          "Chains (catalog)"
        ],
        "operationId": "get-api-v2-chains-resolve",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The identifier to resolve. Case-insensitive; at most 128 characters."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/chains/{chain}": {
      "get": {
        "summary": "One chain, with the routes it supports",
        "description": "The publicView row for one chain plus the /api/v2/chain/{chain}/* routes that will work on it given its measured capabilities, and — separately — the ones that will 501, each with the reason.",
        "tags": [
          "Chains (catalog)"
        ],
        "operationId": "get-api-v2-chains-chain",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Any identifier the catalog resolves, case-insensitively: the Stryke key (eth), an alias (ethereum), the display name, an EIP-155 id (1), evm:1, eip155:1, any CAIP-2 id, or the id a provider uses for the chain (the market-data layer evm:1, the pool index eth, the DEX index ethereum)."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/pairs": {
      "get": {
        "summary": "Rank pairs",
        "description": "The screener. Ranked pools with price, change, volume, transactions, liquidity, FDV and age.",
        "tags": [
          "Screener (pairs)"
        ],
        "operationId": "get-api-v2-pairs",
        "parameters": [
          {
            "name": "chain",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "eth | base | sol, or omit for all three."
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "volume24h (default), volume6h, volume1h, volume5m, liquidity, txns24h, change24h, change6h, change1h, change5m, fdv, age, lastTrade."
          },
          {
            "name": "order",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "'desc' (default) or 'asc'."
          },
          {
            "name": "minLiquidityUsd",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Defaults to 1. Pass 0 to include pools whose depth was never measured — their volume is NOT trustworthy; see volumeTrusted on each row."
          },
          {
            "name": "minVolume24hUsd",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Floor on 24h volume."
          },
          {
            "name": "minTxns24h",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Floor on 24h transaction count."
          },
          {
            "name": "maxAge",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only pairs first traded within this long, e.g. '15m', '6h', '7d'. Implies an exact first-trade timestamp."
          },
          {
            "name": "minAge",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only pairs older than this."
          },
          {
            "name": "dex",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Exact venue match, e.g. pumpswap, orca-whirlpool, uniswap-v3."
          },
          {
            "name": "activeWithin",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only pairs whose LAST trade is this recent, e.g. '15m', '1h'. Sorted by 24h volume, a pool that pumped and stopped still ranks — one real example carried $164.32M across 167,749 transactions and had been dead for nine hours. Not applied by default."
          },
          {
            "name": "token",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Every pair whose BASE side is this token."
          },
          {
            "name": "pools",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated pool addresses (max 200) — how a watchlist is fetched in one request."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1-500, default 50."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "0-10000, default 0."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/pairs/trending": {
      "get": {
        "summary": "Trending pairs",
        "description": "Ranked by 1-hour volume, with a floor on transaction count so one large trade cannot buy the top of the list.",
        "tags": [
          "Screener (pairs)"
        ],
        "operationId": "get-api-v2-pairs-trending",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/pairs/new": {
      "get": {
        "summary": "New pairs",
        "description": "Pairs whose FIRST trade the index actually witnessed. Pairs whose history merely begins at the edge of the tape's retention window are excluded rather than shown as new.",
        "tags": [
          "Screener (pairs)"
        ],
        "operationId": "get-api-v2-pairs-new",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/pairs/gainers": {
      "get": {
        "summary": "Gainers",
        "description": "Ranked by 24h change, with liquidity and transaction floors so the list is not a directory of empty pools, and a recency floor so it is not a directory of pairs that stopped trading.",
        "tags": [
          "Screener (pairs)"
        ],
        "operationId": "get-api-v2-pairs-gainers",
        "parameters": [
          {
            "name": "activeWithin",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "How recently the pair must have traded, e.g. '15m', '2h'. Defaults to 2h on this feed; '0' removes it."
          },
          {
            "name": "minLiquidityUsd",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Defaults to 5000 here."
          },
          {
            "name": "minTxns24h",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Defaults to 50 here."
          },
          {
            "name": "chain",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "eth | base | sol, or omit for all three."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1-500, default 50."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/pairs/losers": {
      "get": {
        "summary": "Losers",
        "description": "Ranked by 24h change ascending, same floors as gainers.",
        "tags": [
          "Screener (pairs)"
        ],
        "operationId": "get-api-v2-pairs-losers",
        "parameters": [
          {
            "name": "activeWithin",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "How recently the pair must have traded, e.g. '15m', '2h'. Defaults to 2h on this feed; '0' removes it."
          },
          {
            "name": "minLiquidityUsd",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Defaults to 5000 here."
          },
          {
            "name": "minTxns24h",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Defaults to 50 here."
          },
          {
            "name": "chain",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "eth | base | sol, or omit for all three."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1-500, default 50."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/pairs/search": {
      "get": {
        "summary": "Search pairs",
        "description": "By token symbol (prefix), token name (contains), or exact token/pool address. Ordered by liquidity.",
        "tags": [
          "Screener (pairs)"
        ],
        "operationId": "get-api-v2-pairs-search",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Symbol, name or address."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/pairs/stats": {
      "get": {
        "summary": "Index totals",
        "description": "Per-chain pair counts and 24h volume, published both filtered and unfiltered so the difference stays visible.",
        "tags": [
          "Screener (pairs)"
        ],
        "operationId": "get-api-v2-pairs-stats",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/pairs/{chain}/{pool}": {
      "get": {
        "summary": "One pair",
        "description": "A pair with both tokens hydrated, Solana mint/freeze authority where it applies, and the other pools trading the same token.",
        "tags": [
          "Screener (pairs)"
        ],
        "operationId": "get-api-v2-pairs-chain-pool",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/pairs/{chain}/{pool}/candles": {
      "get": {
        "summary": "Pair candles",
        "description": "OHLCV for the pair, on the base side. Intervals 60, 300, 900, 3600, 14400, 86400.",
        "tags": [
          "Screener (pairs)"
        ],
        "operationId": "get-api-v2-pairs-chain-pool-candles",
        "parameters": [
          {
            "name": "interval",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "60, 300, 900, 3600, 14400 or 86400 seconds. Default 300."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1-1000, default 300."
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "ISO timestamp or epoch ms. WITH from, the response is the window STARTING there. Without it, the response is the most recent `limit` bars."
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "ISO timestamp or epoch ms."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/pairs/{chain}/{pool}/traders": {
      "get": {
        "summary": "Top traders",
        "description": "Which wallets are trading this pool, with their trade counts and buy/sell split — the signal that separates an organic market from a handful of bots.",
        "tags": [
          "Screener (pairs)"
        ],
        "operationId": "get-api-v2-pairs-chain-pool-traders",
        "parameters": [
          {
            "name": "minutes",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Window, 1-360, default 60. Bounded because this groups the raw tape by maker: one hour costs 172ms on Solana’s busiest pool and 24 hours costs 26.7 seconds."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1-100, default 25."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/pairs/{chain}/{pool}/trades": {
      "get": {
        "summary": "Pair trades",
        "description": "The pair's own tape, newest first, from the index's raw swaps.",
        "tags": [
          "Screener (pairs)"
        ],
        "operationId": "get-api-v2-pairs-chain-pool-trades",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/wallet/{chain}/{address}": {
      "get": {
        "summary": "Wallet positions",
        "description": "Every token an address has traded, with net position, current value and average-cost PnL — from Stryke's own tape, not a vendor.",
        "tags": [
          "Wallets (first-party)"
        ],
        "operationId": "get-api-v2-wallet-chain-address",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "eth | base | sol."
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The wallet, in the chain's own address format."
          },
          {
            "name": "hours",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Window to look back over, default 168 (7 days). 0 means the whole retained tape (14 days) and is slower on high-frequency wallets."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/wallet/{chain}/{address}/balances": {
      "get": {
        "summary": "Wallet balances",
        "description": "What the address actually HOLDS, read from the chain through Stryke’s own RPC — not what it traded.",
        "tags": [
          "Wallets (first-party)"
        ],
        "operationId": "get-api-v2-wallet-chain-address-balances",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "eth | base | sol."
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The wallet, in the chain's own address format."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Holdings to return, 1-500, default 200. Sorted by value."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/wallet/{chain}/{address}/trades": {
      "get": {
        "summary": "Wallet trades",
        "description": "The address's own tape, newest first.",
        "tags": [
          "Wallets (first-party)"
        ],
        "operationId": "get-api-v2-wallet-chain-address-trades",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1-200, default 50."
          },
          {
            "name": "hours",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Look-back window, default 168."
          },
          {
            "name": "side",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "'buy' or 'sell'."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/token/{chain}/{address}": {
      "get": {
        "summary": "Token overview",
        "description": "One token: identity, the price its deepest market sets, cross-pool totals, and every market it trades in.",
        "tags": [
          "Tokens (first-party)"
        ],
        "operationId": "get-api-v2-token-chain-address",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "eth | base | sol."
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The token, in the chain's own address format."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Markets to return, 1-200, default 50."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/token/{chain}/{address}/pools": {
      "get": {
        "summary": "Token markets",
        "description": "Every pool the token trades in, deepest first, with the side it sits on.",
        "tags": [
          "Tokens (first-party)"
        ],
        "operationId": "get-api-v2-token-chain-address-pools",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1-500, default 100."
          },
          {
            "name": "minLiquidityUsd",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Default 0 — a token page must not hide a token's only market. Rows carry liquidityUsd and volTrusted so the caller can mark them."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/token/{chain}/{address}/candles": {
      "get": {
        "summary": "Token OHLCV",
        "description": "The token's cross-pool candle series — each bucket from that bucket's deepest eligible pool, never averaged.",
        "tags": [
          "Tokens (first-party)"
        ],
        "operationId": "get-api-v2-token-chain-address-candles",
        "parameters": [
          {
            "name": "interval",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "60, 300, 900, 3600, 14400 or 86400 seconds. Default 300."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1-1000, default 300."
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "ISO timestamp or epoch ms."
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "ISO timestamp or epoch ms."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v2/token/{chain}/{address}/trades": {
      "get": {
        "summary": "Token tape",
        "description": "Every trade of one token across all its markets, newest first — not one pool's tape.",
        "tags": [
          "Tokens (first-party)"
        ],
        "operationId": "get-api-v2-token-chain-address-trades",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1-200, default 50."
          },
          {
            "name": "hours",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Look-back window, default 24. The raw tape retains 14 days."
          },
          {
            "name": "side",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "'buy' or 'sell', oriented to this token."
          },
          {
            "name": "minUsd",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Floor on the trade value in dollars. On a chain whose follower prices its own swaps this is pushed into the query; where it does not (eth and base write no USD at all) the tape is valued at read time and filtered here, and `minUsdApplied` says which happened. When it is 'after-valuation', `scanned` says how many recent trades were examined — fewer results than `limit` at the scan cap means the window may hold more, further back."
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid API key"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    }
  }
}