{"openapi":"3.1.0","x-blockreq-source":{"repository":"blockreq/liveapi","path":"apps/api/openapi.yaml","commit":"950df84"},"servers":[{"url":"https://api.blockreq.com","description":"The BlockReq API gateway, which authenticates and meters calls and forwards /v1/dex/... to the data service."}],"security":[{"ApiKey":[]},{"BearerKey":[]},{}],"info":{"version":"0.4.0","title":"BlockReq Wallet API","summary":"Token holder rankings, address portfolios and pool trades from BlockReq's DEX index.","description":"The Wallet API is part of the BlockReq Crypto API. It shares the On-chain DEX API's host, API key, quota and error shapes; this document lists only its own operations.\n\nSend the key of a Crypto API endpoint in `X-API-Key` (or `Authorization: Bearer <key>`). Without a key a request is anonymous and limited per IP address. Plans and limits are in the guide (https://blockreq.com/docs/build/wallet-api/)."},"tags":[{"name":"DEX API","description":"BlockReq's own routes. Chains are named `ethereum`, `base`, `bsc`, `arbitrum` and `polygon`."},{"name":"Wallet API","description":"Wallets: holders, positions, cost basis and PnL. Part of the Crypto Data API with the On-chain DEX API: the same API key, quota and pricing."}],"paths":{"/v1/dex/{chain}/tokens/{address}/holders":{"get":{"tags":["Wallet API"],"operationId":"getTokenHolders","summary":"A token's largest holders","description":"The top `limit` holders, counted from the token's ERC-20 Transfers. Burn addresses, Uniswap v4 PoolManagers and the pools holding the token are left out of the ranking and of the known total that `pct` is a share of. Only tracked tokens have a ranking: an anchor, a token in no indexed pool, a blocked token, or one not caught up to the Portal's head yet answers 404. A newly tracked token is backfilled from the chain's genesis, so it answers 404 until that backfill is done; the highest-reserve tokens are backfilled first. On Base the backfill is still running (November 2026) and no token has a ranking yet, so every Base token answers 404 for now: that is the data still being filled, not an error.","parameters":[{"$ref":"#/components/parameters/Chain"},{"$ref":"#/components/parameters/TokenAddress"},{"name":"limit","in":"query","description":"Most holders returned.","schema":{"type":"integer","minimum":1,"maximum":5000,"default":5000}}],"responses":{"200":{"description":"The ranking.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Holders"}}}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/GatewayUnauthorized"},"403":{"$ref":"#/components/responses/GatewayForbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/GatewayRateLimited"},"500":{"$ref":"#/components/responses/Internal"},"502":{"$ref":"#/components/responses/GatewayBadGateway"},"503":{"$ref":"#/components/responses/Unavailable"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/v1/dex/{chain}/accounts/{address}/portfolio":{"get":{"tags":["Wallet API"],"operationId":"getAccountPortfolio","summary":"An address's lightweight portfolio","description":"What an address holds on the chain, ranked by USD value (largest first, holdings without one last).\n\n**Without `tokens` the answer is the address's whole position in every token BlockReq lists on the chain** (the tokens `GET /v1/dex/{chain}/tokens` pages through, stablecoins and majors included), plus the native coin. BlockReq reads the `balanceOf` of all of them from its own node at one block (`node_block`) through Multicall3 `aggregate3`, in batches of 500, and returns every non-zero one; `complete` is true. The list of tokens read is cached for 10 minutes, so a token newly listed reaches this read within that time. This full read is on for Ethereum; other chains (and any chain whose node has no Multicall3) answer as below, with `complete` false. Balances of tokens BlockReq does not list are not read: this is not every ERC-20 the address holds. A reading that failed for one token (a revert, or an answer that is not a uint256) leaves that token out and lists it in `failed`; a batch the node cannot answer at all fails the request with 503 instead of returning a result that misses it.\n\nThe chain's native coin is always included, as one holding with `native` true (ETH on Ethereum, Base and Arbitrum): its balance is read with `eth_getBalance` from BlockReq's own node at the same block, valued at the price of the chain's wrapped native token (so ETH and WETH carry the same price) and counted in `total_value_usd`; a zero balance has no row. A node reading wins over the holder ranking's stored balance (a zero drops the token).\n\nWithout the full read (a chain that does not take it, or `tokens` listed) the tokens come from two sources only, and `complete` is false: the balances the holder ranking stores (only tracked tokens whose top 5000 the address is in), and `balanceOf` from the same node for the tokens `tokens` lists. `tokens` behaves as before.\n\nThe result for one address on one chain is reused for 20 seconds, so balances can be up to about two Ethereum blocks old; `node_block` says which block they are as of. Holdings come in pages of `limit` (100 by default, 1,000 at most), `total` is the number of all of them and `total_value_usd` always counts all of them. Full reads share a small number of slots on the node: when they are all taken and the queue is full or the wait is over, the request answers 503 with `Retry-After`. An address with nothing found answers 200 and an empty list.","parameters":[{"$ref":"#/components/parameters/Chain"},{"name":"address","in":"path","required":true,"description":"The holder's address, in any case.","schema":{"$ref":"#/components/schemas/AddressInput"}},{"name":"limit","in":"query","description":"Most holdings returned in this page.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":100}},{"name":"cursor","in":"query","description":"The `next_cursor` of the previous page; any other value answers 400. It is tied to the node block of the reading it came from: once the result is read again (after about 20 seconds) at a newer block, an older cursor answers 400 and the paging starts again without one.","schema":{"$ref":"#/components/schemas/PortfolioCursor"}},{"name":"tokens","in":"query","description":"Up to 50 comma-separated ERC-20 addresses (duplicates count once) to read with `balanceOf` from BlockReq's own node, in addition to the holder ranking's stored balances (this replaces the full read). The native coin's address is refused. On a chain without a node configured, listing any answers 503.","schema":{"type":"string","pattern":"^\\s*0x[0-9a-fA-F]{40}\\s*(,\\s*0x[0-9a-fA-F]{40}\\s*)*$"}}],"responses":{"200":{"description":"The portfolio.","content":{"application/json":{"schema":{"type":"object","required":["data","next_cursor","total"],"properties":{"data":{"$ref":"#/components/schemas/Portfolio"},"next_cursor":{"description":"The `cursor` of the next page; null on the last.","oneOf":[{"$ref":"#/components/schemas/PortfolioCursor"},{"type":"null"}]},"total":{"type":"integer","minimum":0,"description":"How many holdings the address has, whatever `cursor` and `limit` are; on every page."}}}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/GatewayUnauthorized"},"403":{"$ref":"#/components/responses/GatewayForbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/GatewayRateLimited"},"500":{"$ref":"#/components/responses/Internal"},"502":{"$ref":"#/components/responses/GatewayBadGateway"},"503":{"description":"Postgres cannot serve right now, `tokens` were listed on a chain without a node configured, the node did not answer (including one batch of a full read), or too many full reads are in progress (with `Retry-After`); the message says which. The gateway may also answer 503 here (see `GatewayUnavailableError`).","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"const":"unavailable"},"message":{"type":"string"}}}}},"example":{"error":{"code":"unavailable","message":"balance reads are not available on base; retry without tokens"}}}}},"504":{"$ref":"#/components/responses/Timeout"}}}},"/v1/dex/{chain}/pools/{id}/trades":{"get":{"tags":["DEX API"],"operationId":"listPoolTrades","summary":"A pool's trades","description":"Newest first. A full page comes with `next_cursor`; pass it as `cursor` for the next page. Raw trades are kept for a limited window: a listed pool's for 90 days, any other pool's candidate trades for 30 days (an unknown pool has none, an empty list). `earliest_available` says where that window starts, so paging that ends there has reached the end of the kept trades rather than lost any; older history is in the candles. This endpoint never reads the cold archive.","parameters":[{"$ref":"#/components/parameters/Chain"},{"$ref":"#/components/parameters/PoolId"},{"name":"limit","in":"query","description":"Most trades per page.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"A page of trades.","headers":{"X-Data-Tier":{"$ref":"#/components/headers/DataTier"}},"content":{"application/json":{"schema":{"type":"object","required":["data","next_cursor","earliest_available"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Trade"}},"next_cursor":{"description":"Where the next page starts; null when this page was the last (shorter than `limit`).","oneOf":[{"$ref":"#/components/schemas/Cursor"},{"type":"null"}]},"earliest_available":{"description":"Unix seconds of the start of the oldest UTC day whose trades this pool still serves (90 days back for a listed pool, 30 for any other). Trades before it are no longer kept; their history is in the candles.","type":"integer"}}}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/GatewayUnauthorized"},"403":{"$ref":"#/components/responses/GatewayForbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/GatewayRateLimited"},"500":{"$ref":"#/components/responses/Internal"},"502":{"$ref":"#/components/responses/GatewayBadGateway"},"503":{"$ref":"#/components/responses/Unavailable"},"504":{"$ref":"#/components/responses/Timeout"}}}}},"components":{"parameters":{"Chain":{"name":"chain","in":"path","required":true,"description":"The chain: its name here, or its EVM chain id, CoinGecko network id or CoinGecko asset platform id, in any case (see Chain identifiers). Any other value answers 404.","schema":{"$ref":"#/components/schemas/ChainName"}},"TokenAddress":{"name":"address","in":"path","required":true,"description":"Token address, in any case.","schema":{"$ref":"#/components/schemas/AddressInput"}},"PoolId":{"name":"id","in":"path","required":true,"description":"Pool address, or the 64-digit pool id of a Uniswap v4 pool, in any case.","schema":{"$ref":"#/components/schemas/PoolIdInput"}},"Cursor":{"name":"cursor","in":"query","description":"The `next_cursor` of the previous page; any other value answers 400.","schema":{"$ref":"#/components/schemas/Cursor"}}},"schemas":{"Holders":{"type":"object","required":["chain","address","symbol","decimals","block","known_total","known_total_amount","total_supply","consistent","excluded","top"],"properties":{"chain":{"$ref":"#/components/schemas/ChainName"},"address":{"$ref":"#/components/schemas/Address"},"symbol":{"type":["string","null"]},"decimals":{"type":["integer","null"]},"block":{"description":"Transfers up to this block are counted.","type":"integer"},"known_total":{"description":"Sum of every balance besides the excluded addresses', raw; the denominator of `pct`.","$ref":"#/components/schemas/RawAmount"},"known_total_amount":{"description":"`known_total` in whole tokens; null when the decimals are unknown.","$ref":"#/components/schemas/NullableDecimal"},"total_supply":{"description":"The token's `totalSupply()` read from BlockReq's own node; null when it could not be read.","oneOf":[{"$ref":"#/components/schemas/RawAmount"},{"type":"null"}]},"consistent":{"description":"Whether the Transfers add up to within 1% of `total_supply`; null without it. When false (a token that mints without a Transfer, rebases and the like) balances may be off and every `pct` is null.","type":["boolean","null"]},"excluded":{"description":"Burn addresses, Uniswap v4 PoolManagers and the pools holding the token themselves, left out.","type":"array","items":{"$ref":"#/components/schemas/Address"}},"top":{"description":"Largest balance first.","type":"array","items":{"type":"object","required":["rank","address","balance","amount","pct"],"properties":{"rank":{"description":"1 for the largest.","type":"integer"},"address":{"$ref":"#/components/schemas/Address"},"balance":{"$ref":"#/components/schemas/RawAmount"},"amount":{"description":"The balance in whole tokens; null when the decimals are unknown.","$ref":"#/components/schemas/NullableDecimal"},"pct":{"description":"Percent of `known_total`, to 6 decimals; null when the known total is 0 or `consistent` is false.","$ref":"#/components/schemas/NullableDecimal"}}}}}},"AddressInput":{"description":"`0x` and 40 hex digits, in any case.","type":"string","pattern":"^0x[0-9a-fA-F]{40}$"},"PortfolioCursor":{"description":"An opaque portfolio cursor this API returned.","type":"string","pattern":"^[A-Za-z0-9_-]{1,40}$"},"Portfolio":{"type":"object","required":["chain","address","total_value_usd","holdings","node_block","complete","failed"],"properties":{"chain":{"$ref":"#/components/schemas/ChainName"},"address":{"$ref":"#/components/schemas/Address"},"total_value_usd":{"description":"Sum of every `value_usd` of all the holdings, not only this page's, to 6 decimals; holdings without one are not counted.","$ref":"#/components/schemas/Decimal"},"holdings":{"description":"This page of the holdings, largest `value_usd` first, holdings without one last.","type":"array","items":{"type":"object","required":["token","native","symbol","name","decimals","balance","amount","price_usd","value_usd","source","block"],"properties":{"token":{"description":"The token's contract address; `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee` on the native coin's row.","$ref":"#/components/schemas/Address"},"native":{"description":"True on the chain's native coin, false on ERC-20 holdings.","type":"boolean"},"symbol":{"type":["string","null"]},"name":{"type":["string","null"]},"decimals":{"type":["integer","null"]},"balance":{"$ref":"#/components/schemas/RawAmount"},"amount":{"description":"The balance in whole tokens; null when the decimals are unknown.","$ref":"#/components/schemas/NullableDecimal"},"price_usd":{"$ref":"#/components/schemas/NullableDecimal"},"value_usd":{"description":"`amount` × `price_usd`, to 6 decimals; null when either is missing.","$ref":"#/components/schemas/NullableDecimal"},"source":{"description":"`holders`: the holder ranking's stored balance; `node`: `balanceOf` (or, for the native coin, `eth_getBalance`) on BlockReq's own node.","enum":["holders","node"]},"block":{"description":"Block the balance is as of.","type":"integer"}}}},"node_block":{"description":"Block of the node's reads (`balanceOf` and the native balance); null when none was made (the chain has no node configured, or the node did not answer and no tokens were listed).","type":["integer","null"]},"complete":{"description":"True when BlockReq's node read every token the chain lists (the full read), so the holdings are the address's whole position in those tokens apart from `failed`; false when the holdings are the holder ranking's stored balances plus the tokens `tokens` listed.","type":"boolean"},"failed":{"description":"Tokens whose `balanceOf` failed (those listed in `tokens`, or any listed token in a full read), and `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee` when the native balance could not be read; a stored balance is kept for a failed token.","type":"array","items":{"$ref":"#/components/schemas/Address"}}}},"Trade":{"type":"object","required":["block_number","log_index","time","tx_hash","trader","amount0","amount1","price","amount_usd","price0_usd","price1_usd"],"properties":{"block_number":{"type":"integer"},"log_index":{"type":"integer"},"time":{"type":"string","format":"date-time"},"tx_hash":{"$ref":"#/components/schemas/TxHash"},"trader":{"description":"The transaction's sender, when known.","oneOf":[{"$ref":"#/components/schemas/Address"},{"type":"null"}]},"amount0":{"description":"Raw token0 amount in the pool's view (positive = the pool received it).","$ref":"#/components/schemas/RawAmount"},"amount1":{"description":"Raw token1 amount in the pool's view (positive = the pool received it).","$ref":"#/components/schemas/RawAmount"},"price":{"description":"Whole token1 per whole token0 this trade executed at.","$ref":"#/components/schemas/NullableDecimal"},"amount_usd":{"$ref":"#/components/schemas/NullableDecimal"},"price0_usd":{"$ref":"#/components/schemas/NullableDecimal"},"price1_usd":{"$ref":"#/components/schemas/NullableDecimal"}}},"Cursor":{"description":"An opaque page cursor this API returned.","type":"string","pattern":"^[0-9]{1,15}\\.[0-9]{1,12}\\.[0-9]{1,7}$"},"ChainName":{"description":"Chain name as the DEX API uses it; responses always give this value. Parameters also take the other chain identifiers (see Chain identifiers).","type":"string","enum":["ethereum","base","bsc","arbitrum","polygon"]},"Address":{"description":"`0x` and 40 lowercase hex digits.","type":"string","pattern":"^0x[0-9a-f]{40}$"},"RawAmount":{"description":"A raw token amount (no decimals applied) as an integer string.","type":"string","pattern":"^-?[0-9]+$"},"NullableDecimal":{"description":"A decimal number as a string, or null when unknown.","type":["string","null"]},"GatewayUnauthorizedError":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"const":"invalid_key"},"message":{"type":"string"}}}}},"GatewayForbiddenError":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"const":"forbidden"},"message":{"type":"string"}}}}},"NotFoundError":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"const":"not_found"},"message":{"type":"string"}}}}},"GatewayRateLimitedError":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"description":"`rate_limited` over the request rate; `quota_exceeded` when the period's quota is used up. These are the only two codes a 429 carries (`quota_exhausted` is a field of the gateway's auth snapshot and a metric label, never a response code).","type":"string","enum":["rate_limited","quota_exceeded"]},"message":{"type":"string"}}}}},"GatewayBadGatewayError":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["upstream_failed","response_too_large"]},"message":{"type":"string"}}}}},"UnavailableError":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"const":"unavailable"},"message":{"const":"temporarily unavailable; retry shortly"}}}}},"GatewayUnavailableError":{"description":"The gateway's 503.","type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"const":"unavailable"},"message":{"type":"string","enum":["API key authentication temporarily unavailable","temporarily unavailable; retry shortly"]}}}}},"TimeoutError":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"const":"timeout"},"message":{"const":"query took too long; narrow the range"}}}}},"GatewayTimeoutError":{"description":"The gateway's 504.","type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"const":"timeout"},"message":{"const":"gateway deadline exceeded"}}}}},"Decimal":{"description":"A decimal number as a string, e.g. `\"2500.5\"`.","type":"string"},"PoolIdInput":{"description":"`0x` and 40 hex digits (a pool address) or 64 (a Uniswap v4 pool id), in any case.","type":"string","pattern":"^0x([0-9a-fA-F]{40}|[0-9a-fA-F]{64})$"},"TxHash":{"type":"string","pattern":"^0x[0-9a-f]{64}$"}},"responses":{"InvalidRequest":{"description":"A parameter or the body is invalid; the message says which.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"const":"invalid_request"},"message":{"type":"string"}}}}},"example":{"error":{"code":"invalid_request","message":"limit must be an integer from 1 to 100"}}}}},"GatewayUnauthorized":{"description":"Answered by the gateway. The key is unknown or revoked, or it was sent somewhere other than the `X-API-Key` or `Authorization: Bearer` header (a query parameter, a cookie, another header or a path segment). An invalid key never falls back to anonymous access.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayUnauthorizedError"},"example":{"error":{"code":"invalid_key","message":"Invalid API key. Get a key at blockreq.com and send it in the X-API-Key header."}}}}},"GatewayForbidden":{"description":"Answered by the gateway. The account is suspended, the key's On-chain DEX API endpoints are all expired or do not allow the client IP, or the key has only RPC endpoints and the RPC-key transition (until 2026-12-03T00:00:00Z) is over.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayForbiddenError"},"examples":{"forbidden":{"summary":"Access denied","value":{"error":{"code":"forbidden","message":"API key access denied"}}},"rpc_only":{"summary":"An RPC key after the transition","value":{"error":{"code":"forbidden","message":"This API key is for RPC only. Create an On-chain DEX API endpoint at blockreq.com to get a data API key."}}}}}}},"NotFound":{"description":"The chain is not served, or the token or pool is not indexed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotFoundError"},"example":{"error":{"code":"not_found","message":"token is not indexed"}}}}},"GatewayRateLimited":{"description":"Answered by the gateway. `rate_limited`: over the request rate (with a key, the plan's rate; without a key, the per-IP window); every request takes one token whatever its units, and `Retry-After` is 1 with a key. `quota_exceeded`: the plan's quota for the current 30-day period is used up; `Retry-After` is the seconds left in the period and `X-BlockReq-Data-Api-Quota-Reset` is when it ends. The quota is marked after settlement, so a few calls may still pass after it runs out.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-BlockReq-Data-Api-Quota-Reset":{"$ref":"#/components/headers/QuotaReset"},"X-BlockReq-Data-Api-Units":{"$ref":"#/components/headers/Units"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayRateLimitedError"},"examples":{"rate_limited":{"summary":"Over the plan's rate (with a key)","value":{"error":{"code":"rate_limited","message":"Rate limit reached for this API key. See blockreq.com for higher limits."}}},"rate_limited_anonymous":{"summary":"Over the per-IP window (without a key)","value":{"error":{"code":"rate_limited","message":"Rate limit reached. Get a free API key at blockreq.com for a higher limit."}}},"quota_exceeded":{"summary":"The period's quota is used up","value":{"error":{"code":"quota_exceeded","message":"Data API quota reached for this period; it resets at 2026-12-01T08:00:00Z. See blockreq.com for higher limits."}}}}}}},"Internal":{"description":"An unexpected failure.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"const":"internal"},"message":{"const":"internal error"}}}}}}}},"GatewayBadGateway":{"description":"Answered by the gateway. The data service failed, did not answer in time (10 seconds), or answered more than the gateway relays (8 MiB). Worth retrying with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayBadGatewayError"},"example":{"error":{"code":"upstream_failed","message":"upstream request failed"}}}}},"Unavailable":{"description":"Postgres or ClickHouse cannot serve right now (from the data service), or the gateway cannot authenticate keys or record usage for a moment. Retry shortly.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/UnavailableError"},{"$ref":"#/components/schemas/GatewayUnavailableError"}]}}}},"Timeout":{"description":"A query ran out of time (from the data service; narrow the range), or the gateway ran out of time for the whole request.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/TimeoutError"},{"$ref":"#/components/schemas/GatewayTimeoutError"}]}}}}},"headers":{"DataTier":{"description":"Where the answer was read from: `hot` (ClickHouse, the kept window) or `archive` (the cold Parquet archive, seconds slower). Every endpoint carrying it today answers from `hot`.","required":true,"schema":{"type":"string","enum":["hot","archive"]}},"RetryAfter":{"description":"Seconds to wait before sending the request again.","required":true,"schema":{"type":"integer","minimum":1}},"QuotaReset":{"description":"Only on `quota_exceeded`. When the current period ends and the quota resets, in Unix seconds.","schema":{"type":"integer"}},"Units":{"description":"On every response to a request with a valid key: the calls this request counted against the quota. The units of a 2xx answer (1, or for `POST /v1/dex/prices` one per 10 tokens, rounded up); `0` on every other answer. Absent on anonymous requests and on an invalid key.","schema":{"type":"integer","minimum":0}}},"securitySchemes":{"ApiKey":{"type":"apiKey","in":"header","name":"X-API-Key","description":"The key of an On-chain DEX API endpoint (Dashboard → Endpoints → Add Endpoint → On-chain DEX API). Until 2026-12-03T00:00:00Z an RPC key is accepted too and counts against the same account's data API quota."},"BearerKey":{"type":"http","scheme":"bearer","description":"The same key as `ApiKey`, sent as `Authorization: Bearer <key>`."}}}}