{"openapi":"3.1.0","info":{"title":"hyper-bank-indexer API","description":"Multichain EVM token indexer + wallet balances across every EVM mainnet. Balances come five ways: /balances (cached current state, watched wallets), /portfolio (live balanceOf over the token universe, any wallet, RPC), /balance-at (exact archive read at a block, RPC), /balance-delta (one token, summed from indexed logs, no RPC), and /wallet/{addr}/holdings (every token on every chain, summed from indexed logs, no RPC). Non-EVM (UTXO) addresses are rejected with a clear message.","license":{"name":""},"version":"0.2.0"},"paths":{"/chains":{"get":{"tags":["chains"],"operationId":"chains","responses":{"200":{"description":"Chains with ERC-20 transfers indexed (enabled ∩ has activity)"}}}},"/chains/{chain_id}/disable":{"post":{"tags":["chains"],"operationId":"chain_disable","responses":{"200":{"description":"Chain disabled"},"404":{"description":"No such chain"}}}},"/chains/{chain_id}/enable":{"post":{"tags":["chains"],"operationId":"chain_enable","responses":{"200":{"description":"Chain enabled"},"404":{"description":"No such chain"}}}},"/gas":{"get":{"tags":["radar"],"operationId":"gas","parameters":[{"name":"chain","in":"query","description":"Chain id","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"hashes","in":"query","description":"Comma-separated tx hashes","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"tx_hash -> gas_used for the given transactions on one chain"}}}},"/health":{"get":{"tags":["health"],"operationId":"health","responses":{"200":{"description":"Service is up"}}}},"/health/ready":{"get":{"tags":["health"],"operationId":"ready","responses":{"200":{"description":"Ready — Postgres reachable (ClickHouse/Redis reported)"},"503":{"description":"Not ready — Postgres unreachable"}}}},"/internal":{"get":{"tags":["radar"],"operationId":"internal","parameters":[{"name":"chain","in":"query","description":"Chain id filter","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"limit","in":"query","description":"Max rows (1-200, default 25)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Recent native internal transfers, newest first"}}}},"/radar":{"get":{"tags":["radar"],"operationId":"radar","responses":{"200":{"description":"Per-chain liveness snapshot (tip block + staleness) from the cursor table"}}}},"/stats":{"get":{"tags":["transfers"],"operationId":"stats","responses":{"200":{"description":"Per-chain transfer counts + cursor positions"}}}},"/swaps":{"get":{"tags":["radar"],"operationId":"swaps","parameters":[{"name":"chain","in":"query","description":"Chain id filter","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"limit","in":"query","description":"Max rows (1-200, default 25)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Recent decoded DEX swaps (Uniswap V2/V3 + forks), newest first"}}}},"/tokens/{chain}/{token}":{"get":{"tags":["tokens"],"operationId":"token_info","parameters":[{"name":"chain","in":"path","description":"EVM chain id","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"token","in":"path","description":"ERC-20 token contract address","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Token symbol + decimals (on-chain, memoized)"},"500":{"description":"Invalid token address"}}}},"/transactions":{"get":{"tags":["radar"],"operationId":"transactions","parameters":[{"name":"chain","in":"query","description":"Chain id filter","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"limit","in":"query","description":"Max rows (1-200, default 25)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Recent normal (regular) transactions, newest first"}}}},"/transfers":{"get":{"tags":["transfers"],"operationId":"transfers","parameters":[{"name":"chain","in":"query","description":"Chain id filter","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"token","in":"query","description":"Token address filter","required":false,"schema":{"type":"string"}},{"name":"address","in":"query","description":"From/to address filter","required":false,"schema":{"type":"string"}},{"name":"from_block","in":"query","description":"Min block (inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to_block","in":"query","description":"Max block (inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cursor","in":"query","description":"Keyset page token from next_cursor","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max rows (1-1000, default 50)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"{ data, next_cursor } — newest first, keyset-paginated"},"500":{"description":"Invalid address/token"}}}},"/wallet/{addr}/balance-at":{"get":{"tags":["balances"],"operationId":"balance_at","parameters":[{"name":"addr","in":"path","description":"EVM wallet address","required":true,"schema":{"type":"string"}},{"name":"chain","in":"query","description":"Chain id","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"token","in":"query","description":"ERC-20 token address","required":true,"schema":{"type":"string"}},{"name":"block","in":"query","description":"Block height (omit = latest)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Exact balanceOf at a block (live archive RPC, not the cache)"},"500":{"description":"Invalid address"}}}},"/wallet/{addr}/balance-delta":{"get":{"tags":["balances"],"operationId":"balance_delta","parameters":[{"name":"addr","in":"path","description":"EVM wallet address","required":true,"schema":{"type":"string"}},{"name":"chain","in":"query","description":"Chain id","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"token","in":"query","description":"ERC-20 token address","required":true,"schema":{"type":"string"}},{"name":"to_block","in":"query","description":"Count transfers at/below this block","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Net token flow (received - sent) from indexed transfers; no RPC"},"500":{"description":"Invalid address"}}}},"/wallet/{addr}/balances":{"get":{"tags":["balances"],"summary":"Indexed balances for a WATCHED wallet — pure Postgres, milliseconds, no\nRPC. Kept fresh by the worker's event-triggered refresh + daily snapshot.\nFor unwatched wallets use /portfolio (live multicall) instead.","operationId":"balances","parameters":[{"name":"addr","in":"path","description":"EVM address","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Indexed balances for a watched wallet (Postgres, no RPC)"}}}},"/wallet/{addr}/holdings":{"get":{"tags":["balances"],"operationId":"holdings","parameters":[{"name":"addr","in":"path","description":"EVM address","required":true,"schema":{"type":"string"}},{"name":"chain","in":"query","description":"Restrict to one chain (default: all chains)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Per-(chain,token) net flow summed from indexed transfer logs; no RPC, any wallet"},"400":{"description":"Not an EVM address"}}}},"/wallet/{addr}/portfolio":{"get":{"tags":["balances"],"operationId":"portfolio","parameters":[{"name":"addr","in":"path","description":"EVM address","required":true,"schema":{"type":"string"}},{"name":"chain","in":"query","description":"Restrict to one chain (default: all chains with token metadata)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Live Multicall3 balances across the token universe; any wallet, no indexing required"},"400":{"description":"Not an EVM address"}}}},"/wallets/{addr}/transfers":{"get":{"tags":["transfers"],"operationId":"wallet_transfers","parameters":[{"name":"addr","in":"path","description":"EVM address (matches from or to)","required":true,"schema":{"type":"string"}},{"name":"chain","in":"query","description":"Chain id filter","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"token","in":"query","description":"Token address filter","required":false,"schema":{"type":"string"}},{"name":"from_block","in":"query","description":"Min block (inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to_block","in":"query","description":"Max block (inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cursor","in":"query","description":"Keyset page token from next_cursor","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max rows (1-1000, default 50)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"A wallet's ERC-20 transfers, keyset-paginated"},"500":{"description":"Invalid address/token"}}}},"/warm":{"post":{"tags":["ops"],"operationId":"warm","responses":{"200":{"description":"Per-wallet warm timings"},"500":{"description":"ClickHouse unavailable"}}}},"/watch":{"get":{"tags":["watch"],"operationId":"watch_list","responses":{"200":{"description":"Watched wallets with holding counts"}}}},"/watch/bulk":{"post":{"tags":["watch"],"operationId":"watch_add_bulk","responses":{"202":{"description":"Accepted; balances snapshot runs in the background"},"400":{"description":"No valid addresses"}}}},"/watch/{address}":{"delete":{"tags":["watch"],"operationId":"watch_purge","responses":{"200":{"description":"Wallet purged"},"404":{"description":"Not watched"}}}},"/watch/{address}/stop":{"post":{"tags":["watch"],"operationId":"watch_stop","responses":{"200":{"description":"Wallet stopped (data kept)"},"404":{"description":"Not watched"}}}}},"components":{},"tags":[{"name":"health","description":"Liveness"},{"name":"transfers","description":"Firehose reads: stats, transfers, wallet activity"},{"name":"balances","description":"Wallet balances — cached current state, live RPC scans (portfolio, at-block), and log-derived estimates (delta, holdings)"},{"name":"watch","description":"Wallet subscription"},{"name":"chains","description":"Dynamic chain registry + enable/disable"},{"name":"radar","description":"Per-chain liveness + internal transfers"},{"name":"ops","description":"Operational: cache warming"}]}