{
 "components": {
  "schemas": {
   "Asset": {
    "properties": {
     "decimals": {
      "type": "integer"
     },
     "id": {
      "description": "ASA id, 0 = ALGO",
      "format": "int64",
      "type": "integer"
     },
     "name": {
      "type": "string"
     },
     "unit": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "AssetUSD": {
    "properties": {
     "hops": {
      "type": "integer"
     },
     "liquidity_usd": {
      "type": "number"
     },
     "routes": {
      "description": "With details=1",
      "items": {
       "$ref": "#/components/schemas/Route"
      },
      "type": "array"
     },
     "usd": {
      "description": "USD per whole unit; null if not routable",
      "nullable": true,
      "type": "number"
     }
    },
    "type": "object"
   },
   "Error": {
    "properties": {
     "error": {
      "example": "unknown asset 1",
      "type": "string"
     }
    },
    "type": "object"
   },
   "History": {
    "properties": {
     "asset": {
      "$ref": "#/components/schemas/Asset"
     },
     "bin_seconds": {
      "type": "integer"
     },
     "from": {
      "format": "date-time",
      "type": "string"
     },
     "points": {
      "items": {
       "$ref": "#/components/schemas/Point"
      },
      "type": "array"
     },
     "pools": {
      "type": "integer"
     },
     "quote": {
      "$ref": "#/components/schemas/Asset"
     },
     "source": {
      "enum": [
       "events",
       "bars_1h",
       "daily"
      ],
      "type": "string"
     },
     "to": {
      "format": "date-time",
      "type": "string"
     }
    },
    "type": "object"
   },
   "Pair": {
    "properties": {
     "active_pools": {
      "type": "integer"
     },
     "asset_a": {
      "$ref": "#/components/schemas/Asset"
     },
     "asset_b": {
      "$ref": "#/components/schemas/Asset"
     },
     "kind": {
      "description": "amm: tradable pools; rate: mint/redeem or lending rate venues, TVL = redeemable backing",
      "enum": [
       "amm",
       "rate"
      ],
      "type": "string"
     },
     "pools": {
      "type": "integer"
     },
     "price": {
      "description": "Close: asset B per asset A (whole units), deepest pool",
      "type": "number"
     },
     "reserve_a": {
      "type": "number"
     },
     "reserve_b": {
      "type": "number"
     },
     "swaps": {
      "type": "integer"
     },
     "tvl_usd": {
      "type": "number"
     },
     "venues": {
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "volume_a": {
      "type": "number"
     },
     "volume_b": {
      "type": "number"
     },
     "volume_usd": {
      "type": "number"
     }
    },
    "type": "object"
   },
   "Pairs": {
    "properties": {
     "count": {
      "type": "integer"
     },
     "date": {
      "format": "date",
      "type": "string"
     },
     "final": {
      "type": "boolean"
     },
     "pairs": {
      "items": {
       "$ref": "#/components/schemas/Pair"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "Point": {
    "properties": {
     "algo": {
      "nullable": true,
      "type": "number"
     },
     "liquidity_usd": {
      "type": "number"
     },
     "price": {
      "nullable": true,
      "type": "number"
     },
     "ts": {
      "format": "date-time",
      "type": "string"
     },
     "usdc": {
      "nullable": true,
      "type": "number"
     }
    },
    "type": "object"
   },
   "Pool": {
    "properties": {
     "address": {
      "type": "string"
     },
     "app_id": {
      "format": "int64",
      "type": "integer"
     },
     "asa_a": {
      "format": "int64",
      "type": "integer"
     },
     "asa_b": {
      "format": "int64",
      "type": "integer"
     },
     "fee_bps": {
      "type": "number"
     },
     "first_round": {
      "format": "int64",
      "type": "integer"
     },
     "lp_asa": {
      "format": "int64",
      "type": "integer"
     },
     "pool_id": {
      "description": "App id, or the LP-token ASA id for Tinyman V2",
      "format": "int64",
      "type": "integer"
     },
     "venue": {
      "enum": [
       "tinyman2",
       "pact",
       "pactstable",
       "pactw",
       "biatec",
       "humble",
       "algofi",
       "liquihog",
       "nanoswap",
       "talgo",
       "xalgo",
       "folks"
      ],
      "type": "string"
     }
    },
    "type": "object"
   },
   "Pools": {
    "properties": {
     "asset": {
      "format": "int64",
      "type": "integer"
     },
     "count": {
      "type": "integer"
     },
     "pools": {
      "items": {
       "$ref": "#/components/schemas/Pool"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "Price": {
    "example": {
     "algo": 806462.88,
     "asset": {
      "decimals": 8,
      "id": 386192725,
      "name": "goBTC",
      "unit": "goBTC"
     },
     "asset_usd": {
      "hops": 1,
      "liquidity_usd": 122543.4,
      "usd": 74302.41
     },
     "price": 74302.41,
     "quote": {
      "decimals": 6,
      "id": 31566704,
      "name": "USDC",
      "unit": "USDC"
     },
     "quote_usd": {
      "usd": 1
     },
     "round": 65000000,
     "ts": "2026-09-13T09:16:17Z",
     "usdc": 74302.41
    },
    "properties": {
     "algo": {
      "nullable": true,
      "type": "number"
     },
     "asset": {
      "$ref": "#/components/schemas/Asset"
     },
     "asset_usd": {
      "$ref": "#/components/schemas/AssetUSD"
     },
     "price": {
      "description": "Whole quote units per whole asset unit",
      "nullable": true,
      "type": "number"
     },
     "quote": {
      "$ref": "#/components/schemas/Asset"
     },
     "quote_usd": {
      "$ref": "#/components/schemas/AssetUSD"
     },
     "requested_ts": {
      "description": "Present when ts was at or after the indexed tip",
      "format": "date-time",
      "type": "string"
     },
     "round": {
      "format": "int64",
      "type": "integer"
     },
     "ts": {
      "format": "date-time",
      "type": "string"
     },
     "usdc": {
      "nullable": true,
      "type": "number"
     }
    },
    "type": "object"
   },
   "Route": {
    "properties": {
     "kept": {
      "type": "boolean"
     },
     "pool_id": {
      "format": "int64",
      "type": "integer"
     },
     "price_usd": {
      "type": "number"
     },
     "venue": {
      "type": "string"
     },
     "via": {
      "description": "Asset on the other side of the pool",
      "format": "int64",
      "type": "integer"
     },
     "weight_usd": {
      "type": "number"
     }
    },
    "type": "object"
   },
   "Status": {
    "properties": {
     "final_day": {
      "format": "date",
      "type": "string"
     },
     "round": {
      "format": "int64",
      "type": "integer"
     },
     "ts": {
      "format": "date-time",
      "type": "string"
     }
    },
    "type": "object"
   }
  }
 },
 "info": {
  "contact": {
   "email": "support@nodely.io",
   "name": "API Support"
  },
  "description": "Algorand DEX prices, paid per call with x402 (exact scheme, USDC ASA 31566704 on Algorand, 0.001 USDC per call, payTo X4O2STHZWIA425GOSCKVW3KY6IAW3F6SSV5AZ23HOYFLKCDRTHKWUYNDLY). An unpaid call answers 402 with the PAYMENT-REQUIRED offer; a bad request answers 400 and is never charged, nor is a call that returns no data. The same data is free and rate-limited at https://algoprices.api.nodely.io. The network fee is sponsored (extra.feePayer X4O2STHZWIA425GOSCKVW3KY6IAW3F6SSV5AZ23HOYFLKCDRTHKWUYNDLY): the payer signs only the USDC transfer, with fee 0, and needs no ALGO beyond its minimum balance. Historical and live prices of Algorand ASAs, computed from on-chain DEX pool state (Tinyman V2, Pact, Pact StableSwap, Pact weighted, Humble, Algofi, LiquiHog, Biatec) since round 19,247,000. Prices are exact to the round: the state of every pool is replayed from its eval deltas. A USD price is a liquidity-weighted route search to USDC over the pools; a price in another quote is the ratio of both USD prices.\n\nEvery price carries three units: `price` (in the requested quote), `usdc` and `algo` (null if the asset cannot be routed).\n\nRate limit: 10 requests/s per client IP (burst 20); excess requests get HTTP 429. Checkout \u003ca href=\"/v1/api-docs/swagger.json\"\u003eswagger.json\u003c/a\u003e.",
  "title": "Nodely DEX Prices (x402)",
  "version": "1.0.0"
 },
 "openapi": "3.0.3",
 "paths": {
  "/v1/prices/health": {
   "get": {
    "operationId": "pricesHealth",
    "responses": {
     "200": {
      "description": "OK"
     }
    },
    "summary": "Service and algod health (free)",
    "tags": [
     "status"
    ]
   }
  },
  "/v1/prices/history": {
   "get": {
    "description": "`bins` bins of equal width ending at `to` (clamped to the indexed tip). Each point is the price at the end of its bin. Bins under 1 h are computed from raw pool events, 1 h to 1 d from hourly bars, 1 d or more from daily bars.",
    "operationId": "pricesHistory",
    "parameters": [
     {
      "description": "ASA id, `algo` (= 0) or `usdc` (= 31566704).",
      "example": "386192725",
      "in": "query",
      "name": "asset",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Quote asset (ASA id, `algo` or `usdc`). Default USDC.",
      "in": "query",
      "name": "quote",
      "schema": {
       "default": "usdc",
       "type": "string"
      }
     },
     {
      "description": "Unix seconds, RFC 3339, or YYYY-MM-DD (UTC).",
      "example": "2026-10-01",
      "in": "query",
      "name": "from",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Unix seconds, RFC 3339, or YYYY-MM-DD (UTC).",
      "example": "2026-10-23",
      "in": "query",
      "name": "to",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Number of bins (max 2000).",
      "in": "query",
      "name": "bins",
      "schema": {
       "default": 100,
       "maximum": 2000,
       "type": "integer"
      }
     },
     {
      "description": "Minimum pool liquidity in USD for a pool to be used in routing.",
      "in": "query",
      "name": "min_liq",
      "schema": {
       "default": 50,
       "type": "number"
      }
     },
     {
      "description": "Maximum route length from the asset to USDC.",
      "in": "query",
      "name": "max_hops",
      "schema": {
       "default": 4,
       "type": "integer"
      }
     },
     {
      "description": "Ignore pools with no event for this many days.",
      "in": "query",
      "name": "stale_days",
      "schema": {
       "default": 30,
       "type": "integer"
      }
     },
     {
      "description": "Drop pool quotes deviating more than this fraction from the liquidity-weighted median.",
      "in": "query",
      "name": "max_dev",
      "schema": {
       "default": 0.2,
       "type": "number"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/History"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      },
      "description": "Bad parameter or unknown asset"
     },
     "402": {
      "description": "Payment required: x402 offer in the PAYMENT-REQUIRED header (base64 JSON; the same JSON is the body). Retry with PAYMENT-SIGNATURE."
     },
     "429": {
      "description": "Rate limit exceeded (10 requests/s per client IP, burst 20)"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      },
      "description": "Internal error"
     }
    },
    "summary": "Price history in equal-width bins",
    "tags": [
     "prices"
    ]
   }
  },
  "/v1/prices/pairs": {
   "get": {
    "description": "Every pair with a live pool that day, sorted by TVL: venues, pool counts, swaps, close price (asset B per asset A, deepest pool), reserves, volumes, TVL and volume in USD. The default day is the last finalized one; `final` is false for the still-open day. Pools of rate venues (talgo, xalgo, folks) form their own rows with `kind: rate`, so a pair can appear twice (amm and rate).",
    "operationId": "pricesPairs",
    "parameters": [
     {
      "description": "YYYY-MM-DD (UTC). Default: last finalized day.",
      "in": "query",
      "name": "date",
      "schema": {
       "format": "date",
       "type": "string"
      }
     },
     {
      "description": "`1`: only pairs with at least one swap that day.",
      "in": "query",
      "name": "active",
      "schema": {
       "enum": [
        "0",
        "1"
       ],
       "type": "string"
      }
     },
     {
      "description": "Minimum TVL in USD.",
      "in": "query",
      "name": "min_tvl",
      "schema": {
       "type": "number"
      }
     },
     {
      "description": "`amm`: tradable pools only; `rate`: mint/redeem and lending rate venues only (tALGO, xALGO, Folks fAssets: their TVL is redeemable backing, not market liquidity). Default: both, as separate rows.",
      "in": "query",
      "name": "kind",
      "schema": {
       "enum": [
        "amm",
        "rate"
       ],
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Pairs"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      },
      "description": "Bad parameter or unknown asset"
     },
     "402": {
      "description": "Payment required: x402 offer in the PAYMENT-REQUIRED header (base64 JSON; the same JSON is the body). Retry with PAYMENT-SIGNATURE."
     },
     "429": {
      "description": "Rate limit exceeded (10 requests/s per client IP, burst 20)"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      },
      "description": "Internal error"
     }
    },
    "summary": "All pairs with a live pool on a day",
    "tags": [
     "markets"
    ]
   }
  },
  "/v1/prices/pools": {
   "get": {
    "operationId": "pricesPools",
    "parameters": [
     {
      "description": "ASA id, `algo` (= 0) or `usdc` (= 31566704).",
      "example": "386192725",
      "in": "query",
      "name": "asset",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Pools"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      },
      "description": "Bad parameter or unknown asset"
     },
     "402": {
      "description": "Payment required: x402 offer in the PAYMENT-REQUIRED header (base64 JSON; the same JSON is the body). Retry with PAYMENT-SIGNATURE."
     },
     "429": {
      "description": "Rate limit exceeded (10 requests/s per client IP, burst 20)"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      },
      "description": "Internal error"
     }
    },
    "summary": "Pools holding an asset",
    "tags": [
     "markets"
    ]
   }
  },
  "/v1/prices/price": {
   "get": {
    "description": "The price after round `round`, or after the last block at or before `ts`. With neither, the price at the indexed tip (seconds behind the chain). A `ts` at or after the tip is answered at the tip and echoed as `requested_ts`.",
    "operationId": "pricesPrice",
    "parameters": [
     {
      "description": "ASA id, `algo` (= 0) or `usdc` (= 31566704).",
      "example": "386192725",
      "in": "query",
      "name": "asset",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Quote asset (ASA id, `algo` or `usdc`). Default USDC.",
      "in": "query",
      "name": "quote",
      "schema": {
       "default": "usdc",
       "type": "string"
      }
     },
     {
      "description": "Round (exclusive of `ts`).",
      "example": 65000000,
      "in": "query",
      "name": "round",
      "schema": {
       "format": "int64",
       "type": "integer"
      }
     },
     {
      "description": "Time (exclusive of `round`). Unix seconds, RFC 3339, or YYYY-MM-DD (UTC).",
      "example": "2026-09-13T09:16:17Z",
      "in": "query",
      "name": "ts",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "`1` lists every pool quote used: venue, pool, via-asset, implied USD price, weight, kept.",
      "in": "query",
      "name": "details",
      "schema": {
       "enum": [
        "0",
        "1"
       ],
       "type": "string"
      }
     },
     {
      "description": "Minimum pool liquidity in USD for a pool to be used in routing.",
      "in": "query",
      "name": "min_liq",
      "schema": {
       "default": 50,
       "type": "number"
      }
     },
     {
      "description": "Maximum route length from the asset to USDC.",
      "in": "query",
      "name": "max_hops",
      "schema": {
       "default": 4,
       "type": "integer"
      }
     },
     {
      "description": "Ignore pools with no event for this many days.",
      "in": "query",
      "name": "stale_days",
      "schema": {
       "default": 30,
       "type": "integer"
      }
     },
     {
      "description": "Drop pool quotes deviating more than this fraction from the liquidity-weighted median.",
      "in": "query",
      "name": "max_dev",
      "schema": {
       "default": 0.2,
       "type": "number"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Price"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      },
      "description": "Bad parameter or unknown asset"
     },
     "402": {
      "description": "Payment required: x402 offer in the PAYMENT-REQUIRED header (base64 JSON; the same JSON is the body). Retry with PAYMENT-SIGNATURE."
     },
     "429": {
      "description": "Rate limit exceeded (10 requests/s per client IP, burst 20)"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      },
      "description": "Internal error"
     }
    },
    "summary": "Price of an asset at a round or time",
    "tags": [
     "prices"
    ]
   }
  },
  "/v1/prices/pricing": {
   "get": {
    "operationId": "pricesPricing",
    "responses": {
     "200": {
      "description": "OK"
     }
    },
    "summary": "Paid resources and their prices (free)",
    "tags": [
     "status"
    ]
   }
  },
  "/v1/prices/status": {
   "get": {
    "operationId": "pricesStatus",
    "responses": {
     "200": {
      "description": "OK"
     }
    },
    "summary": "How far the dataset is built (free)",
    "tags": [
     "status"
    ]
   }
  }
 },
 "servers": [
  {
   "url": "https://x402.api.nodely.io"
  }
 ],
 "tags": [
  {
   "name": "prices"
  },
  {
   "name": "markets"
  },
  {
   "name": "status"
  }
 ]
}