{
  "openapi": "3.1.0",
  "info": {
    "title": "kyro.markets Public API",
    "version": "1.0.0",
    "summary": "Indexed Uniswap v4 analytics across 19 networks, focused on hooks.",
    "description": "Public, read-only REST & SSE API serving real-time and historical Uniswap v4 pools, hooks (with verified source code, decoded bytecode, and model-generated explanations), swaps, liquidity events, tokens, TVL, and volume across 19 EVM networks.\n\n### Rate Limiting\nEvery client IP receives a token bucket (**240 requests/min** sustained, burst of **120**). Every response includes `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` headers. When rate-limited, the API returns HTTP `429` with a `Retry-After` header.\n\n### Caching & Conditional Requests\nResponses are cached in memory (with single-flight request coalescing and stale-while-revalidate) and at the Cloudflare CDN edge. Every response includes `X-Cache` (`hit`, `stale`, `miss`, or `coalesced`) and a weak `ETag`. Pass `If-None-Match` to receive `304 Not Modified` with zero payload when data has not changed.\n\n### Pagination\n- **Offset pagination** (`/v1/hooks`, `/v1/pools`, `/v1/tokens`): pass `limit` (`1..500`, default `50`) and `offset` (`0..10000`). Responses return `{ data, meta: { limit, offset, total, has_more, next_offset? } }`.\n- **Cursor pagination** (`/v1/swaps`, `/v1/liquidity`): pass `limit` (`1..500`, default `50`) and `cursor` (`meta.next_cursor` from the previous page). Responses return `{ data, meta: { limit, has_more, next_cursor? } }`.",
    "contact": {
      "name": "kyro.markets",
      "url": "https://kyro.markets"
    }
  },
  "servers": [
    {
      "url": "https://api.kyro.markets",
      "description": "Production API (Cloudflare edge + Fly.io)"
    },
    {
      "url": "http://localhost:8080",
      "description": "Local development server"
    }
  ],
  "tags": [
    {
      "name": "Networks & Overview",
      "description": "Indexed networks, global/per-network market totals, and historical volume/swap/TVL time series."
    },
    {
      "name": "Hooks",
      "description": "Uniswap v4 hook leaderboard, contract metadata, verified Solidity source code, runtime bytecode, and LLM security/behaviour analysis."
    },
    {
      "name": "Pools",
      "description": "Uniswap v4 pool leaderboard, pool details, and 7-day activity series."
    },
    {
      "name": "Swaps & Liquidity",
      "description": "Cursor-paginated swap and ModifyLiquidity event feeds, plus the real-time Server-Sent Events stream."
    },
    {
      "name": "Tokens",
      "description": "Indexed tokens with trusted USD prices, hourly price history, and v4 pool TVL/volume."
    },
    {
      "name": "Health",
      "description": "Liveness, ClickHouse readiness, and per-network indexing freshness probes."
    }
  ],
  "paths": {
    "/v1/chains": {
      "get": {
        "tags": ["Networks & Overview"],
        "operationId": "listChains",
        "summary": "List indexed networks",
        "description": "Returns all indexed EVM networks with their latest indexed block, 24h and all-time swaps, volume, traders, pools, TVL, and hooked shares.",
        "parameters": [
          {
            "name": "chain_id",
            "in": "query",
            "description": "Optional numeric EVM chain ID (e.g. `1` for Ethereum, `8453` for Base, `130` for Unichain).",
            "schema": { "type": "integer", "example": 8453 }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Metric to sort networks by.",
            "schema": {
              "type": "string",
              "enum": ["volume_usd_24h", "volume_usd", "tvl_usd", "swaps_24h", "swaps", "pools", "chain_id"],
              "default": "volume_usd_24h"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of indexed networks with overview metrics.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data", "meta"],
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/ChainOverview" } },
                    "meta": {
                      "type": "object",
                      "required": ["total"],
                      "properties": { "total": { "type": "integer", "example": 19 } }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/overview": {
      "get": {
        "tags": ["Networks & Overview"],
        "operationId": "getOverview",
        "summary": "Market overview & hooked share",
        "description": "Aggregate Uniswap v4 metrics (24h and all-time volume, swaps, traders, pools, TVL, and hooked share ratios) across all networks or a single network, alongside the per-network breakdown.",
        "parameters": [
          {
            "name": "chain_id",
            "in": "query",
            "description": "Filter overview to a single EVM chain ID. Omit for all networks.",
            "schema": { "type": "integer", "example": 8453 }
          }
        ],
        "responses": {
          "200": {
            "description": "Aggregate totals and per-network breakdown.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": {
                    "data": {
                      "type": "object",
                      "required": ["scope", "totals", "chains"],
                      "properties": {
                        "scope": { "type": "string", "example": "all" },
                        "totals": { "$ref": "#/components/schemas/MarketTotals" },
                        "chains": { "type": "array", "items": { "$ref": "#/components/schemas/ChainOverview" } }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/series": {
      "get": {
        "tags": ["Networks & Overview"],
        "operationId": "getSeries",
        "summary": "Volume, swaps & traders time series",
        "description": "Hourly or daily time series of swaps, hooked swaps, unique traders, USD volume, and hooked USD volume. Can be scoped to a network, a hook contract, a single pool, or hooked/vanilla pools.",
        "parameters": [
          {
            "name": "chain_id",
            "in": "query",
            "description": "Filter by numeric EVM chain ID.",
            "schema": { "type": "integer", "example": 8453 }
          },
          {
            "name": "hooks",
            "in": "query",
            "description": "Filter by hook contract address (`0x` + 40 hex).",
            "schema": { "type": "string" }
          },
          {
            "name": "pool_id",
            "in": "query",
            "description": "Filter by pool ID (`0x` + 64 hex).",
            "schema": { "type": "string" }
          },
          {
            "name": "hooked",
            "in": "query",
            "description": "`true` = only pools with a hook, `false` = only vanilla pools.",
            "schema": { "type": "boolean" }
          },
          {
            "name": "interval",
            "in": "query",
            "description": "Bucket size (`hour` or `day`).",
            "schema": { "type": "string", "enum": ["hour", "day"], "default": "hour" }
          },
          {
            "name": "days",
            "in": "query",
            "description": "Lookback window in days (`1..365`, default `7`).",
            "schema": { "type": "integer", "minimum": 1, "maximum": 365, "default": 7 }
          }
        ],
        "responses": {
          "200": {
            "description": "Time series points ordered ascending by `t`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data", "meta"],
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/SeriesPoint" } },
                    "meta": { "$ref": "#/components/schemas/SeriesMeta" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/tvl": {
      "get": {
        "tags": ["Networks & Overview"],
        "operationId": "getTvlSeries",
        "summary": "Daily TVL time series",
        "description": "Daily Total Value Locked (TVL) and hooked TVL in USD at the end of each UTC day (with today showing the latest hourly snapshot). Can be scoped by network, hook address, or pool ID.",
        "parameters": [
          {
            "name": "chain_id",
            "in": "query",
            "description": "Filter by numeric EVM chain ID.",
            "schema": { "type": "integer", "example": 1 }
          },
          {
            "name": "hooks",
            "in": "query",
            "description": "Filter by hook contract address (`0x` + 40 hex).",
            "schema": { "type": "string" }
          },
          {
            "name": "pool_id",
            "in": "query",
            "description": "Filter by pool ID (`0x` + 64 hex).",
            "schema": { "type": "string" }
          },
          {
            "name": "days",
            "in": "query",
            "description": "Lookback window in days (`1..365`, default `90`).",
            "schema": { "type": "integer", "minimum": 1, "maximum": 365, "default": 90 }
          }
        ],
        "responses": {
          "200": {
            "description": "Daily TVL points ordered ascending by `t`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data", "meta"],
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/TvlPoint" } },
                    "meta": { "$ref": "#/components/schemas/SeriesMeta" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/hooks": {
      "get": {
        "tags": ["Hooks"],
        "operationId": "listHooks",
        "summary": "List and filter hook contracts",
        "description": "Paginated leaderboard and directory of Uniswap v4 hook contracts across all indexed networks. Supports filtering by network, LLM category, Sourcify verification status, proxy detection, risk level, v4 permission bit, behaviour tag, or name/address search.",
        "parameters": [
          {
            "name": "chain_id",
            "in": "query",
            "description": "Filter by numeric EVM chain ID.",
            "schema": { "type": "integer", "example": 8453 }
          },
          {
            "name": "category",
            "in": "query",
            "description": "Filter by hook category.",
            "schema": {
              "type": "string",
              "enum": [
                "dynamic-fee",
                "limit-orders",
                "twamm",
                "oracle",
                "access-control",
                "mev-protection",
                "rewards",
                "launchpad",
                "auction",
                "liquidity-management",
                "custom-accounting",
                "fee-sharing",
                "token",
                "utility",
                "other"
              ]
            }
          },
          {
            "name": "verified",
            "in": "query",
            "description": "Filter by whether the contract source is verified on Sourcify.",
            "schema": { "type": "boolean" }
          },
          {
            "name": "is_proxy",
            "in": "query",
            "description": "Filter by whether the hook is an EIP-1167 clone or EIP-1967 proxy.",
            "schema": { "type": "boolean" }
          },
          {
            "name": "risk_level",
            "in": "query",
            "description": "Filter by LLM-assessed risk level.",
            "schema": { "type": "string", "enum": ["low", "medium", "high", "unknown", "unrated"] }
          },
          {
            "name": "permission",
            "in": "query",
            "description": "Filter hooks that enable a specific v4 callback flag encoded in their address.",
            "schema": {
              "type": "string",
              "enum": [
                "beforeInitialize",
                "afterInitialize",
                "beforeAddLiquidity",
                "afterAddLiquidity",
                "beforeRemoveLiquidity",
                "afterRemoveLiquidity",
                "beforeSwap",
                "afterSwap",
                "beforeDonate",
                "afterDonate",
                "beforeSwapReturnDelta",
                "afterSwapReturnDelta",
                "afterAddLiquidityReturnDelta",
                "afterRemoveLiquidityReturnDelta"
              ]
            }
          },
          {
            "name": "tag",
            "in": "query",
            "description": "Filter by heuristic behaviour tag (e.g. `dynamic-fee`, `return-delta`, `ownable`, `upgradeable`).",
            "schema": { "type": "string" }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Search by verified contract name or `0x` address prefix.",
            "schema": { "type": "string" }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Field to rank hooks by descending (`first_seen` = newest first).",
            "schema": {
              "type": "string",
              "enum": ["volume_usd_24h", "volume_usd", "tvl_usd", "swaps_24h", "swaps", "pools", "first_seen"],
              "default": "volume_usd_24h"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size (`1..500`, default `50`).",
            "schema": { "type": "integer", "minimum": 1, "maximum": 500, "default": 50 }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Row offset (`0..10000`, default `0`).",
            "schema": { "type": "integer", "minimum": 0, "maximum": 10000, "default": 0 }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of hook contracts.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data", "meta"],
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/Hook" } },
                    "meta": { "$ref": "#/components/schemas/PageMeta" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/hooks/{chain_id}/{address}": {
      "get": {
        "tags": ["Hooks"],
        "operationId": "getHook",
        "summary": "Get hook details, pools, contract & explanation",
        "description": "Complete profile of a single hook contract: activity metrics, paginated pools using the hook, hourly activity series, decoded contract metadata (ABI, evmole functions, storage layout, permissions), and model-generated explanation with security findings.",
        "parameters": [
          {
            "name": "chain_id",
            "in": "path",
            "required": true,
            "description": "Numeric EVM chain ID.",
            "schema": { "type": "integer", "example": 8453 }
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "description": "Hook contract address (`0x` + 40 hex).",
            "schema": { "type": "string" }
          },
          {
            "name": "pools_sort",
            "in": "query",
            "description": "Sort order for the hook's pools.",
            "schema": {
              "type": "string",
              "enum": ["volume_usd_24h", "volume_usd", "tvl_usd", "swaps_24h", "swaps", "created_at"],
              "default": "volume_usd_24h"
            }
          },
          {
            "name": "pools_limit",
            "in": "query",
            "description": "Number of pools to return (`1..500`, default `50`).",
            "schema": { "type": "integer", "minimum": 1, "maximum": 500, "default": 50 }
          },
          {
            "name": "pools_offset",
            "in": "query",
            "description": "Offset into the hook's pools (`0..10000`, default `0`).",
            "schema": { "type": "integer", "minimum": 0, "maximum": 10000, "default": 0 }
          },
          {
            "name": "series_days",
            "in": "query",
            "description": "Days of hourly activity series to include (`1..90`, default `7`).",
            "schema": { "type": "integer", "minimum": 1, "maximum": 90, "default": 7 }
          }
        ],
        "responses": {
          "200": {
            "description": "Hook detail envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": {
                    "data": { "$ref": "#/components/schemas/HookDetail" }
                  }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/hooks/{chain_id}/{address}/source": {
      "get": {
        "tags": ["Hooks"],
        "operationId": "getHookSource",
        "summary": "Get verified Solidity source tree",
        "description": "Returns the verified Solidity source files from Sourcify for this hook (or its proxy implementation), ordered with the primary hook contract file first.",
        "parameters": [
          {
            "name": "chain_id",
            "in": "path",
            "required": true,
            "schema": { "type": "integer", "example": 8453 }
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Verified source files.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": {
                    "data": { "$ref": "#/components/schemas/HookSource" }
                  }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/hooks/{chain_id}/{address}/code": {
      "get": {
        "tags": ["Hooks"],
        "operationId": "getHookCode",
        "summary": "Get runtime bytecode",
        "description": "Returns the runtime bytecode (`0x`-hex), keccak256 code hash, and byte size of the hook contract.",
        "parameters": [
          {
            "name": "chain_id",
            "in": "path",
            "required": true,
            "schema": { "type": "integer", "example": 8453 }
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Runtime bytecode.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": {
                    "data": { "$ref": "#/components/schemas/HookCode" }
                  }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/pools": {
      "get": {
        "tags": ["Pools"],
        "operationId": "listPools",
        "summary": "List and filter pools",
        "description": "Paginated leaderboard of Uniswap v4 pools across all indexed networks. Filter by network, hooked/vanilla status, hook contract address, token currency, or fee tier.",
        "parameters": [
          {
            "name": "chain_id",
            "in": "query",
            "description": "Filter by numeric EVM chain ID.",
            "schema": { "type": "integer", "example": 1 }
          },
          {
            "name": "hooked",
            "in": "query",
            "description": "`true` = only pools with a hook, `false` = only vanilla pools.",
            "schema": { "type": "boolean" }
          },
          {
            "name": "hooks",
            "in": "query",
            "description": "Filter by hook contract address (`0x` + 40 hex).",
            "schema": { "type": "string" }
          },
          {
            "name": "token",
            "in": "query",
            "description": "Filter pools containing this token address (`0x` + 40 hex) as either `currency0` or `currency1`.",
            "schema": { "type": "string" }
          },
          {
            "name": "currency0",
            "in": "query",
            "description": "Filter by exact `currency0` address (`0x` + 40 hex).",
            "schema": { "type": "string" }
          },
          {
            "name": "currency1",
            "in": "query",
            "description": "Filter by exact `currency1` address (`0x` + 40 hex).",
            "schema": { "type": "string" }
          },
          {
            "name": "fee",
            "in": "query",
            "description": "Filter by fee in pips (e.g. `500`, `3000`, or `8388608` for dynamic fee).",
            "schema": { "type": "integer" }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Metric to rank pools by descending.",
            "schema": {
              "type": "string",
              "enum": ["volume_usd_24h", "volume_usd", "tvl_usd", "swaps_24h", "swaps", "created_at"],
              "default": "volume_usd_24h"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size (`1..500`, default `50`).",
            "schema": { "type": "integer", "minimum": 1, "maximum": 500, "default": 50 }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Row offset (`0..10000`, default `0`).",
            "schema": { "type": "integer", "minimum": 0, "maximum": 10000, "default": 0 }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of pools.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data", "meta"],
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/Pool" } },
                    "meta": { "$ref": "#/components/schemas/PageMeta" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/pools/{chain_id}/{pool_id}": {
      "get": {
        "tags": ["Pools"],
        "operationId": "getPool",
        "summary": "Get pool details & activity series",
        "description": "Returns a single Uniswap v4 pool by `(chain_id, pool_id)` along with its hourly volume/swap series.",
        "parameters": [
          {
            "name": "chain_id",
            "in": "path",
            "required": true,
            "schema": { "type": "integer", "example": 1 }
          },
          {
            "name": "pool_id",
            "in": "path",
            "required": true,
            "description": "Bytes32 pool ID (`0x` + 64 hex).",
            "schema": { "type": "string" }
          },
          {
            "name": "series_days",
            "in": "query",
            "description": "Days of hourly series to include (`1..90`, default `7`).",
            "schema": { "type": "integer", "minimum": 1, "maximum": 90, "default": 7 }
          }
        ],
        "responses": {
          "200": {
            "description": "Pool detail envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": {
                    "data": {
                      "type": "object",
                      "required": ["pool", "series"],
                      "properties": {
                        "pool": { "$ref": "#/components/schemas/Pool" },
                        "series": { "type": "array", "items": { "$ref": "#/components/schemas/SeriesPoint" } }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/swaps": {
      "get": {
        "tags": ["Swaps & Liquidity"],
        "operationId": "listSwaps",
        "summary": "List swaps (cursor & offset pagination)",
        "description": "Returns decoded Uniswap v4 `Swap` events ordered newest first, enriched with token symbols, decimal-adjusted amounts, post-swap price, and tracked USD size. Pass `meta.next_cursor` as `cursor` to paginate backwards through history.",
        "parameters": [
          {
            "name": "chain_id",
            "in": "query",
            "description": "Filter by numeric EVM chain ID.",
            "schema": { "type": "integer", "example": 8453 }
          },
          {
            "name": "pool_id",
            "in": "query",
            "description": "Filter by pool ID (`0x` + 64 hex).",
            "schema": { "type": "string" }
          },
          {
            "name": "hooks",
            "in": "query",
            "description": "Filter by hook contract address (`0x` + 40 hex).",
            "schema": { "type": "string" }
          },
          {
            "name": "hooked",
            "in": "query",
            "description": "`true` = only hooked pools, `false` = only vanilla pools.",
            "schema": { "type": "boolean" }
          },
          {
            "name": "trader",
            "in": "query",
            "description": "Filter by transaction sender address (`tx_from`, `0x` + 40 hex).",
            "schema": { "type": "string" }
          },
          {
            "name": "tx_hash",
            "in": "query",
            "description": "Filter by transaction hash (`0x` + 64 hex).",
            "schema": { "type": "string" }
          },
          {
            "name": "from_timestamp",
            "in": "query",
            "description": "Minimum block timestamp (unix seconds, inclusive).",
            "schema": { "type": "integer" }
          },
          {
            "name": "to_timestamp",
            "in": "query",
            "description": "Maximum block timestamp (unix seconds, inclusive).",
            "schema": { "type": "integer" }
          },
          {
            "name": "min_usd",
            "in": "query",
            "description": "Minimum USD swap size (e.g. `10000` for whale swaps).",
            "schema": { "type": "number", "minimum": 0 }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque keyset cursor (`meta.next_cursor` from the previous response).",
            "schema": { "type": "string" }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Optional offset (`0..5000`); cannot be combined with `cursor`.",
            "schema": { "type": "integer", "minimum": 0, "maximum": 5000 }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size (`1..500`, default `50`).",
            "schema": { "type": "integer", "minimum": 1, "maximum": 500, "default": 50 }
          }
        ],
        "responses": {
          "200": {
            "description": "Cursor-paginated list of swaps.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data", "meta"],
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/Swap" } },
                    "meta": { "$ref": "#/components/schemas/CursorMeta" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/liquidity": {
      "get": {
        "tags": ["Swaps & Liquidity"],
        "operationId": "listLiquidityEvents",
        "summary": "List ModifyLiquidity events (cursor & offset pagination)",
        "description": "Returns decoded Uniswap v4 `ModifyLiquidity` events (liquidity additions and removals) ordered newest first, enriched with pool currencies and token metadata.",
        "parameters": [
          {
            "name": "chain_id",
            "in": "query",
            "description": "Filter by numeric EVM chain ID.",
            "schema": { "type": "integer", "example": 1 }
          },
          {
            "name": "pool_id",
            "in": "query",
            "description": "Filter by pool ID (`0x` + 64 hex).",
            "schema": { "type": "string" }
          },
          {
            "name": "hooks",
            "in": "query",
            "description": "Filter by hook contract address (`0x` + 40 hex).",
            "schema": { "type": "string" }
          },
          {
            "name": "hooked",
            "in": "query",
            "description": "`true` = only hooked pools, `false` = only vanilla pools.",
            "schema": { "type": "boolean" }
          },
          {
            "name": "sender",
            "in": "query",
            "description": "Filter by `ModifyLiquidity` caller (`msg.sender` into PoolManager, `0x` + 40 hex).",
            "schema": { "type": "string" }
          },
          {
            "name": "trader",
            "in": "query",
            "description": "Filter by EOA transaction sender (`tx_from`, `0x` + 40 hex).",
            "schema": { "type": "string" }
          },
          {
            "name": "tx_hash",
            "in": "query",
            "description": "Filter by transaction hash (`0x` + 64 hex).",
            "schema": { "type": "string" }
          },
          {
            "name": "from_timestamp",
            "in": "query",
            "description": "Minimum block timestamp (unix seconds, inclusive; defaults to last 7 days when unscoped).",
            "schema": { "type": "integer" }
          },
          {
            "name": "to_timestamp",
            "in": "query",
            "description": "Maximum block timestamp (unix seconds, inclusive).",
            "schema": { "type": "integer" }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque keyset cursor (`meta.next_cursor` from the previous response).",
            "schema": { "type": "string" }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Optional offset (`0..5000`); cannot be combined with `cursor`.",
            "schema": { "type": "integer", "minimum": 0, "maximum": 5000 }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size (`1..500`, default `50`).",
            "schema": { "type": "integer", "minimum": 1, "maximum": 500, "default": 50 }
          }
        ],
        "responses": {
          "200": {
            "description": "Cursor-paginated list of ModifyLiquidity events.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data", "meta"],
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/LiquidityEvent" } },
                    "meta": { "$ref": "#/components/schemas/CursorMeta" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/tokens": {
      "get": {
        "tags": ["Tokens"],
        "operationId": "listTokens",
        "summary": "List tokens with USD prices, TVL & volume",
        "description": "Paginated leaderboard of tokens active in Uniswap v4 pools, enriched with their latest USD price, trusted anchor status, pool counts, v4 TVL, and 24h pool volume.",
        "parameters": [
          {
            "name": "chain_id",
            "in": "query",
            "description": "Filter by numeric EVM chain ID.",
            "schema": { "type": "integer", "example": 1 }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Search by token symbol, name, or `0x` address prefix.",
            "schema": { "type": "string" }
          },
          {
            "name": "trusted",
            "in": "query",
            "description": "Filter by whether the token's USD price is backed by a trusted anchor or deep pool.",
            "schema": { "type": "boolean" }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Metric to rank tokens by descending.",
            "schema": {
              "type": "string",
              "enum": ["tvl_usd", "volume_usd_24h", "pools", "hooked_pools"],
              "default": "tvl_usd"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size (`1..500`, default `50`).",
            "schema": { "type": "integer", "minimum": 1, "maximum": 500, "default": 50 }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Row offset (`0..10000`, default `0`).",
            "schema": { "type": "integer", "minimum": 0, "maximum": 10000, "default": 0 }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of tokens.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data", "meta"],
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/TokenSummary" } },
                    "meta": { "$ref": "#/components/schemas/PageMeta" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/tokens/{chain_id}/{address}": {
      "get": {
        "tags": ["Tokens"],
        "operationId": "getToken",
        "summary": "Get token details, price history & top pools",
        "description": "Returns a token's metadata, current USD price, hourly USD price history, and top Uniswap v4 pools containing the token.",
        "parameters": [
          {
            "name": "chain_id",
            "in": "path",
            "required": true,
            "schema": { "type": "integer", "example": 1 }
          },
          {
            "name": "address",
            "in": "path",
            "required": true,
            "description": "Token contract address (`0x` + 40 hex; `0x0000000000000000000000000000000000000000` for native currency).",
            "schema": { "type": "string" }
          },
          {
            "name": "days",
            "in": "query",
            "description": "Days of hourly price history to return (`1..90`, default `7`).",
            "schema": { "type": "integer", "minimum": 1, "maximum": 90, "default": 7 }
          },
          {
            "name": "pools_limit",
            "in": "query",
            "description": "Number of top pools to include (`1..100`, default `25`).",
            "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 25 }
          }
        ],
        "responses": {
          "200": {
            "description": "Token detail envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": {
                    "data": {
                      "type": "object",
                      "required": ["token", "price_history", "top_pools"],
                      "properties": {
                        "token": { "$ref": "#/components/schemas/TokenSummary" },
                        "price_history": { "type": "array", "items": { "$ref": "#/components/schemas/TokenPricePoint" } },
                        "top_pools": { "type": "array", "items": { "$ref": "#/components/schemas/Pool" } }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/live": {
      "get": {
        "tags": ["Swaps & Liquidity"],
        "operationId": "streamLiveSwaps",
        "summary": "Real-time Server-Sent Events (SSE) stream",
        "description": "Streams newly indexed swaps (`event: swaps`), catch-up skip counts (`event: skipped`), and chain head checkpoints (`event: sync`) in real time. Capped at 8 concurrent streams per IP.",
        "parameters": [
          {
            "name": "chain_id",
            "in": "query",
            "description": "Filter live swaps to a single EVM chain ID.",
            "schema": { "type": "integer" }
          },
          {
            "name": "hooked",
            "in": "query",
            "description": "`true` = only hooked swaps, `false` = only vanilla swaps.",
            "schema": { "type": "boolean" }
          }
        ],
        "responses": {
          "200": {
            "description": "SSE event stream (`text/event-stream`).",
            "content": {
              "text/event-stream": {
                "schema": { "type": "string" }
              }
            }
          }
        }
      }
    },
    "/health": {
      "get": {
        "tags": ["Health"],
        "operationId": "getHealth",
        "summary": "Liveness check",
        "description": "Always returns HTTP `200` while the API process is serving requests, along with ClickHouse latency.",
        "responses": {
          "200": {
            "description": "Server is alive.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": { "type": "boolean" },
                    "db": { "type": "string" },
                    "db_ms": { "type": "integer" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/health/sync": {
      "get": {
        "tags": ["Health"],
        "operationId": "getHealthSync",
        "summary": "Per-network indexing freshness",
        "description": "Returns HTTP `200` when all enabled networks are advancing within their `stall_secs` threshold, or `503` if any network checkpoint is stalled.",
        "responses": {
          "200": {
            "description": "Per-network checkpoint ages.",
            "content": {
              "application/json": {
                "schema": { "type": "object" }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "responses": {
      "NotFound": {
        "description": "Resource not found.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ApiError" }
          }
        }
      }
    },
    "schemas": {
      "ApiError": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": { "type": "string", "example": "not found" }
        }
      },
      "PageMeta": {
        "type": "object",
        "required": ["limit", "offset", "total", "has_more"],
        "properties": {
          "limit": { "type": "integer", "example": 50 },
          "offset": { "type": "integer", "example": 0 },
          "total": { "type": "integer", "example": 1420 },
          "has_more": { "type": "boolean", "example": true },
          "next_offset": { "type": ["integer", "null"], "example": 50 }
        }
      },
      "CursorMeta": {
        "type": "object",
        "required": ["limit", "has_more"],
        "properties": {
          "limit": { "type": "integer", "example": 50 },
          "offset": { "type": ["integer", "null"] },
          "has_more": { "type": "boolean", "example": true },
          "next_cursor": { "type": ["string", "null"], "example": "1760520000:8453:21450123:4" }
        }
      },
      "SeriesMeta": {
        "type": "object",
        "required": ["days", "count"],
        "properties": {
          "interval": { "type": ["string", "null"], "example": "hour" },
          "days": { "type": "integer", "example": 7 },
          "count": { "type": "integer", "example": 168 }
        }
      },
      "ChainOverview": {
        "type": "object",
        "required": [
          "chain_id",
          "name",
          "native_symbol",
          "last_block",
          "last_block_timestamp",
          "pools",
          "hooked_pools",
          "swaps",
          "hooked_swaps",
          "swaps_24h",
          "hooked_swaps_24h",
          "traders_24h",
          "volume_usd",
          "volume_usd_24h",
          "hooked_volume_usd_24h",
          "tvl_usd",
          "hooked_tvl_usd"
        ],
        "properties": {
          "chain_id": { "type": "integer", "example": 8453 },
          "name": { "type": "string", "example": "Base" },
          "native_symbol": { "type": "string", "example": "ETH" },
          "last_block": { "type": "integer", "example": 29104512 },
          "last_block_timestamp": { "type": "integer", "example": 1760521000 },
          "pools": { "type": "integer" },
          "hooked_pools": { "type": "integer" },
          "swaps": { "type": "integer" },
          "hooked_swaps": { "type": "integer" },
          "swaps_24h": { "type": "integer" },
          "hooked_swaps_24h": { "type": "integer" },
          "traders_24h": { "type": "integer" },
          "volume_usd": { "type": "number" },
          "volume_usd_24h": { "type": "number" },
          "hooked_volume_usd_24h": { "type": "number" },
          "tvl_usd": { "type": "number" },
          "hooked_tvl_usd": { "type": "number" }
        }
      },
      "MarketTotals": {
        "type": "object",
        "properties": {
          "chains": { "type": "integer" },
          "pools": { "type": "integer" },
          "hooked_pools": { "type": "integer" },
          "hooked_pool_share": { "type": "number" },
          "swaps": { "type": "integer" },
          "hooked_swaps": { "type": "integer" },
          "swaps_24h": { "type": "integer" },
          "hooked_swaps_24h": { "type": "integer" },
          "hooked_swap_share_24h": { "type": "number" },
          "traders_24h": { "type": "integer" },
          "volume_usd": { "type": "number" },
          "volume_usd_24h": { "type": "number" },
          "hooked_volume_usd_24h": { "type": "number" },
          "hooked_volume_share_24h": { "type": "number" },
          "tvl_usd": { "type": "number" },
          "hooked_tvl_usd": { "type": "number" },
          "hooked_tvl_share": { "type": "number" }
        }
      },
      "SeriesPoint": {
        "type": "object",
        "required": ["t", "swaps", "hooked_swaps", "traders", "volume_usd", "hooked_volume_usd"],
        "properties": {
          "t": { "type": "integer", "description": "Bucket start timestamp (unix seconds)." },
          "swaps": { "type": "integer" },
          "hooked_swaps": { "type": "integer" },
          "traders": { "type": "integer" },
          "volume_usd": { "type": "number" },
          "hooked_volume_usd": { "type": "number" }
        }
      },
      "TvlPoint": {
        "type": "object",
        "required": ["t", "tvl_usd", "hooked_tvl_usd"],
        "properties": {
          "t": { "type": "integer", "description": "UTC day start timestamp (unix seconds)." },
          "tvl_usd": { "type": "number" },
          "hooked_tvl_usd": { "type": "number" }
        }
      },
      "Hook": {
        "type": "object",
        "required": [
          "chain_id",
          "hooks",
          "pools",
          "swaps",
          "swaps_24h",
          "traders_24h",
          "first_seen",
          "last_swap_at",
          "volume_usd",
          "volume_usd_24h",
          "tvl_usd",
          "permissions",
          "name",
          "verified",
          "is_proxy",
          "tags",
          "category",
          "risk_level",
          "risk_estimated"
        ],
        "properties": {
          "chain_id": { "type": "integer" },
          "hooks": { "type": "string" },
          "pools": { "type": "integer" },
          "swaps": { "type": "integer" },
          "swaps_24h": { "type": "integer" },
          "traders_24h": { "type": "integer" },
          "first_seen": { "type": "integer" },
          "last_swap_at": { "type": "integer" },
          "volume_usd": { "type": "number" },
          "volume_usd_24h": { "type": "number" },
          "tvl_usd": { "type": "number" },
          "tvl_note": { "type": "string" },
          "permissions": { "type": "array", "items": { "type": "string" } },
          "name": { "type": "string" },
          "verified": { "type": "boolean" },
          "is_proxy": { "type": "boolean" },
          "tags": { "type": "array", "items": { "type": "string" } },
          "category": { "type": "string" },
          "risk_level": { "type": "string" },
          "risk_estimated": { "type": "boolean" }
        }
      },
      "HookContract": {
        "type": "object",
        "properties": {
          "permissions": { "type": "array", "items": { "type": "string" } },
          "has_code": { "type": "boolean" },
          "code_hash": { "type": "string" },
          "code_size": { "type": "integer" },
          "is_proxy": { "type": "boolean" },
          "implementation": { "type": "string" },
          "selectors": { "type": "array", "items": { "type": "string" } },
          "verified": { "type": "boolean" },
          "verified_source": { "type": "string" },
          "name": { "type": "string" },
          "compiler": { "type": "string" },
          "abi": { "type": ["array", "null"], "items": { "type": "object" } },
          "functions": { "type": ["array", "null"], "items": { "type": "object" } },
          "storage_layout": { "type": ["array", "null"], "items": { "type": "object" } },
          "tags": { "type": "array", "items": { "type": "string" } },
          "explain_model": { "type": "string" },
          "code_checked_at": { "type": "integer" },
          "abi_checked_at": { "type": "integer" },
          "explained_at": { "type": "integer" },
          "sourcify_url": { "type": ["string", "null"] },
          "source_files": { "type": "array", "items": { "type": "string" } },
          "source_primary": { "type": "string" }
        }
      },
      "HookExplanation": {
        "type": "object",
        "properties": {
          "summary": { "type": "string" },
          "category": { "type": "string" },
          "what_it_does": { "type": "array", "items": { "type": "string" } },
          "swap_behaviour": { "type": "string" },
          "liquidity_behaviour": { "type": "string" },
          "fee_behaviour": { "type": "string" },
          "permissions_used": { "type": "string" },
          "admin_controls": { "type": "string" },
          "security": {
            "type": "object",
            "properties": {
              "risk_level": { "type": "string" },
              "findings": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "title": { "type": "string" },
                    "severity": { "type": "string" },
                    "detail": { "type": "string" }
                  }
                }
              },
              "centralization": { "type": "string" },
              "user_funds_exposure": { "type": "string" }
            }
          },
          "confidence": { "type": "string" },
          "evidence": { "type": "string" }
        }
      },
      "HookDetail": {
        "type": "object",
        "required": ["hook", "pools", "pools_meta", "series", "disclaimer"],
        "properties": {
          "hook": { "$ref": "#/components/schemas/Hook" },
          "pools": { "type": "array", "items": { "$ref": "#/components/schemas/Pool" } },
          "pools_meta": { "$ref": "#/components/schemas/PageMeta" },
          "series": { "type": "array", "items": { "$ref": "#/components/schemas/SeriesPoint" } },
          "contract": { "oneOf": [{ "$ref": "#/components/schemas/HookContract" }, { "type": "null" }] },
          "explanation": { "oneOf": [{ "$ref": "#/components/schemas/HookExplanation" }, { "type": "null" }] },
          "disclaimer": { "type": "string" }
        }
      },
      "HookSource": {
        "type": "object",
        "required": ["chain_id", "address", "name", "verified_source", "primary", "files"],
        "properties": {
          "chain_id": { "type": "integer" },
          "address": { "type": "string" },
          "name": { "type": "string" },
          "verified_source": { "type": "string" },
          "primary": { "type": "string" },
          "sourcify_url": { "type": ["string", "null"] },
          "files": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["path", "content"],
              "properties": {
                "path": { "type": "string" },
                "content": { "type": "string" }
              }
            }
          }
        }
      },
      "HookCode": {
        "type": "object",
        "required": ["chain_id", "address", "has_code", "code_hash", "code_size", "bytecode"],
        "properties": {
          "chain_id": { "type": "integer" },
          "address": { "type": "string" },
          "has_code": { "type": "boolean" },
          "code_hash": { "type": "string" },
          "code_size": { "type": "integer" },
          "bytecode": { "type": "string" }
        }
      },
      "Pool": {
        "type": "object",
        "required": [
          "chain_id",
          "pool_id",
          "currency0",
          "currency1",
          "symbol0",
          "symbol1",
          "decimals0",
          "decimals1",
          "fee",
          "tick_spacing",
          "hooks",
          "is_hooked",
          "created_at",
          "swaps",
          "swaps_24h",
          "traders_24h",
          "last_price",
          "last_swap_at",
          "volume_usd",
          "volume_usd_24h",
          "tvl_usd",
          "tvl_partial",
          "tvl_note"
        ],
        "properties": {
          "chain_id": { "type": "integer" },
          "pool_id": { "type": "string" },
          "currency0": { "type": "string" },
          "currency1": { "type": "string" },
          "symbol0": { "type": "string" },
          "symbol1": { "type": "string" },
          "decimals0": { "type": "integer" },
          "decimals1": { "type": "integer" },
          "fee": { "type": "integer" },
          "tick_spacing": { "type": "integer" },
          "hooks": { "type": "string" },
          "is_hooked": { "type": "boolean" },
          "created_at": { "type": "integer" },
          "swaps": { "type": "integer" },
          "swaps_24h": { "type": "integer" },
          "traders_24h": { "type": "integer" },
          "last_price": { "type": "number" },
          "last_swap_at": { "type": "integer" },
          "volume_usd": { "type": "number" },
          "volume_usd_24h": { "type": "number" },
          "tvl_usd": { "type": "number" },
          "tvl_partial": { "type": "boolean" },
          "tvl_note": { "type": "string" }
        }
      },
      "Swap": {
        "type": "object",
        "required": [
          "chain_id",
          "chain_name",
          "pool_id",
          "hooks",
          "is_hooked",
          "currency0",
          "currency1",
          "symbol0",
          "symbol1",
          "amount0",
          "amount1",
          "price",
          "fee",
          "amount_usd",
          "block_number",
          "block_timestamp",
          "tx_hash",
          "tx_from",
          "log_index"
        ],
        "properties": {
          "chain_id": { "type": "integer" },
          "chain_name": { "type": "string" },
          "pool_id": { "type": "string" },
          "hooks": { "type": "string" },
          "is_hooked": { "type": "boolean" },
          "currency0": { "type": "string" },
          "currency1": { "type": "string" },
          "symbol0": { "type": "string" },
          "symbol1": { "type": "string" },
          "amount0": { "type": "number" },
          "amount1": { "type": "number" },
          "price": { "type": "number" },
          "fee": { "type": "integer" },
          "amount_usd": { "type": "number" },
          "block_number": { "type": "integer" },
          "block_timestamp": { "type": "integer" },
          "tx_hash": { "type": "string" },
          "tx_from": { "type": "string" },
          "log_index": { "type": "integer" }
        }
      },
      "LiquidityEvent": {
        "type": "object",
        "required": [
          "chain_id",
          "chain_name",
          "pool_id",
          "hooks",
          "is_hooked",
          "currency0",
          "currency1",
          "symbol0",
          "symbol1",
          "decimals0",
          "decimals1",
          "action",
          "sender",
          "tick_lower",
          "tick_upper",
          "liquidity_delta",
          "salt",
          "block_number",
          "block_timestamp",
          "tx_hash",
          "tx_from",
          "log_index"
        ],
        "properties": {
          "chain_id": { "type": "integer" },
          "chain_name": { "type": "string" },
          "pool_id": { "type": "string" },
          "hooks": { "type": "string" },
          "is_hooked": { "type": "boolean" },
          "currency0": { "type": "string" },
          "currency1": { "type": "string" },
          "symbol0": { "type": "string" },
          "symbol1": { "type": "string" },
          "decimals0": { "type": "integer" },
          "decimals1": { "type": "integer" },
          "action": { "type": "string", "enum": ["add", "remove", "modify"] },
          "sender": { "type": "string" },
          "tick_lower": { "type": "integer" },
          "tick_upper": { "type": "integer" },
          "liquidity_delta": { "type": "string" },
          "salt": { "type": "string" },
          "block_number": { "type": "integer" },
          "block_timestamp": { "type": "integer" },
          "tx_hash": { "type": "string" },
          "tx_from": { "type": "string" },
          "log_index": { "type": "integer" }
        }
      },
      "TokenSummary": {
        "type": "object",
        "required": [
          "chain_id",
          "chain_name",
          "address",
          "symbol",
          "name",
          "decimals",
          "price_usd",
          "trusted",
          "pools",
          "hooked_pools",
          "tvl_usd",
          "volume_usd_24h"
        ],
        "properties": {
          "chain_id": { "type": "integer" },
          "chain_name": { "type": "string" },
          "address": { "type": "string" },
          "symbol": { "type": "string" },
          "name": { "type": "string" },
          "decimals": { "type": "integer" },
          "price_usd": { "type": "number" },
          "trusted": { "type": "boolean" },
          "pools": { "type": "integer" },
          "hooked_pools": { "type": "integer" },
          "tvl_usd": { "type": "number" },
          "volume_usd_24h": { "type": "number" }
        }
      },
      "TokenPricePoint": {
        "type": "object",
        "required": ["t", "price_usd", "source", "depth_usd"],
        "properties": {
          "t": { "type": "integer" },
          "price_usd": { "type": "number" },
          "source": { "type": "string" },
          "depth_usd": { "type": "number" }
        }
      }
    }
  }
}
