{
  "openapi": "3.1.1",
  "info": {
    "title": "Tirio DEX Aggregator API",
    "version": "1.0.0",
    "summary": "Quotes and ready-to-send swap transactions across the DEXes of a chain.",
    "description": "A public, read-only JSON API. It quotes pools with exact local AMM math, splits a trade across pools and hops, simulates the route on chain and returns the `Router.swap` transaction for your wallet or backend to sign and send. Chains are addressed by slug in the path (`bsc`). The native coin is the zero address. Amounts are decimal integer strings in the token's raw units. Every error is `{error, message}`."
  },
  "servers": [{ "url": "https://api.tirio.io" }],
  "tags": [
    { "name": "status", "description": "Health of the API and its chains" },
    { "name": "chain", "description": "Per-chain listings and quotes" },
    { "name": "orders", "description": "Limit, stop and DCA orders escrowed by the chain's Orders contract, and its order book" }
  ],
  "paths": {
    "/health": {
      "get": {
        "tags": ["status"],
        "operationId": "health",
        "summary": "Overall status of every chain",
        "description": "`status` is `ok` or `degraded`; the response is 503 while degraded. Not rate limited.",
        "responses": {
          "200": { "description": "Every chain is ready", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Health" }, "example": { "status": "ok", "chains": { "bsc": { "ready": true, "reason": null, "pools": 212, "tokens": 988, "engineLagMs": 1200, "engineLagBlocks": 1, "replicaLagMs": 380, "replicaLagBlocks": 0, "feeBps": 0, "exactOut": false, "router": "0x000000000927913A80FCBC84E6e1F8f8a9614f2E" } } } } } },
          "503": { "description": "At least one chain is not ready", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Health" }, "example": { "status": "degraded", "chains": { "bsc": { "ready": false, "reason": "pools are still loading", "pools": 0, "tokens": 988, "engineLagMs": 900, "engineLagBlocks": 1, "replicaLagMs": 410, "replicaLagBlocks": 0, "feeBps": 0, "exactOut": false, "router": "0x000000000927913A80FCBC84E6e1F8f8a9614f2E" } } } } } }
        }
      }
    },
    "/ready": {
      "get": {
        "tags": ["status"],
        "operationId": "ready",
        "summary": "Readiness for load balancers",
        "description": "204 when the API can serve quotes on every chain it serves. Not rate limited.",
        "responses": {
          "204": { "description": "Ready" },
          "503": { "description": "Not ready", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "error": "unavailable", "message": "bsc: pools are still loading" } } } }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "tags": ["status"],
        "operationId": "openapi",
        "summary": "This document",
        "responses": { "200": { "description": "The OpenAPI description of the API", "content": { "application/json": { "schema": { "type": "object" } } } } }
      }
    },
    "/{chain}/tokens": {
      "get": {
        "tags": ["chain"],
        "operationId": "tokens",
        "summary": "Listed tokens",
        "description": "The native coin first, then the curated tokens, then the chain's token list. `q` ranks exact symbol matches before symbol prefixes before name or symbol mentions and returns at most 100 tokens. If `q` is an address, that token is read on chain and returned first with `listed: false`.",
        "parameters": [
          { "$ref": "#/components/parameters/chain" },
          { "name": "q", "in": "query", "description": "Search text or a token address, at most 64 characters", "schema": { "type": "string", "maxLength": 64 } }
        ],
        "responses": {
          "200": { "description": "Tokens", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Token" } }, "example": [
            { "address": "0x0000000000000000000000000000000000000000", "symbol": "BNB", "name": "BNB", "decimals": 18, "logoURI": "https://tokens.pancakeswap.finance/images/0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c.png", "tags": ["native"], "listed": true },
            { "address": "0x55d398326f99059fF775485246999027B3197955", "symbol": "USDT", "name": "Tether USD", "decimals": 18, "logoURI": "https://tokens.pancakeswap.finance/images/0x55d398326f99059fF775485246999027B3197955.png", "tags": ["usd", "hub"], "listed": true },
            { "address": "0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82", "symbol": "Cake", "name": "PancakeSwap Token", "decimals": 18, "tags": ["hub"], "listed": true }
          ] } } },
          "400": { "$ref": "#/components/responses/invalidRequest" },
          "404": { "$ref": "#/components/responses/notFound" },
          "429": { "$ref": "#/components/responses/rateLimited" }
        }
      }
    },
    "/{chain}/protocols": {
      "get": {
        "tags": ["chain"],
        "operationId": "protocols",
        "summary": "Liquidity sources",
        "description": "The chain's liquidity sources. `id` is what quote hops carry in `dex`; `pools` is the number of pools available for routing where the source has a count, and `null` for factory-based sources whose pools are looked up per pair. The wrap edge `wrapped_native` is not listed.",
        "parameters": [{ "$ref": "#/components/parameters/chain" }],
        "responses": {
          "200": { "description": "Protocols", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Protocol" } }, "example": [
            { "id": "pancakeswap_v3", "name": "PancakeSwap V3", "kind": "v3", "factory": "0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865", "pools": null },
            { "id": "uniswap_v4", "name": "Uniswap V4", "kind": "v4", "factory": "0x28e2Ea090877bF75740558f6BFB36A5ffeE9e9dF", "pools": 41 }
          ] } } },
          "404": { "$ref": "#/components/responses/notFound" },
          "429": { "$ref": "#/components/responses/rateLimited" }
        }
      }
    },
    "/{chain}/prices": {
      "get": {
        "tags": ["chain"],
        "operationId": "prices",
        "summary": "USD spot prices",
        "description": "The value of one whole token in the chain's USD stablecoin, read from the hub pools for a small probe amount (the marginal price), as a decimal string with 8 places. Tokens without a route to the stablecoin are left out. A price can be up to 10 seconds old.",
        "parameters": [
          { "$ref": "#/components/parameters/chain" },
          { "name": "tokens", "in": "query", "description": "Comma-separated token addresses, at most 50; the zero address is the native coin; empty for the listed tokens", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Prices", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Prices" }, "example": { "block": 124501234, "prices": { "0x0000000000000000000000000000000000000000": "612.34000000", "0x55d398326f99059fF775485246999027B3197955": "1.00000000" } } } } },
          "400": { "$ref": "#/components/responses/invalidRequest" },
          "404": { "$ref": "#/components/responses/notFound" },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "503": { "$ref": "#/components/responses/unavailable" }
        }
      }
    },
    "/{chain}/quote": {
      "get": {
        "tags": ["chain"],
        "operationId": "quote",
        "summary": "Quote a swap and build its transaction",
        "description": "Routes the amount across the pools of the pair, the chain's hubs and intermediate tokens, simulates the route on chain and returns the quote with the `Router.swap` transaction. Every exact-in quote whose tokenOut has no transfer tax (and a known one) settles its output through the Router: the calldata sets the `SETTLE_OUTPUT` flag and `expectedOut` = `amountOut`, the expected output after the output-side fees. When the swap then delivers more than `expectedOut`, the Router keeps the excess up to `fees.surplusCapBps` (1%) of `expectedOut`, passes 20% of what it keeps to the partner when the quote names one, and sends the rest to the recipient; this holds whatever the protocol fee, 0 included. A taxed or unknown-tax tokenOut and exact-out quotes pay the recipient directly with `expectedOut` 0, so nothing is kept (a native output still passes through the Router). The protocol fee (`feeBps`, read from the Router) is taken from the output (`PROTOCOL_FEE_ON_OUTPUT`) when the output settles, tokenOut is a hub token and the fee is not 0, otherwise from the input; the partner fee follows `feeToken` (`PARTNER_FEE_ON_OUTPUT` for the output), defaulting to the protocol fee's side (the input while the protocol fee is 0) and falling back to the input for taxed outputs and exact-out; `fees` reports the sides and amounts. `minOut` applies the slippage to the simulated output and is written into the calldata. A pure wrap or unwrap (the native coin against its wrapped token) requested with a `sender` equal to `recipient` skips the Router: `tx` calls the wrapped token's `deposit()` with the amount as value or `withdraw(amount)`, no fee is charged, no approval is needed and the route is the single `wrapped_native` hop.",
        "parameters": [
          { "$ref": "#/components/parameters/chain" },
          { "name": "tokenIn", "in": "query", "required": true, "description": "Token sold; the zero address is the native coin", "schema": { "$ref": "#/components/schemas/Address" } },
          { "name": "tokenOut", "in": "query", "required": true, "description": "Token bought; the zero address is the native coin", "schema": { "$ref": "#/components/schemas/Address" } },
          { "name": "amountIn", "in": "query", "description": "Amount sold in raw units, a positive decimal integer below 2^128; exactly one of amountIn and amountOut is required", "schema": { "$ref": "#/components/schemas/Amount" } },
          { "name": "amountOut", "in": "query", "description": "Exact amount to receive in raw units (exact-out mode): the quote returns the expected input as amountIn and the most the Router may pull as maxIn, with slippage applied to the input; available for tokens without transfer taxes, the native coin included (tx.value is then maxIn and the Router refunds what the route did not use in the same transaction; a wrapped-native input may start with an unwrap into a native pool), through constant product, V3-style and hook-free V4 / Infinity CL pools once the chain's Executor supports it (see /health exactOut)", "schema": { "$ref": "#/components/schemas/Amount" } },
          { "name": "recipient", "in": "query", "required": true, "description": "Address that receives the output; written into the calldata", "schema": { "$ref": "#/components/schemas/Address" } },
          { "name": "sender", "in": "query", "description": "The wallet that will send the transaction: the quote honours the Router's fee exemption for it, fills tx.from, reports balance and allowance issues and, for an ERC20 input, picks the approval path: an EIP-2612 permit or a Permit2 signature to sign (permit), an unsigned Permit2 calldata when the wallet's Permit2 allowance already covers the amount, or the approval to make first (approval); an EOA delegated with EIP-7702 counts as an EOA", "schema": { "$ref": "#/components/schemas/Address" } },
          { "name": "slippageBps", "in": "query", "description": "Maximum slippage in basis points", "schema": { "type": "integer", "minimum": 0, "maximum": 5000, "default": 50 } },
          { "name": "deadline", "in": "query", "description": "Unix timestamp in seconds after which the Router rejects the transaction; at most 3600 seconds ahead, and a timestamp in the past is rejected", "schema": { "type": "integer", "minimum": 0 } },
          { "name": "maxHops", "in": "query", "description": "Maximum swaps per path; wrapping or unwrapping counts as a swap", "schema": { "type": "integer", "minimum": 1, "maximum": 6, "default": 4 } },
          { "name": "maxPaths", "in": "query", "description": "Maximum paths the order may be split across", "schema": { "type": "integer", "minimum": 1, "maximum": 10, "default": 8 } },
          { "name": "includeDexes", "in": "query", "description": "Comma-separated protocol ids to route through exclusively; unknown ids are rejected; the wrap edge always stays", "schema": { "type": "string" } },
          { "name": "excludeDexes", "in": "query", "description": "Comma-separated protocol ids to leave out; cannot be combined with includeDexes", "schema": { "type": "string" } },
          { "name": "source", "in": "query", "description": "Integrator tag written to the API's logs only", "schema": { "type": "string", "pattern": "^[A-Za-z0-9_.-]{1,32}$" } },
          { "name": "partner", "in": "query", "description": "Address that receives the partner fee in the same transaction; required when partnerFeeBps is set", "schema": { "$ref": "#/components/schemas/Address" } },
          { "name": "partnerFeeBps", "in": "query", "description": "Partner fee in basis points, taken on top of the protocol fee and paid to partner minus the Router's partnerShareBps cut", "schema": { "type": "integer", "minimum": 0, "maximum": 1000, "default": 0 } },
          { "name": "feeToken", "in": "query", "description": "Side the partner fee is taken from; without it the partner fee follows the protocol fee; a taxed tokenOut or an exact-out quote moves it to tokenIn, and fees.token reports the token actually used", "schema": { "type": "string", "enum": ["tokenIn", "tokenOut"] } }
        ],
        "responses": {
          "200": { "description": "Quote", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Quote" }, "example": {
            "mode": "exactIn",
            "sender": "0x81994324E1E82A8c02B2C608994Ba6AaD46a3F32",
            "feeExempt": false,
            "issues": { "allowance": null, "balance": { "actual": "250000000000000000", "expected": "1000000000000000000" } },
            "tokenIn": "0x0000000000000000000000000000000000000000",
            "tokenOut": "0x55d398326f99059fF775485246999027B3197955",
            "amountIn": "1000000000000000000",
            "amountOut": "613000000000000000000",
            "minOut": "609935000000000000000",
            "quoteExact": true,
            "feeBps": 0,
            "fees": { "token": "0x0000000000000000000000000000000000000000", "protocolToken": "0x0000000000000000000000000000000000000000", "protocolBps": 0, "protocolAmount": "0", "partner": null, "partnerBps": 0, "partnerAmount": "0", "surplusCapBps": 100 },
            "taxIn": 0,
            "taxOut": 0,
            "taxInKnown": true,
            "taxOutKnown": true,
            "simulated": true,
            "gasEstimate": 143210,
            "gasPrice": "1000000000",
            "deadline": 1790000120,
            "priceImpactBps": 2,
            "amountInUsd": "613.12",
            "amountOutUsd": "613.00",
            "splitGainPpm": 120,
            "route": { "paths": [{ "sharePpm": 1000000, "amountIn": "1000000000000000000", "amountOut": "613000000000000000000", "hops": [
              { "dex": "wrapped_native", "pool": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", "feePpm": 0, "tokenIn": "0x0000000000000000000000000000000000000000", "tokenOut": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", "amountIn": "1000000000000000000", "amountOut": "1000000000000000000", "source": "local", "exact": true },
              { "dex": "pancakeswap_v3", "pool": "0x36696169C63e42cd08ce11f5deeBbCeBae652050", "feePpm": 500, "tokenIn": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", "tokenOut": "0x55d398326f99059fF775485246999027B3197955", "amountIn": "1000000000000000000", "amountOut": "613000000000000000000", "source": "local", "exact": true }
            ] }] },
            "tx": { "from": "0x81994324E1E82A8c02B2C608994Ba6AaD46a3F32", "to": "0x000000000927913A80FCBC84E6e1F8f8a9614f2E", "data": "0x584beb36", "value": "1000000000000000000", "gas": 193210 }
          } } } },
          "400": { "description": "A parameter is missing or malformed, or the token cannot be traded", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "examples": {
            "invalidRequest": { "value": { "error": "invalidRequest", "message": "amountIn must be a positive decimal integer" } },
            "unsupportedToken": { "value": { "error": "unsupportedToken", "message": "token 0x1234567890123456789012345678901234567890 cannot be traded on BNB Chain" } }
          } } } },
          "404": { "description": "Unknown chain, or no route for this pair and amount; a best route with a price impact of 50% or more counts as none", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "examples": {
            "notFound": { "value": { "error": "notFound", "message": "unknown chain ethereum" } },
            "noRoute": { "value": { "error": "noRoute", "message": "no route found for this pair and amount" } }
          } } } },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "503": { "$ref": "#/components/responses/unavailable" }
        }
      }
    },
    "/{chain}/price": {
      "get": {
        "tags": ["chain"],
        "operationId": "price",
        "summary": "Indicative price of a swap, without simulation or transaction",
        "description": "Routes the amount like /quote with the same parameters and fee sides, but returns the routed plan without simulating it and without building a transaction. amountOut is the plan's output after the output-side fees, gasEstimate is the routing model's estimate and simulated is always false. recipient is optional; sender and permits are ignored (no fee exemption is applied and no allowance is read), and partner is required with partnerFeeBps as in /quote but no payout is built. block is the block of the pool state the price was computed from. Call /quote before sending a transaction.",
        "parameters": [
          { "$ref": "#/components/parameters/chain" },
          { "name": "tokenIn", "in": "query", "required": true, "description": "Token sold; the zero address is the native coin", "schema": { "$ref": "#/components/schemas/Address" } },
          { "name": "tokenOut", "in": "query", "required": true, "description": "Token bought; the zero address is the native coin", "schema": { "$ref": "#/components/schemas/Address" } },
          { "name": "amountIn", "in": "query", "description": "Amount sold in raw units; exactly one of amountIn and amountOut is required", "schema": { "$ref": "#/components/schemas/Amount" } },
          { "name": "amountOut", "in": "query", "description": "Exact amount to receive in raw units (exact-out mode), under the same conditions as /quote", "schema": { "$ref": "#/components/schemas/Amount" } },
          { "name": "recipient", "in": "query", "description": "Address that would receive the output", "schema": { "$ref": "#/components/schemas/Address" } },
          { "name": "maxHops", "in": "query", "description": "Maximum swaps per path", "schema": { "type": "integer", "minimum": 1, "maximum": 6, "default": 4 } },
          { "name": "maxPaths", "in": "query", "description": "Maximum paths the order may be split across", "schema": { "type": "integer", "minimum": 1, "maximum": 10, "default": 8 } },
          { "name": "includeDexes", "in": "query", "description": "Comma-separated protocol ids to route through exclusively", "schema": { "type": "string" } },
          { "name": "excludeDexes", "in": "query", "description": "Comma-separated protocol ids to leave out", "schema": { "type": "string" } },
          { "name": "source", "in": "query", "description": "Integrator tag written to the API's logs only", "schema": { "type": "string", "pattern": "^[A-Za-z0-9_.-]{1,32}$" } },
          { "name": "partner", "in": "query", "description": "Address that would receive the partner fee; required when partnerFeeBps is set", "schema": { "$ref": "#/components/schemas/Address" } },
          { "name": "partnerFeeBps", "in": "query", "description": "Partner fee in basis points, as in /quote", "schema": { "type": "integer", "minimum": 0, "maximum": 1000, "default": 0 } },
          { "name": "feeToken", "in": "query", "description": "Side the partner fee is taken from, as in /quote", "schema": { "type": "string", "enum": ["tokenIn", "tokenOut"] } }
        ],
        "responses": {
          "200": { "description": "Price", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Price" }, "example": {
            "mode": "exactIn",
            "tokenIn": "0x0000000000000000000000000000000000000000",
            "tokenOut": "0x55d398326f99059fF775485246999027B3197955",
            "amountIn": "1000000000000000000",
            "amountOut": "613000000000000000000",
            "feeBps": 0,
            "gasEstimate": 131000,
            "gasPrice": "1000000000",
            "priceImpactBps": 2,
            "simulated": false,
            "block": 124501234,
            "route": { "paths": [{ "sharePpm": 1000000, "amountIn": "1000000000000000000", "amountOut": "613000000000000000000", "hops": [
              { "dex": "wrapped_native", "pool": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", "feePpm": 0, "tokenIn": "0x0000000000000000000000000000000000000000", "tokenOut": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", "amountIn": "1000000000000000000", "amountOut": "1000000000000000000", "source": "local", "exact": true },
              { "dex": "pancakeswap_v3", "pool": "0x36696169C63e42cd08ce11f5deeBbCeBae652050", "feePpm": 500, "tokenIn": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", "tokenOut": "0x55d398326f99059fF775485246999027B3197955", "amountIn": "1000000000000000000", "amountOut": "613000000000000000000", "source": "local", "exact": true }
            ] }] }
          } } } },
          "400": { "$ref": "#/components/responses/invalidRequest" },
          "404": { "$ref": "#/components/responses/notFound" },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "503": { "$ref": "#/components/responses/unavailable" }
        }
      }
    },
    "/{chain}/history": {
      "get": {
        "tags": ["chain"],
        "operationId": "history",
        "summary": "Recent spot price history of a pair",
        "description": "Up to 48 points of the spot price of `tokenIn` in `tokenOut`, read from the hub pools at past blocks; a result can be up to two minutes old.",
        "parameters": [
          { "$ref": "#/components/parameters/chain" },
          { "name": "tokenIn", "in": "query", "required": true, "schema": { "$ref": "#/components/schemas/Address" } },
          { "name": "tokenOut", "in": "query", "required": true, "schema": { "$ref": "#/components/schemas/Address" } },
          { "name": "hours", "in": "query", "description": "Window length", "schema": { "type": "integer", "enum": [1, 24, 168], "default": 24 } }
        ],
        "responses": {
          "200": { "description": "History", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/History" }, "example": { "tokenIn": "0x0000000000000000000000000000000000000000", "tokenOut": "0x55d398326f99059fF775485246999027B3197955", "hours": 24, "points": [{ "t": 1790000000, "block": 124480000, "price": "611.12" }, { "t": 1790001800, "block": 124481200, "price": "612.84" }] } } } },
          "400": { "$ref": "#/components/responses/invalidRequest" },
          "404": { "$ref": "#/components/responses/notFound" },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "503": { "$ref": "#/components/responses/unavailable" }
        }
      }
    },
    "/{chain}/candles": {
      "get": {
        "tags": ["chain"],
        "operationId": "candles",
        "summary": "Candles of a pair from its recorded trades",
        "description": "OHLC candles in quote per whole base token: the pair's history from public market data (GeckoTerminal) joined with the swaps Tirio recorded, which win where both have a candle. Recorded candles cover the last 24 hours (1m, 5m) or 7 days (15m and up), aligned to UTC; a recorded candle that starts before the pool's recording began (`since`) is left out. `before` returns the older page of history ending before that time. `v` is the recorded base volume (0 for history) and `vUsd` the USD volume. 404 when neither source knows the pair; `partial` when the history could not be read right now.",
        "parameters": [
          { "$ref": "#/components/parameters/chain" },
          { "name": "base", "in": "query", "required": true, "description": "Base token; the zero address and the wrapped native coin read the same pools", "schema": { "$ref": "#/components/schemas/Address" } },
          { "name": "quote", "in": "query", "required": true, "schema": { "$ref": "#/components/schemas/Address" } },
          { "name": "tf", "in": "query", "schema": { "type": "string", "enum": ["1m", "5m", "15m", "1h", "4h", "1d"], "default": "15m" } },
          { "name": "limit", "in": "query", "description": "Newest candles kept", "schema": { "type": "integer", "minimum": 1, "maximum": 1500, "default": 500 } },
          { "name": "before", "in": "query", "description": "Unix time; the page of history before it", "schema": { "type": "integer", "minimum": 1 } }
        ],
        "responses": {
          "200": { "description": "Candles, oldest first", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Candles" }, "example": { "pool": "0x00000000000000000000000036696169c63e42cd08ce11f5deebbcebae652050", "address": "0x36696169C63e42cd08ce11f5deeBbCeBae652050", "protocol": "pancakeswap_v3", "dex": "PancakeSwap V3", "base": "0x0000000000000000000000000000000000000000", "quote": "0x55d398326f99059fF775485246999027B3197955", "since": 1790000000, "tf": "15m", "partial": false, "candles": [{ "t": 1790000900, "o": 611.2, "h": 612.9, "l": 610.8, "c": 612.4, "v": 1834.5, "vUsd": 1123400.5 }] } } } },
          "400": { "$ref": "#/components/responses/invalidRequest" },
          "404": { "$ref": "#/components/responses/notFound" },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "503": { "$ref": "#/components/responses/unavailable" }
        }
      }
    },
    "/{chain}/trades": {
      "get": {
        "tags": ["chain"],
        "operationId": "trades",
        "summary": "Recent trades of a pair",
        "description": "The newest swaps (at most 200) Tirio recorded on the pool `/candles` reads, followed by older trades from public market data when fewer than 50 are recorded. `side` is the taker's side on the base token, `amount` the base amount, `price` the executed quote per whole base and `volumeUsd` the trade in USD.",
        "parameters": [
          { "$ref": "#/components/parameters/chain" },
          { "name": "base", "in": "query", "required": true, "description": "Base token; the zero address and the wrapped native coin read the same pools", "schema": { "$ref": "#/components/schemas/Address" } },
          { "name": "quote", "in": "query", "required": true, "schema": { "$ref": "#/components/schemas/Address" } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 200, "default": 200 } }
        ],
        "responses": {
          "200": { "description": "Trades, newest first", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Trades" }, "example": { "pool": "0x00000000000000000000000036696169c63e42cd08ce11f5deebbcebae652050", "address": "0x36696169C63e42cd08ce11f5deeBbCeBae652050", "protocol": "pancakeswap_v3", "dex": "PancakeSwap V3", "base": "0x0000000000000000000000000000000000000000", "quote": "0x55d398326f99059fF775485246999027B3197955", "since": 1790000000, "trades": [{ "id": "0x8f0e7d1d0d2c62bd0c3a96f1b8e2e4b1c3f7f5a0f6c2b1e8d9a7c6b5a4f3e2d1:42", "t": 1790001000, "block": 124480123, "tx": "0x8f0e7d1d0d2c62bd0c3a96f1b8e2e4b1c3f7f5a0f6c2b1e8d9a7c6b5a4f3e2d1", "side": "buy", "amount": 1.25, "price": 612.31, "volumeUsd": 765.4 }] } } } },
          "400": { "$ref": "#/components/responses/invalidRequest" },
          "404": { "$ref": "#/components/responses/notFound" },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "503": { "$ref": "#/components/responses/unavailable" }
        }
      }
    },
    "/{chain}/pairstats": {
      "get": {
        "tags": ["chain"],
        "operationId": "pairstats",
        "summary": "24 hour statistics of a pair",
        "description": "Change, high, low and volume of the last 24 hours, from the joined fifteen-minute candles of `/candles`. The change compares the last price with the close before the window. `complete` is false when neither the history nor the recording covers the whole 24 hours.",
        "parameters": [
          { "$ref": "#/components/parameters/chain" },
          { "name": "base", "in": "query", "required": true, "description": "Base token; the zero address and the wrapped native coin read the same pools", "schema": { "$ref": "#/components/schemas/Address" } },
          { "name": "quote", "in": "query", "required": true, "schema": { "$ref": "#/components/schemas/Address" } }
        ],
        "responses": {
          "200": { "description": "Statistics", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PairStats" }, "example": { "pool": "0x00000000000000000000000036696169c63e42cd08ce11f5deebbcebae652050", "address": "0x36696169C63e42cd08ce11f5deeBbCeBae652050", "protocol": "pancakeswap_v3", "dex": "PancakeSwap V3", "base": "0x0000000000000000000000000000000000000000", "quote": "0x55d398326f99059fF775485246999027B3197955", "since": 1790000000, "complete": true, "last": 612.4, "changeBps": 182, "high": 618.2, "low": 598.7, "volume": 41230.6, "volumeUsd": 25248721.1 } } } },
          "400": { "$ref": "#/components/responses/invalidRequest" },
          "404": { "$ref": "#/components/responses/notFound" },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "503": { "$ref": "#/components/responses/unavailable" }
        }
      }
    },
    "/{chain}/market": {
      "get": {
        "tags": ["chain"],
        "operationId": "market",
        "summary": "Market data of a pair",
        "description": "Both tokens' public market data (price, market cap, FDV, liquidity, volume, top pools) and the pair's deepest pool, from GeckoTerminal, up to an hour old. A token or pool it does not know is null.",
        "parameters": [
          { "$ref": "#/components/parameters/chain" },
          { "name": "base", "in": "query", "required": true, "schema": { "$ref": "#/components/schemas/Address" } },
          { "name": "quote", "in": "query", "required": true, "schema": { "$ref": "#/components/schemas/Address" } }
        ],
        "responses": {
          "200": { "description": "Market data", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Market" }, "example": { "network": "bsc", "base": { "address": "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", "symbol": "WBNB", "name": "Wrapped BNB", "decimals": 18, "priceUsd": 612.4, "fdvUsd": null, "marketCapUsd": null, "liquidityUsd": 250000000, "volume24hUsd": 90000000, "totalSupply": null, "pools": [] }, "quote": null, "pool": { "address": "0x172fcd41e0913e95784454622d1c3724f546f849", "name": "WBNB / USDT 0.01%", "dex": "pancakeswap-v3-bsc", "base": "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", "quote": "0x55d398326f99059ff775485246999027b3197955", "reserveUsd": 9000000, "volume24hUsd": 50000000, "change24hPct": 1.5 }, "partial": false } } } },
          "400": { "$ref": "#/components/responses/invalidRequest" },
          "404": { "$ref": "#/components/responses/notFound" },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "503": { "$ref": "#/components/responses/unavailable" }
        }
      }
    },
    "/{chain}/orders": {
      "get": {
        "tags": ["orders"],
        "operationId": "orders",
        "summary": "Orders of a wallet",
        "description": "The newest orders a wallet placed in the Orders contract, newest first, read from the chain on every request. status is the contract's own; an open order past its expiry stays open until the keeper expires it on chain. filledIn is the input the order has spent, receivedOut what the maker received after fees, and avgPrice receivedOut per filledIn in whole tokens (tokenOut per tokenIn). Answers 404 on a chain without an orders contract.",
        "parameters": [
          { "$ref": "#/components/parameters/chain" },
          { "name": "maker", "in": "query", "required": true, "description": "The wallet that placed the orders", "schema": { "$ref": "#/components/schemas/Address" } },
          { "name": "limit", "in": "query", "description": "How many of the newest orders to return", "schema": { "type": "integer", "minimum": 1, "maximum": 200, "default": 200 } }
        ],
        "responses": {
          "200": { "description": "Orders", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Orders" }, "example": {"orders": [{"id": 42, "maker": "0x81994324E1E82A8c02B2C608994Ba6AaD46a3F32", "kind": "limit", "status": "open", "tokenIn": "0x55d398326f99059fF775485246999027B3197955", "tokenOut": "0x0000000000000000000000000000000000000000", "amountIn": "1000000000000000000000", "remainingIn": "400000000000000000000", "minOut": "1633000000000000000", "maxOut": "0", "triggerOut": "0", "minFill": "100000000000000000000", "chunks": 1, "filledChunks": 0, "interval": 0, "nextFillAt": 1790000000, "expiry": 1790604800, "placedAt": 1790000000, "paused": false, "book": true, "partner": null, "partnerFeeBps": 0, "filledIn": "600000000000000000000", "receivedOut": "980412000000000000", "avgPrice": "0.00163402"}, {"id": 57, "maker": "0x81994324E1E82A8c02B2C608994Ba6AaD46a3F32", "kind": "dca", "status": "filled", "tokenIn": "0x55d398326f99059fF775485246999027B3197955", "tokenOut": "0x0000000000000000000000000000000000000000", "amountIn": "400000000000000000000", "remainingIn": "0", "minOut": "326000000000000000", "maxOut": "0", "triggerOut": "0", "minFill": "0", "chunks": 4, "filledChunks": 4, "interval": 86400, "nextFillAt": 1790345600, "expiry": 1791814400, "placedAt": 1790000000, "paused": false, "book": false, "partner": "0x4444444444444444444444444444444444444444", "partnerFeeBps": 20, "filledIn": "400000000000000000000", "receivedOut": "652101000000000000", "avgPrice": "0.0016302525"}]} } } },
          "400": { "$ref": "#/components/responses/invalidRequest" },
          "404": { "$ref": "#/components/responses/notFound" },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "503": { "$ref": "#/components/responses/unavailable" }
        }
      }
    },
    "/{chain}/orders/{id}": {
      "get": {
        "tags": ["orders"],
        "operationId": "order",
        "summary": "One order",
        "description": "The order with this id, in the shape of /orders, read from the chain; 404 when no order has this id.",
        "parameters": [
          { "$ref": "#/components/parameters/chain" },
          { "name": "id", "in": "path", "required": true, "description": "Order id", "schema": { "type": "integer", "minimum": 1 } }
        ],
        "responses": {
          "200": { "description": "Order", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Order" }, "example": {"id": 42, "maker": "0x81994324E1E82A8c02B2C608994Ba6AaD46a3F32", "kind": "limit", "status": "open", "tokenIn": "0x55d398326f99059fF775485246999027B3197955", "tokenOut": "0x0000000000000000000000000000000000000000", "amountIn": "1000000000000000000000", "remainingIn": "400000000000000000000", "minOut": "1633000000000000000", "maxOut": "0", "triggerOut": "0", "minFill": "100000000000000000000", "chunks": 1, "filledChunks": 0, "interval": 0, "nextFillAt": 1790000000, "expiry": 1790604800, "placedAt": 1790000000, "paused": false, "book": true, "partner": null, "partnerFeeBps": 0, "filledIn": "600000000000000000000", "receivedOut": "980412000000000000", "avgPrice": "0.00163402"} } } },
          "400": { "$ref": "#/components/responses/invalidRequest" },
          "404": { "description": "Unknown chain, no orders contract on it, or no such order", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "error": "notFound", "message": "order 4242 does not exist" } } } },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "503": { "$ref": "#/components/responses/unavailable" }
        }
      }
    },
    "/{chain}/orders/place": {
      "get": {
        "tags": ["orders"],
        "operationId": "placeOrder",
        "summary": "Check an order and build its placement",
        "description": "Applies every rule Orders.place enforces and answers 400 naming the broken one, refuses tokens with a transfer tax, a blocked token or one whose tax is unknown (400 unsupportedToken; the contract refuses a taxed input with FeeOnTransfer and a taxed output with Insolvent) and answers 503 while the contract does not accept orders, then returns the Orders.place transaction. preview compares the order with the market: marketOut is an indicative output for amountIn at the market rate of one chunk, not simulated, distanceBps how far minOut (triggerOut for a stop) lies from it, chunk the first chunk and estimatedFee the order fee plus the partner fee in tokenOut on the larger of marketOut and the output that meets minOut. A first chunk (the whole order for limit and stop) known to be worth less than 10 USD is refused with 400; a token without a USD price is not refused. The escrow is taken by the transaction: the native coin as value, an ERC20 through the classic allowance, the permit in the calldata or Permit2, all with the Orders contract as spender.",
        "parameters": [
          { "$ref": "#/components/parameters/chain" },
          { "name": "kind", "in": "query", "required": true, "description": "limit fills at minOut or better; stop fills when the market falls to triggerOut, never below minOut, and with maxOut also takes profit at maxOut or better (a bracket on one escrow); dca buys in chunks every interval between minOut and maxOut per chunk", "schema": { "type": "string", "enum": ["limit", "stop", "dca"] } },
          { "name": "tokenIn", "in": "query", "required": true, "description": "Token escrowed and sold; the zero address is the native coin", "schema": { "$ref": "#/components/schemas/Address" } },
          { "name": "tokenOut", "in": "query", "required": true, "description": "Token bought; the zero address is the native coin", "schema": { "$ref": "#/components/schemas/Address" } },
          { "name": "amountIn", "in": "query", "required": true, "description": "Input escrowed in raw units, between 1 and 2^128 − 1", "schema": { "$ref": "#/components/schemas/Amount" } },
          { "name": "minOut", "in": "query", "description": "Least output for the whole amountIn after the order fee and the partner fee, enforced in proportion to every fill; exactly one of minOut and price is required", "schema": { "$ref": "#/components/schemas/Amount" } },
          { "name": "price", "in": "query", "description": "Limit price in whole tokens, tokenOut per tokenIn, as a decimal number; minOut becomes amountIn times price rounded up, net of fees like minOut", "schema": { "type": "string", "pattern": "^[0-9]+(\\.[0-9]+)?$" } },
          { "name": "maxOut", "in": "query", "description": "stop: the take-profit output for amountIn, above triggerOut; dca: the most output for amountIn a chunk may buy at (0 for none); must be 0 for limit orders", "schema": { "$ref": "#/components/schemas/Amount" } },
          { "name": "triggerOut", "in": "query", "description": "stop: the output for amountIn at which the stop leg fires, at or above minOut; must be 0 otherwise", "schema": { "$ref": "#/components/schemas/Amount" } },
          { "name": "minFill", "in": "query", "description": "Smallest partial fill in tokenIn; 0 fills the order whole; must be 0 for dca", "schema": { "$ref": "#/components/schemas/Amount" } },
          { "name": "chunks", "in": "query", "description": "dca: number of chunks, at least 2 and at most amountIn; 1 for the other kinds", "schema": { "type": "integer", "minimum": 1, "default": 1 } },
          { "name": "interval", "in": "query", "description": "dca: seconds between chunks, 60 to 31536000; 0 for the other kinds", "schema": { "type": "integer", "minimum": 0, "default": 0 } },
          { "name": "expiry", "in": "query", "required": true, "description": "Unix time after which the order no longer fills and its remainder is refunded; more than 60 seconds away and at most 365 days away", "schema": { "type": "integer" } },
          { "name": "startNow", "in": "query", "description": "dca: false waits one interval before the first chunk", "schema": { "type": "boolean", "default": true } },
          { "name": "book", "in": "query", "description": "limit only: list the order on the order book, where swaps take it at its limit at once", "schema": { "type": "boolean", "default": false } },
          { "name": "partner", "in": "query", "description": "Address paid the partner fee out of every fill; required when partnerFeeBps is set", "schema": { "$ref": "#/components/schemas/Address" } },
          { "name": "partnerFeeBps", "in": "query", "description": "Partner fee on the output of every fill", "schema": { "type": "integer", "minimum": 0, "maximum": 1000, "default": 0 } },
          { "name": "sender", "in": "query", "description": "The maker: fills tx.from, reports a short balance and, for an ERC20 input, picks the approval path for the Orders contract as /quote does for the Router (an EIP-2612 permit or a Permit2 signature to sign, an unsigned Permit2 calldata, or the approval to make first)", "schema": { "$ref": "#/components/schemas/Address" } }
        ],
        "responses": {
          "200": { "description": "Placement", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Placement" }, "example": {"order": {"kind": "limit", "tokenIn": "0x55d398326f99059fF775485246999027B3197955", "tokenOut": "0x0000000000000000000000000000000000000000", "amountIn": "1000000000000000000000", "minOut": "1633000000000000000", "price": "0.001633", "maxOut": "0", "triggerOut": "0", "minFill": "100000000000000000000", "chunks": 1, "interval": 0, "expiry": 1790604800, "startNow": true, "partner": null, "partnerFeeBps": 0, "book": true}, "preview": {"marketOut": "1631779000000000000", "distanceBps": 7, "chunk": "1000000000000000000000", "estimatedFee": "1634634000000000"}, "approval": {"spender": "0x000000000022D473030F116dDEE9F6B43aC78BA3", "permit2": true, "required": "1000000000000000000000", "actual": "0"}, "issues": {"balance": null, "minimum": null}, "tx": {"from": "0x81994324E1E82A8c02B2C608994Ba6AaD46a3F32", "to": "0x0000000008BCCFD5793B6dEA2FEFCDd2320f8a4b", "data": "0x2b98f50700000000000000000000000055d398326f99059ff775485246999027b3197955000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003635c9adc5dea0000000000000000000000000000000000000000000000000000016a994d916368000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000056bc75e2d6310000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006aba76000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000", "value": "0"}} } } },
          "400": { "description": "A parameter is malformed, breaks a rule of the Orders contract or names a taxed token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "examples": {"minimum": {"value": {"error": "invalidRequest", "message": "each slice must be worth at least $10"}}, "taxed": {"value": {"error": "unsupportedToken", "message": "tokens with transfer taxes cannot be placed as orders"}}, "price": {"value": {"error": "invalidRequest", "message": "exactly one of minOut and price is required"}}, "stop": {"value": {"error": "invalidRequest", "message": "a stop order needs minOut at or below triggerOut"}}, "dca": {"value": {"error": "invalidRequest", "message": "a DCA order needs at least 2 chunks"}}, "expiry": {"value": {"error": "invalidRequest", "message": "expiry must be at most 365 days away"}}} } } },
          "404": { "$ref": "#/components/responses/notFound" },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "503": { "description": "The chain cannot be served or the Orders contract does not accept orders right now", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "examples": { "paused": { "value": { "error": "unavailable", "message": "orders are paused" } }, "loading": { "value": { "error": "unavailable", "message": "bsc: pools are still loading" } } } } } }
        }
      }
    },
    "/{chain}/orders/cancel": {
      "get": {
        "tags": ["orders"],
        "operationId": "cancelOrder",
        "summary": "Cancel an order",
        "description": "Orders.cancel(id): closes an open order and refunds its remainder to the maker. The calldata is the plain ABI encoding of the call.",
        "parameters": [
          { "$ref": "#/components/parameters/chain" },
          { "name": "id", "in": "query", "required": true, "description": "Order id", "schema": { "type": "integer", "minimum": 1 } },
          { "name": "sender", "in": "query", "description": "The maker; when given, the order is read on chain and a request for an order the sender did not place, a closed order or, for pause, resume and update, an order that is not DCA is refused with 400 before any transaction is built; fills tx.from", "schema": { "$ref": "#/components/schemas/Address" } }
        ],
        "responses": {
          "200": { "description": "Transaction", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OrderAction" }, "example": {"tx": {"from": "0x81994324E1E82A8c02B2C608994Ba6AaD46a3F32", "to": "0x0000000008BCCFD5793B6dEA2FEFCDd2320f8a4b", "data": "0x40e58ee5000000000000000000000000000000000000000000000000000000000000002a", "value": "0"}} } } },
          "400": { "$ref": "#/components/responses/invalidRequest" },
          "404": { "$ref": "#/components/responses/notFound" },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "503": { "$ref": "#/components/responses/unavailable" }
        }
      }
    },
    "/{chain}/orders/cancelAll": {
      "get": {
        "tags": ["orders"],
        "operationId": "cancelOrders",
        "summary": "Cancel several orders",
        "description": "Orders.cancelAll(ids): cancels the open orders among ids in one transaction; closed ones are skipped, and an id the sender did not place reverts.",
        "parameters": [
          { "$ref": "#/components/parameters/chain" },
          { "name": "ids", "in": "query", "required": true, "description": "Comma-separated order ids, at most 100, encoded in the given order", "schema": { "type": "string", "pattern": "^[0-9]+(,[0-9]+)*$" } },
          { "name": "sender", "in": "query", "description": "The maker; when given, the order is read on chain and a request for an order the sender did not place, a closed order or, for pause, resume and update, an order that is not DCA is refused with 400 before any transaction is built; fills tx.from", "schema": { "$ref": "#/components/schemas/Address" } }
        ],
        "responses": {
          "200": { "description": "Transaction", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OrderAction" }, "example": {"tx": {"from": "0x81994324E1E82A8c02B2C608994Ba6AaD46a3F32", "to": "0x0000000008BCCFD5793B6dEA2FEFCDd2320f8a4b", "data": "0x6416b01a00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000039", "value": "0"}} } } },
          "400": { "$ref": "#/components/responses/invalidRequest" },
          "404": { "$ref": "#/components/responses/notFound" },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "503": { "$ref": "#/components/responses/unavailable" }
        }
      }
    },
    "/{chain}/orders/pause": {
      "get": {
        "tags": ["orders"],
        "operationId": "pauseOrder",
        "summary": "Pause a DCA order",
        "description": "Orders.pause(id): a paused DCA order fills no chunk until it is resumed.",
        "parameters": [
          { "$ref": "#/components/parameters/chain" },
          { "name": "id", "in": "query", "required": true, "description": "Order id", "schema": { "type": "integer", "minimum": 1 } },
          { "name": "sender", "in": "query", "description": "The maker; when given, the order is read on chain and a request for an order the sender did not place, a closed order or, for pause, resume and update, an order that is not DCA is refused with 400 before any transaction is built; fills tx.from", "schema": { "$ref": "#/components/schemas/Address" } }
        ],
        "responses": {
          "200": { "description": "Transaction", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OrderAction" }, "example": {"tx": {"from": "0x81994324E1E82A8c02B2C608994Ba6AaD46a3F32", "to": "0x0000000008BCCFD5793B6dEA2FEFCDd2320f8a4b", "data": "0x136439dd0000000000000000000000000000000000000000000000000000000000000039", "value": "0"}} } } },
          "400": { "$ref": "#/components/responses/invalidRequest" },
          "404": { "$ref": "#/components/responses/notFound" },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "503": { "$ref": "#/components/responses/unavailable" }
        }
      }
    },
    "/{chain}/orders/resume": {
      "get": {
        "tags": ["orders"],
        "operationId": "resumeOrder",
        "summary": "Resume a DCA order",
        "description": "Orders.resume(id): the order fills again from its next due chunk; its expiry does not move.",
        "parameters": [
          { "$ref": "#/components/parameters/chain" },
          { "name": "id", "in": "query", "required": true, "description": "Order id", "schema": { "type": "integer", "minimum": 1 } },
          { "name": "sender", "in": "query", "description": "The maker; when given, the order is read on chain and a request for an order the sender did not place, a closed order or, for pause, resume and update, an order that is not DCA is refused with 400 before any transaction is built; fills tx.from", "schema": { "$ref": "#/components/schemas/Address" } }
        ],
        "responses": {
          "200": { "description": "Transaction", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OrderAction" }, "example": {"tx": {"from": "0x81994324E1E82A8c02B2C608994Ba6AaD46a3F32", "to": "0x0000000008BCCFD5793B6dEA2FEFCDd2320f8a4b", "data": "0x414000b50000000000000000000000000000000000000000000000000000000000000039", "value": "0"}} } } },
          "400": { "$ref": "#/components/responses/invalidRequest" },
          "404": { "$ref": "#/components/responses/notFound" },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "503": { "$ref": "#/components/responses/unavailable" }
        }
      }
    },
    "/{chain}/orders/update": {
      "get": {
        "tags": ["orders"],
        "operationId": "updateOrder",
        "summary": "Change a DCA order",
        "description": "Orders.update(id, chunks, interval, minOut, maxOut) with chunks counting the chunks left.",
        "parameters": [
          { "$ref": "#/components/parameters/chain" },
          { "name": "id", "in": "query", "required": true, "description": "Order id", "schema": { "type": "integer", "minimum": 1 } },
          { "name": "chunks", "in": "query", "required": true, "description": "Chunks left, at least 1 and at most the input that remains", "schema": { "type": "integer", "minimum": 1 } },
          { "name": "interval", "in": "query", "required": true, "description": "Seconds between chunks, 60 to 31536000; a shorter interval brings the next chunk forward", "schema": { "type": "integer", "minimum": 60 } },
          { "name": "minOut", "in": "query", "required": true, "description": "New floor for the whole amountIn, applied per chunk", "schema": { "$ref": "#/components/schemas/Amount" } },
          { "name": "maxOut", "in": "query", "description": "New upper bound for the whole amountIn, 0 for none", "schema": { "$ref": "#/components/schemas/Amount" } },
          { "name": "sender", "in": "query", "description": "The maker; when given, the order is read on chain and a request for an order the sender did not place, a closed order or, for pause, resume and update, an order that is not DCA is refused with 400 before any transaction is built; fills tx.from", "schema": { "$ref": "#/components/schemas/Address" } }
        ],
        "responses": {
          "200": { "description": "Transaction", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OrderAction" }, "example": {"tx": {"from": "0x81994324E1E82A8c02B2C608994Ba6AaD46a3F32", "to": "0x0000000008BCCFD5793B6dEA2FEFCDd2320f8a4b", "data": "0x9446f0bf00000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000001518000000000000000000000000000000000000000000000000821ab0d44149800000000000000000000000000000000000000000000000000000000000000000000", "value": "0"}} } } },
          "400": { "$ref": "#/components/responses/invalidRequest" },
          "404": { "$ref": "#/components/responses/notFound" },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "503": { "$ref": "#/components/responses/unavailable" }
        }
      }
    },
    "/{chain}/book": {
      "get": {
        "tags": ["orders"],
        "operationId": "book",
        "summary": "Order book and pool depth of a pair",
        "description": "The open limit orders listed on the book for the pair, tokenIn being the base and tokenOut the quote, grouped by price, next to the depth of the pools. asks sell tokenIn (amountIn in raw tokenIn, lowest price first), bids sell tokenOut (amountIn in raw tokenOut, highest price first); price is the makers' limit in whole tokens, tokenOut per tokenIn, net of the order fee. The native coin and its wrapped token count as one. amm holds 16 indicative points from the pair's pools, not simulated: the first 8 sell tokenIn for tokenOut, the last 8 sell tokenOut for tokenIn, each at growing sizes worth about 100 to 300 000 USD, or 0.1 to 300 whole tokens for a token without a USD price (amountIn and amountOut in raw units, priceImpactBps against the rate at 1/1000 of the size; a size without a route has amountOut 0 and priceImpactBps 10000). spot is the marginal pool price, tokenOut per tokenIn. The answer can be up to five seconds old.",
        "parameters": [
          { "$ref": "#/components/parameters/chain" },
          { "name": "tokenIn", "in": "query", "required": true, "description": "Base token", "schema": { "$ref": "#/components/schemas/Address" } },
          { "name": "tokenOut", "in": "query", "required": true, "description": "Quote token", "schema": { "$ref": "#/components/schemas/Address" } },
          { "name": "depth", "in": "query", "description": "Price levels per side", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 } }
        ],
        "responses": {
          "200": { "description": "Book", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Book" }, "example": {"bids": [{"price": "612.5", "amountIn": "2450000000000000000000", "orders": 2}, {"price": "611.8", "amountIn": "611800000000000000000", "orders": 1}], "asks": [{"price": "613.1", "amountIn": "1500000000000000000", "orders": 1}, {"price": "614", "amountIn": "4000000000000000000", "orders": 3}], "amm": [{"amountIn": "163185000000000000", "amountOut": "100002000000000000000", "priceImpactBps": 0}, {"amountIn": "489555000000000000", "amountOut": "300004000000000000000", "priceImpactBps": 0}, {"amountIn": "1631850000000000000", "amountOut": "1000010000000000000000", "priceImpactBps": 1}, {"amountIn": "4895550000000000000", "amountOut": "2999970000000000000000", "priceImpactBps": 2}, {"amountIn": "16318500000000000000", "amountOut": "9998800000000000000000", "priceImpactBps": 4}, {"amountIn": "48955500000000000000", "amountOut": "29990100000000000000000", "priceImpactBps": 9}, {"amountIn": "163185000000000000000", "amountOut": "99901000000000000000000", "priceImpactBps": 27}, {"amountIn": "489555000000000000000", "amountOut": "298912000000000000000000", "priceImpactBps": 79}, {"amountIn": "100000000000000000000", "amountOut": "163120000000000000", "priceImpactBps": 0}, {"amountIn": "300000000000000000000", "amountOut": "489359000000000000", "priceImpactBps": 0}, {"amountIn": "1000000000000000000000", "amountOut": "1631170000000000000", "priceImpactBps": 1}, {"amountIn": "3000000000000000000000", "amountOut": "4893300000000000000", "priceImpactBps": 2}, {"amountIn": "10000000000000000000000", "amountOut": "16309400000000000000", "priceImpactBps": 4}, {"amountIn": "30000000000000000000000", "amountOut": "48914700000000000000", "priceImpactBps": 9}, {"amountIn": "100000000000000000000000", "amountOut": "162922000000000000000", "priceImpactBps": 27}, {"amountIn": "300000000000000000000000", "amountOut": "486710000000000000000", "priceImpactBps": 79}], "spot": "612.84"} } } },
          "400": { "$ref": "#/components/responses/invalidRequest" },
          "404": { "$ref": "#/components/responses/notFound" },
          "429": { "$ref": "#/components/responses/rateLimited" },
          "503": { "$ref": "#/components/responses/unavailable" }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "chain": { "name": "chain", "in": "path", "required": true, "description": "Chain slug, bsc today; an unknown slug answers 404", "schema": { "type": "string", "enum": ["bsc", "robinhood"] } }
    },
    "responses": {
      "invalidRequest": { "description": "A parameter is missing or malformed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "error": "invalidRequest", "message": "q is longer than 64 characters" } } } },
      "notFound": { "description": "Unknown chain", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "error": "notFound", "message": "unknown chain ethereum" } } } },
      "rateLimited": { "description": "Too many requests from this client; wait for Retry-After seconds", "headers": { "Retry-After": { "description": "Seconds to wait", "schema": { "type": "integer" } } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "error": "rateLimited", "message": "slow down" } } } },
      "unavailable": { "description": "The chain cannot be served right now; retry later", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "error": "unavailable", "message": "bsc: pools are still loading" } } } }
    },
    "schemas": {
      "Address": { "type": "string", "pattern": "^0x[0-9a-fA-F]{40}$", "description": "Hex address; responses use EIP-55 checksums; the zero address is the native coin" },
      "Amount": { "type": "string", "pattern": "^[0-9]+$", "description": "Decimal integer string in the token's raw units" },
      "Bytes32": { "type": "string", "pattern": "^0x[0-9a-fA-F]{64}$", "description": "32-byte hex value" },
      "Error": {
        "type": "object", "required": ["error", "message"], "additionalProperties": false,
        "properties": {
          "error": { "type": "string", "enum": ["invalidRequest", "unsupportedToken", "notFound", "noRoute", "unavailable", "rateLimited", "internal"] },
          "message": { "type": "string" }
        }
      },
      "Health": {
        "type": "object", "required": ["status", "chains"], "additionalProperties": false,
        "properties": {
          "status": { "type": "string", "enum": ["ok", "degraded"] },
          "chains": { "type": "object", "additionalProperties": { "$ref": "#/components/schemas/ChainHealth" } }
        }
      },
      "ChainHealth": {
        "type": "object", "required": ["ready", "reason", "pools", "tokens", "engineLagMs", "engineLagBlocks", "feeBps", "exactOut", "router"], "additionalProperties": false,
        "properties": {
          "ready": { "type": "boolean" },
          "exactOut": { "type": "boolean", "description": "true when the deployed Executor can settle exact-output routes, so amountOut quotes are served" },
          "reason": { "type": ["string", "null"], "description": "Why the chain is not ready" },
          "pools": { "type": "integer", "description": "Pools held ready for quoting; informational, quotes are not limited to these" },
          "tokens": { "type": "integer", "description": "Listed tokens" },
          "engineLagMs": { "type": ["integer", "null"], "description": "Age of the last block seen" },
          "engineLagBlocks": { "type": ["integer", "null"] },
          "replicaLagMs": { "type": "integer", "description": "Age of the pool state used for quotes, in milliseconds; absent when not available" },
          "replicaLagBlocks": { "type": "integer", "description": "Blocks the pool state used for quotes trails the latest block; absent when not available" },
          "feeBps": { "type": ["integer", "null"], "description": "Protocol fee read from the Router" },
          "router": { "$ref": "#/components/schemas/Address", "description": "Router every quote of this chain targets" },
          "orders": { "$ref": "#/components/schemas/Address", "description": "Orders contract of the chain; absent where orders are not available" }
        }
      },
      "Token": {
        "type": "object", "required": ["address", "symbol", "name", "decimals", "tags", "listed"], "additionalProperties": false,
        "properties": {
          "address": { "$ref": "#/components/schemas/Address" },
          "symbol": { "type": "string" },
          "name": { "type": "string" },
          "decimals": { "type": ["integer", "null"], "minimum": 0, "maximum": 255, "description": "null when it could not be read on chain" },
          "logoURI": { "type": "string", "format": "uri", "description": "Present when the token list has a logo" },
          "tags": { "type": "array", "items": { "type": "string", "enum": ["native", "wrapped", "usd", "hub"] } },
          "listed": { "type": "boolean", "description": "false for a token read on chain that is not on the list" }
        }
      },
      "Protocol": {
        "type": "object", "required": ["id", "name", "kind", "factory", "pools"], "additionalProperties": false,
        "properties": {
          "id": { "type": "string", "description": "Adapter id, as carried by quote hops in dex" },
          "name": { "type": "string" },
          "kind": { "type": "string", "enum": ["v2", "v3", "v4", "infinity_cl", "infinity_bin", "maverick_v2", "maverick_v1", "biswap_v3", "metric", "algebra", "stable", "dodo", "dodo_v1", "fluid", "call", "launchpad", "solidly", "liquidity_book", "book"], "description": "book is the order book of open limit orders (id tirio_book), listed last on chains where orders are enabled; factory is the Orders contract and pools is the number of open orders, up to 30 seconds old" },
          "factory": { "$ref": "#/components/schemas/Address" },
          "pools": { "type": ["integer", "null"], "description": "Pools available for routing; null for sources whose pools are looked up per pair" }
        }
      },
      "Prices": {
        "type": "object", "required": ["block", "prices"], "additionalProperties": false,
        "properties": {
          "block": { "type": "integer" },
          "prices": { "type": "object", "additionalProperties": { "type": "string", "pattern": "^[0-9]+\\.[0-9]{8}$" }, "description": "USD per whole token, keyed by checksummed address" }
        }
      },
      "Price": {
        "type": "object", "required": ["mode", "tokenIn", "tokenOut", "amountIn", "amountOut", "feeBps", "gasEstimate", "gasPrice", "priceImpactBps", "simulated", "block", "route"], "additionalProperties": false,
        "properties": {
          "mode": { "type": "string", "enum": ["exactIn", "exactOut"] },
          "tokenIn": { "$ref": "#/components/schemas/Address" },
          "tokenOut": { "$ref": "#/components/schemas/Address" },
          "amountIn": { "$ref": "#/components/schemas/Amount", "description": "Amount sold (exactIn) or the planned input including the protocol fee (exactOut)" },
          "amountOut": { "$ref": "#/components/schemas/Amount", "description": "The routed plan's output after the output-side fees, not simulated" },
          "feeBps": { "type": "integer", "description": "Protocol fee in basis points" },
          "gasEstimate": { "type": "integer", "description": "The routing model's gas estimate" },
          "gasPrice": { "$ref": "#/components/schemas/Amount" },
          "priceImpactBps": { "type": ["integer", "null"] },
          "simulated": { "type": "boolean", "const": false },
          "block": { "type": "integer", "description": "Block of the pool state the price was computed from" },
          "route": { "type": "object", "required": ["paths"], "additionalProperties": false, "properties": { "paths": { "type": "array", "items": { "$ref": "#/components/schemas/Path" } } } }
        }
      },
      "Hop": {
        "type": "object", "required": ["dex", "pool", "feePpm", "tokenIn", "tokenOut", "amountIn", "amountOut", "source", "exact"], "additionalProperties": false,
        "properties": {
          "dex": { "type": "string", "description": "Protocol id, or wrapped_native for a wrap or unwrap" },
          "pool": { "$ref": "#/components/schemas/Address" },
          "poolId": { "type": "string", "description": "Pool id of a singleton pool, or the order id as 32 bytes when dex is tirio_book (present only for singleton sources and order book levels)" },
          "feePpm": { "type": "integer", "description": "Pool fee in parts per million" },
          "tokenIn": { "$ref": "#/components/schemas/Address" },
          "tokenOut": { "$ref": "#/components/schemas/Address" },
          "amountIn": { "$ref": "#/components/schemas/Amount" },
          "amountOut": { "$ref": "#/components/schemas/Amount" },
          "source": { "type": "string", "enum": ["local", "call"], "description": "local: exact math over the pool state; call: quoted on chain" },
          "exact": { "type": "boolean" }
        }
      },
      "Path": {
        "type": "object", "required": ["sharePpm", "amountIn", "amountOut", "hops"], "additionalProperties": false,
        "properties": {
          "sharePpm": { "type": "integer", "description": "Share of the input routed through this path, in parts per million" },
          "amountIn": { "$ref": "#/components/schemas/Amount" },
          "amountOut": { "$ref": "#/components/schemas/Amount" },
          "hops": { "type": "array", "items": { "$ref": "#/components/schemas/Hop" } }
        }
      },
      "Transaction": {
        "type": "object", "required": ["to", "data", "value", "gas"], "additionalProperties": false,
        "properties": {
          "from": { "$ref": "#/components/schemas/Address", "description": "The sender, when the request named one" },
          "to": { "$ref": "#/components/schemas/Address", "description": "The Router, or the wrapped native token for a pure wrap or unwrap" },
          "data": { "type": "string", "pattern": "^0x[0-9a-f]*$", "description": "ABI-encoded Router.swap calldata (its SwapParams carry expectedOut and the fee flags described under /quote), or deposit() / withdraw(amount) for a pure wrap or unwrap" },
          "value": { "$ref": "#/components/schemas/Amount", "description": "amountIn (maxIn in exactOut) for a native input, else 0" },
          "gas": { "type": "integer", "description": "Suggested gas limit (estimate plus margin)" }
        }
      },
      "Quote": {
        "type": "object",
        "required": ["mode", "feeExempt", "tokenIn", "tokenOut", "amountIn", "amountOut", "minOut", "quoteExact", "feeBps", "fees", "taxIn", "taxOut", "taxInKnown", "taxOutKnown", "simulated", "gasEstimate", "gasPrice", "deadline", "priceImpactBps", "amountInUsd", "amountOutUsd", "splitGainPpm", "route", "tx"],
        "additionalProperties": false,
        "properties": {
          "mode": { "type": "string", "enum": ["exactIn", "exactOut"], "description": "exactIn: amountIn is sold and amountOut is the expected output; exactOut: amountOut is bought exactly, amountIn is the expected input and maxIn the ceiling written into the calldata (and sent as tx.value for a native input)" },
          "maxIn": { "$ref": "#/components/schemas/Amount", "description": "Exact-out only: the most the Router may pull (expected input plus the input-side fees and slippage); the unused part never leaves the wallet, and for a native input maxIn is tx.value and the Router refunds the unused part in the same transaction" },
          "sender": { "$ref": "#/components/schemas/Address", "description": "Echoed when the request named a sender" },
          "feeExempt": { "type": "boolean", "description": "true when the sender is exempt from the protocol fee (feeBps is then 0)" },
          "issues": {
            "type": "object", "required": ["allowance", "balance"], "additionalProperties": false,
            "description": "Present when the request named a sender; what the wallet must fix before sending",
            "properties": {
              "allowance": { "type": ["object", "null"], "required": ["actual", "spender"], "additionalProperties": false, "properties": { "actual": { "$ref": "#/components/schemas/Amount" }, "spender": { "$ref": "#/components/schemas/Address" } }, "description": "An approval is still needed before sending: matches approval (spender is Permit2 when that is the recommended approval, else the Router); null when the classic allowance is enough, when the quote carries a permit to sign or an unsigned Permit2 calldata, and for the native coin" },
              "balance": { "type": ["object", "null"], "required": ["actual", "expected"], "additionalProperties": false, "properties": { "actual": { "$ref": "#/components/schemas/Amount" }, "expected": { "$ref": "#/components/schemas/Amount" } }, "description": "The wallet holds less tokenIn than amountIn; null when enough" }
            }
          },
          "permit": {
            "type": "object", "required": ["kind", "eip712", "signatureOffset", "spender"], "additionalProperties": false,
            "description": "Present when the sender's classic allowance is short and the wallet can sign instead of approving: sign eip712 with signTypedData and write the 65-byte r‖s‖v signature into tx.data at signatureOffset (the bytes there are zero), then send; the Router applies the permit before pulling. kind eip2612 signs the token's own Permit (spender is the Router); kind permit2 signs a Permit2 PermitSingle (spender is Permit2, the token must already be approved to Permit2) and is offered only to EOAs (EIP-7702 delegated accounts included) on chains where Permit2 is deployed. A wallet whose Permit2 allowance already covers the amount past the deadline, contract wallets included, gets an unsigned Permit2 calldata instead and neither permit nor approval",
            "properties": {
              "kind": { "type": "string", "enum": ["eip2612", "permit2"] },
              "eip712": { "type": "object", "required": ["types", "primaryType", "domain", "message"], "description": "The typed data to sign, in the shape signTypedData takes: types, primaryType, domain and message; uint values are decimal strings" },
              "signatureOffset": { "type": "integer", "description": "Byte offset inside tx.data where the 65-byte signature goes" },
              "spender": { "$ref": "#/components/schemas/Address" }
            }
          },
          "approval": {
            "type": "object", "required": ["spender", "permit2", "required", "actual"], "additionalProperties": false,
            "description": "Present when the sender must approve before sending: approve spender for at least required (permit2 true means the recommended one-time approval of the token to Permit2, after which quotes carry a Permit2 signature; a contract wallet, or any wallet on a chain where Permit2 has no code, is asked to approve the Router directly)",
            "properties": {
              "spender": { "$ref": "#/components/schemas/Address" },
              "permit2": { "type": "boolean" },
              "required": { "$ref": "#/components/schemas/Amount" },
              "actual": { "$ref": "#/components/schemas/Amount", "description": "The spender's current allowance" }
            }
          },
          "tokenIn": { "$ref": "#/components/schemas/Address" },
          "tokenOut": { "$ref": "#/components/schemas/Address" },
          "amountIn": { "$ref": "#/components/schemas/Amount", "description": "Amount sold (exactIn) or the expected input including the input-side fees (exactOut)" },
          "amountOut": { "$ref": "#/components/schemas/Amount", "description": "Expected output the recipient receives after the output-side fees, the simulated one when simulated is true, and the expectedOut written into the calldata when the output settles through the Router; the exact amount bought in exactOut" },
          "minOut": { "$ref": "#/components/schemas/Amount", "description": "amountOut after slippage, enforced by the Router; equals amountOut in exactOut" },
          "quoteExact": { "type": "boolean" },
          "feeBps": { "type": "integer", "description": "Protocol fee in basis points, 0 for an exempt sender; fees.protocolToken says which side it is taken from" },
          "fees": {
            "type": "object", "required": ["token", "protocolToken", "protocolBps", "protocolAmount", "partner", "partnerBps", "partnerAmount", "surplusCapBps"], "additionalProperties": false,
            "description": "How the swap is charged: the protocol fee on protocolToken, the partner fee on token; amounts are expected values in raw units of their token",
            "properties": {
              "token": { "$ref": "#/components/schemas/Address", "description": "Token the partner fee is taken in (tokenIn or tokenOut)" },
              "protocolToken": { "$ref": "#/components/schemas/Address", "description": "Token the protocol fee is taken in" },
              "protocolBps": { "type": "integer" },
              "protocolAmount": { "$ref": "#/components/schemas/Amount" },
              "partner": { "oneOf": [{ "$ref": "#/components/schemas/Address" }, { "type": "null" }] },
              "partnerBps": { "type": "integer", "minimum": 0, "maximum": 1000 },
              "partnerAmount": { "$ref": "#/components/schemas/Amount", "description": "What the partner receives after the Router's partnerShareBps cut" },
              "surplusCapBps": { "type": "integer", "description": "Positive slippage cap, always 100 (1%): when the output settles through the Router (every exact-in quote whose tokenOut has no transfer tax, whatever the protocol fee) and the swap delivers more than amountOut, the Router keeps the excess up to this share of amountOut and passes 20% of what it keeps to the partner when there is one; a taxed or unknown-tax output and exact-out keep nothing" }
            }
          },
          "taxIn": { "type": "integer", "description": "Sell tax of tokenIn in parts per million, measured at the pools the route sells it to (a token may tax each pool differently); with several paths, the average of their first pools weighted by the input each path takes" },
          "taxOut": { "type": "integer", "description": "Buy tax of tokenOut in parts per million, measured at the pools the route buys it from; with several paths, the average of their last pools weighted by the input each path takes" },
          "taxInKnown": { "type": "boolean" },
          "taxOutKnown": { "type": "boolean" },
          "simulated": { "type": "boolean", "description": "true when the route was simulated on chain and amountOut and gasEstimate come from the simulation" },
          "gasEstimate": { "type": "integer", "description": "Estimated gas of the transaction: the simulated gas plus the transaction overhead when simulated is true, else the routing model; includes the permit's cost (the Router's permit call, Permit2's transfer detour and the permit calldata) when tx.data carries one" },
          "gasPrice": { "$ref": "#/components/schemas/Amount", "description": "Gas price in wei used for the gas-aware routing" },
          "deadline": { "type": "integer", "description": "Unix timestamp written into the calldata" },
          "priceImpactBps": { "type": ["integer", "null"] },
          "amountInUsd": { "type": ["string", "null"] },
          "amountOutUsd": { "type": ["string", "null"] },
          "splitGainPpm": { "type": ["integer", "null"], "description": "Extra output of the split compared with the best single path" },
          "route": { "type": "object", "required": ["paths"], "additionalProperties": false, "properties": { "paths": { "type": "array", "items": { "$ref": "#/components/schemas/Path" } } } },
          "tx": { "$ref": "#/components/schemas/Transaction" }
        }
      },
      "History": {
        "type": "object", "required": ["tokenIn", "tokenOut", "hours", "points"], "additionalProperties": false,
        "properties": {
          "tokenIn": { "$ref": "#/components/schemas/Address" },
          "tokenOut": { "$ref": "#/components/schemas/Address" },
          "hours": { "type": "integer", "enum": [1, 24, 168] },
          "points": { "type": "array", "items": { "type": "object", "required": ["t", "block", "price"], "additionalProperties": false, "properties": { "t": { "type": "integer", "description": "Unix timestamp" }, "block": { "type": "integer" }, "price": { "type": "string", "description": "tokenOut per whole tokenIn" } } } }
        }
      },
      "Candles": {
        "type": "object", "required": ["pool", "address", "protocol", "dex", "base", "quote", "since", "tf", "partial", "candles"], "additionalProperties": false,
        "properties": {
          "pool": { "$ref": "#/components/schemas/Bytes32", "description": "Pool id: the pool address left-padded, or the pool key hash of a singleton pool" },
          "address": { "type": "string", "description": "Pool or pool manager contract; empty for a singleton pool known only to market data" },
          "protocol": { "type": "string", "description": "Protocol id as in /protocols" },
          "dex": { "type": "string" },
          "base": { "$ref": "#/components/schemas/Address" },
          "quote": { "$ref": "#/components/schemas/Address" },
          "since": { "type": "integer", "description": "Unix time the pool's recording began, 0 when it is not recorded" },
          "tf": { "type": "string", "enum": ["1m", "5m", "15m", "1h", "4h", "1d"] },
          "partial": { "type": "boolean", "description": "The history could not be read right now (market data busy); only recorded candles are in the answer and a retry in a few seconds fills it" },
          "candles": { "type": "array", "items": { "type": "object", "required": ["t", "o", "h", "l", "c", "v", "vUsd"], "additionalProperties": false, "properties": { "t": { "type": "integer", "description": "Unix time the candle opens" }, "o": { "type": "number" }, "h": { "type": "number" }, "l": { "type": "number" }, "c": { "type": "number" }, "v": { "type": "number", "description": "Base volume in whole tokens" }, "vUsd": { "type": ["number", "null"] } } } }
        }
      },
      "Trades": {
        "type": "object", "required": ["pool", "address", "protocol", "dex", "base", "quote", "since", "trades"], "additionalProperties": false,
        "properties": {
          "pool": { "$ref": "#/components/schemas/Bytes32", "description": "Pool id: the pool address left-padded, or the pool key hash of a singleton pool" },
          "address": { "type": "string", "description": "Pool or pool manager contract; empty for a singleton pool known only to market data" },
          "protocol": { "type": "string", "description": "Protocol id as in /protocols" },
          "dex": { "type": "string" },
          "base": { "$ref": "#/components/schemas/Address" },
          "quote": { "$ref": "#/components/schemas/Address" },
          "since": { "type": "integer", "description": "Unix time the pool's recording began, 0 when it is not recorded" },
          "trades": { "type": "array", "items": { "type": "object", "required": ["id", "t", "block", "tx", "side", "amount", "price", "volumeUsd"], "additionalProperties": false, "properties": { "id": { "type": "string", "description": "Transaction hash and log index" }, "t": { "type": "integer" }, "block": { "type": "integer" }, "tx": { "$ref": "#/components/schemas/Bytes32" }, "side": { "type": "string", "enum": ["buy", "sell"] }, "amount": { "type": "number", "description": "Whole base tokens" }, "price": { "type": "number", "description": "Quote per whole base" }, "volumeUsd": { "type": ["number", "null"] } } } }
        }
      },
      "PairStats": {
        "type": "object", "required": ["pool", "address", "protocol", "dex", "base", "quote", "since", "complete", "last", "changeBps", "high", "low", "volume", "volumeUsd"], "additionalProperties": false,
        "properties": {
          "pool": { "$ref": "#/components/schemas/Bytes32", "description": "Pool id: the pool address left-padded, or the pool key hash of a singleton pool" },
          "address": { "type": "string", "description": "Pool or pool manager contract; empty for a singleton pool known only to market data" },
          "protocol": { "type": "string", "description": "Protocol id as in /protocols" },
          "dex": { "type": "string" },
          "base": { "$ref": "#/components/schemas/Address" },
          "quote": { "$ref": "#/components/schemas/Address" },
          "since": { "type": "integer", "description": "Unix time the pool's recording began, 0 when it is not recorded" },
          "complete": { "type": "boolean", "description": "The recording covers the whole 24 hours" },
          "last": { "type": "number", "description": "Spot price after the last recorded trade" },
          "changeBps": { "type": ["integer", "null"] },
          "high": { "type": "number" },
          "low": { "type": "number" },
          "volume": { "type": "number", "description": "Base volume in whole tokens" },
          "volumeUsd": { "type": ["number", "null"] }
        }
      },
      "MarketPool": {
        "type": "object", "required": ["address", "name", "dex", "base", "quote", "reserveUsd", "volume24hUsd", "change24hPct"], "additionalProperties": false,
        "properties": {
          "address": { "type": "string" }, "name": { "type": "string" }, "dex": { "type": "string" }, "base": { "type": "string" }, "quote": { "type": "string" },
          "reserveUsd": { "type": "number" }, "volume24hUsd": { "type": ["number", "null"] }, "change24hPct": { "type": ["number", "null"] }
        }
      },
      "MarketToken": {
        "type": "object", "required": ["address", "symbol", "name", "decimals", "priceUsd", "fdvUsd", "marketCapUsd", "liquidityUsd", "volume24hUsd", "totalSupply", "pools"], "additionalProperties": false,
        "properties": {
          "address": { "type": "string" }, "symbol": { "type": "string" }, "name": { "type": "string" }, "decimals": { "type": ["integer", "null"] },
          "priceUsd": { "type": ["number", "null"] }, "fdvUsd": { "type": ["number", "null"] }, "marketCapUsd": { "type": ["number", "null"] }, "liquidityUsd": { "type": ["number", "null"] },
          "volume24hUsd": { "type": ["number", "null"] }, "totalSupply": { "type": ["number", "null"] },
          "pools": { "type": "array", "items": { "$ref": "#/components/schemas/MarketPool" } }
        }
      },
      "Market": {
        "type": "object", "required": ["network", "base", "quote", "pool", "partial"], "additionalProperties": false,
        "properties": {
          "network": { "type": "string" },
          "partial": { "type": "boolean", "description": "Some market data could not be read right now; ask again in a few seconds" },
          "base": { "oneOf": [{ "$ref": "#/components/schemas/MarketToken" }, { "type": "null" }] },
          "quote": { "oneOf": [{ "$ref": "#/components/schemas/MarketToken" }, { "type": "null" }] },
          "pool": { "oneOf": [{ "$ref": "#/components/schemas/MarketPool" }, { "type": "null" }] }
        }
      },
      "Order": {
        "type": "object", "required": ["id", "maker", "kind", "status", "tokenIn", "tokenOut", "amountIn", "remainingIn", "minOut", "maxOut", "triggerOut", "minFill", "chunks", "filledChunks", "interval", "nextFillAt", "expiry", "placedAt", "paused", "book", "partner", "partnerFeeBps", "filledIn", "receivedOut", "avgPrice"], "additionalProperties": false,
        "properties": {
          "id": { "type": "integer" },
          "maker": { "$ref": "#/components/schemas/Address" },
          "kind": { "type": "string", "enum": ["limit", "stop", "dca"] },
          "status": { "type": "string", "enum": ["open", "filled", "cancelled", "expired"], "description": "The contract's status; an open order past its expiry stays open until it is expired on chain" },
          "tokenIn": { "$ref": "#/components/schemas/Address" },
          "tokenOut": { "$ref": "#/components/schemas/Address" },
          "amountIn": { "$ref": "#/components/schemas/Amount" },
          "remainingIn": { "$ref": "#/components/schemas/Amount" },
          "minOut": { "$ref": "#/components/schemas/Amount", "description": "Net floor for the whole amountIn (the limit, the stop floor or the DCA lower bound)" },
          "maxOut": { "$ref": "#/components/schemas/Amount", "description": "Take-profit output of a stop, upper bound of a DCA order, else 0" },
          "triggerOut": { "$ref": "#/components/schemas/Amount", "description": "Stop trigger for the whole amountIn, else 0" },
          "minFill": { "$ref": "#/components/schemas/Amount" },
          "chunks": { "type": "integer" },
          "filledChunks": { "type": "integer" },
          "interval": { "type": "integer" },
          "nextFillAt": { "type": "integer", "description": "Unix time the next DCA chunk is due" },
          "expiry": { "type": "integer" },
          "placedAt": { "type": "integer" },
          "paused": { "type": "boolean" },
          "book": { "type": "boolean", "description": "Listed on the order book" },
          "partner": { "type": ["string", "null"], "pattern": "^0x[0-9a-fA-F]{40}$" },
          "partnerFeeBps": { "type": "integer" },
          "filledIn": { "$ref": "#/components/schemas/Amount", "description": "Input the fills spent" },
          "receivedOut": { "$ref": "#/components/schemas/Amount", "description": "Output the maker received after fees" },
          "avgPrice": { "type": ["string", "null"], "description": "receivedOut per filledIn in whole tokens, tokenOut per tokenIn; null before the first fill" }
        }
      },
      "Orders": {
        "type": "object", "required": ["orders"], "additionalProperties": false,
        "properties": { "orders": { "type": "array", "items": { "$ref": "#/components/schemas/Order" } } }
      },
      "OrderTransaction": {
        "type": "object", "required": ["to", "data", "value"], "additionalProperties": false,
        "properties": {
          "from": { "$ref": "#/components/schemas/Address", "description": "The sender, when the request named one" },
          "to": { "$ref": "#/components/schemas/Address", "description": "The Orders contract" },
          "data": { "type": "string", "pattern": "^0x[0-9a-f]*$", "description": "ABI-encoded call of the Orders contract" },
          "value": { "$ref": "#/components/schemas/Amount", "description": "amountIn when a placement escrows the native coin, else 0" }
        }
      },
      "OrderAction": {
        "type": "object", "required": ["tx"], "additionalProperties": false,
        "properties": { "tx": { "$ref": "#/components/schemas/OrderTransaction" } }
      },
      "Placement": {
        "type": "object", "required": ["order", "preview", "issues", "tx"], "additionalProperties": false,
        "properties": {
          "order": {
            "type": "object", "required": ["kind", "tokenIn", "tokenOut", "amountIn", "minOut", "price", "maxOut", "triggerOut", "minFill", "chunks", "interval", "expiry", "startNow", "partner", "partnerFeeBps", "book"], "additionalProperties": false,
            "description": "The Place struct written into the calldata, with minOut computed from price when the request gave a price",
            "properties": {
              "kind": { "type": "string", "enum": ["limit", "stop", "dca"] },
              "tokenIn": { "$ref": "#/components/schemas/Address" },
              "tokenOut": { "$ref": "#/components/schemas/Address" },
              "amountIn": { "$ref": "#/components/schemas/Amount" },
              "minOut": { "$ref": "#/components/schemas/Amount" },
              "price": { "type": ["string", "null"], "description": "minOut per amountIn in whole tokens; null when a token's decimals are unknown" },
              "maxOut": { "$ref": "#/components/schemas/Amount" },
              "triggerOut": { "$ref": "#/components/schemas/Amount" },
              "minFill": { "$ref": "#/components/schemas/Amount" },
              "chunks": { "type": "integer" },
              "interval": { "type": "integer" },
              "expiry": { "type": "integer" },
              "startNow": { "type": "boolean" },
              "partner": { "type": ["string", "null"], "pattern": "^0x[0-9a-fA-F]{40}$" },
              "partnerFeeBps": { "type": "integer" },
              "book": { "type": "boolean" }
            }
          },
          "preview": {
            "type": "object", "required": ["marketOut", "distanceBps", "chunk", "estimatedFee"], "additionalProperties": false,
            "properties": {
              "marketOut": { "type": ["string", "null"], "pattern": "^[0-9]+$", "description": "Output for amountIn at the market rate of one chunk; null without a route" },
              "distanceBps": { "type": ["integer", "null"], "description": "(minOut, or triggerOut for a stop, minus marketOut) / marketOut" },
              "chunk": { "$ref": "#/components/schemas/Amount", "description": "First chunk; amountIn for limit and stop orders" },
              "estimatedFee": { "$ref": "#/components/schemas/Amount", "description": "Order fee plus partner fee in tokenOut" }
            }
          },
          "permit": {
            "type": "object", "required": ["kind", "eip712", "signatureOffset", "spender"], "additionalProperties": false,
            "description": "Present when the maker can sign instead of approving: sign eip712 and write the 65-byte signature into tx.data at signatureOffset. kind eip2612 signs the token's Permit for the Orders contract; kind permit2 signs a PermitSingle whose spender is the Orders contract (offered only to EOAs, EIP-7702 delegated accounts excluded)",
            "properties": {
              "kind": { "type": "string", "enum": ["eip2612", "permit2"] },
              "eip712": { "type": "object", "required": ["types", "primaryType", "domain", "message"] },
              "signatureOffset": { "type": "integer" },
              "spender": { "$ref": "#/components/schemas/Address" }
            }
          },
          "approval": {
            "type": "object", "required": ["spender", "permit2", "required", "actual"], "additionalProperties": false,
            "description": "Present when the maker must approve first: Permit2 (permit2 true) or the Orders contract",
            "properties": {
              "spender": { "$ref": "#/components/schemas/Address" },
              "permit2": { "type": "boolean" },
              "required": { "$ref": "#/components/schemas/Amount" },
              "actual": { "$ref": "#/components/schemas/Amount" }
            }
          },
          "issues": {
            "type": "object", "required": ["balance", "minimum"], "additionalProperties": false,
            "properties": {
              "balance": { "type": ["object", "null"], "required": ["actual", "expected"], "additionalProperties": false, "properties": { "actual": { "type": "string" }, "expected": { "type": "string" } }, "description": "The sender holds less tokenIn than amountIn, raw units; null when enough or without a sender" },
              "minimum": { "type": ["object", "null"], "required": ["actual", "expected"], "additionalProperties": false, "properties": { "actual": { "type": "string" }, "expected": { "type": "string" } }, "description": "Always null: a first chunk known to be worth less than 10 USD is refused with 400 instead" }
            }
          },
          "tx": { "$ref": "#/components/schemas/OrderTransaction" }
        }
      },
      "BookLevel": {
        "type": "object", "required": ["price", "amountIn", "orders"], "additionalProperties": false,
        "properties": {
          "price": { "type": "string", "description": "Limit of the makers, whole tokenOut per whole tokenIn" },
          "amountIn": { "$ref": "#/components/schemas/Amount", "description": "Input the level's orders still hold, in the token they sell" },
          "orders": { "type": "integer" }
        }
      },
      "Book": {
        "type": "object", "required": ["bids", "asks", "amm", "spot"], "additionalProperties": false,
        "properties": {
          "bids": { "type": "array", "items": { "$ref": "#/components/schemas/BookLevel" }, "description": "Orders selling tokenOut, highest price first" },
          "asks": { "type": "array", "items": { "$ref": "#/components/schemas/BookLevel" }, "description": "Orders selling tokenIn, lowest price first" },
          "amm": { "type": "array", "items": { "type": "object", "required": ["amountIn", "amountOut", "priceImpactBps"], "additionalProperties": false, "properties": { "amountIn": { "$ref": "#/components/schemas/Amount" }, "amountOut": { "$ref": "#/components/schemas/Amount" }, "priceImpactBps": { "type": "integer" } } }, "description": "8 sizes selling tokenIn, then 8 selling tokenOut" },
          "spot": { "type": ["string", "null"], "description": "Marginal pool price, whole tokenOut per whole tokenIn" }
        }
      }
    }
  }
}
