{"openapi":"3.0.0","info":{"title":"Alphscan API","description":"API for Alphscan indexer and normalized events.\n\n**Authentication:** Click **Authorize**, enter your API key once. It is sent as both X-API-Key and Authorization Bearer (API Gateway requires both).\n","version":"1.0.0"},"servers":[{"url":"https://api.alphscan.io/prod","description":"prod [Public]"},{"url":"https://api.alphscan.io/dev","description":"dev [Public]"},{"url":"https://api.alphscan.io/prod","description":"prod [Admin]"},{"url":"https://api.alphscan.io/dev","description":"dev [Admin]"}],"tags":[{"name":"Addresses","description":"Address labels (list, add, delete) and **decorated transaction lists** proxied from the Alephium explorer\n(`GET /addresses/{address}/transactions`, `GET /addresses/{address}/tokens/{tokenid}/transactions`), enriched with Alphscan `alphscan` metadata (including **main_event_pending** on each tx when the DB is configured).\n"},{"name":"Category","description":"Category registry (tokens and dapps). List, add, soft-delete. Used by token and dapp filters."},{"name":"Chain","description":"Chain metadata (chainlist.org-style), list, add from chainlist, update, soft delete, search"},{"name":"Contracts","description":"Contract registry (list paginated)"},{"name":"NFT","description":"NFT collections (INFTCollection / INFTCollectionWithRoyalty) and NFTs (INFT); indexed rows with on-chain state and resolved metadata"},{"name":"Dapps","description":"Dapp registry (list, add, update, delete, link categories; max 3 categories per dapp)"},{"name":"dapps:furnace","description":"Furnace dapp — burn events indexed from on-chain contracts (ALPH and token burns).\nCursor-based pagination via `nextKey`.\n"},{"name":"dapps:chainreaction","description":"ChainReaction dapp — play and burn events indexed from all game contracts (V1 and V3).\nCursor-based pagination via `nextKey`.\n"},{"name":"dapps:elexium","description":"Elexium dapp — EX token summary/price/TVL/burns, staking reward distributions, veNFT list and vote events, DEX pool/swap data, and EX/USD price history.\nCursor-based pagination via `nextKey`.\n"},{"name":"dapps:alphbanx","description":"AlphBanx dapp — loans, auctions and staker positions mirrored from the abx-mirror service.\nRequires user authentication. Cursor-based pagination via `nextKey`.\n"},{"name":"dapps:dia-oracle","description":"DIA on-chain oracle — historical price feeds for ALPH/USD, BTC/USD, ETH/USD, and all other oracle-tracked pairs.\nCursor-based pagination via `nextKey`.\n"},{"name":"Events","description":"Normalized events (by transaction or list/poll all)"},{"name":"Series","description":"Series metadata and configuration used by indexer-series"},{"name":"Token","description":"Token registry, categories, and **decorated token transaction lists** (`GET /token/{tokenid}/transactions`, explorer proxy + Alphscan enrichment, including **main_event_pending** per tx).\n"},{"name":"Price","description":"Price section – sources, spot price, OHLC candles (ALPH or USDT)"},{"name":"Transaction","description":"Per-transaction normalized events (`GET /transaction/{txid}/events`) and **decorated transaction by hash**\n(`GET /transaction/{transaction_id}`, explorer proxy + full normalized events when configured).\n"},{"name":"Blocks","description":"Block metadata and transactions (Alephium explorer proxy, enriched with Alphscan)"},{"name":"Keys","description":"API keys and origins"},{"name":"Plans","description":"API plans (list, upsert, delete)"},{"name":"Payment","description":"Payments and history"},{"name":"Banned","description":"Banned users"},{"name":"Telegram","description":"Telegram bot admins"},{"name":"Webhook","description":"Telegram webhook"},{"name":"WireGuard","description":"WireGuard connectivity checks (ping, PostgreSQL via EC2)"},{"name":"Docs","description":"Documentation and OpenAPI spec"}],"paths":{"/docs":{"get":{"tags":["Docs"],"summary":"API docs","operationId":"getDocs","security":[],"x-access-level":"Public","responses":{"200":{"description":"Documentation"}}}},"/transaction/{txid}/events":{"get":{"tags":["Transaction"],"summary":"Get events for a transaction","description":"Returns normalized events stored in RDS for the given transaction hash.\nOffloaded category payloads (`payload_ref`) are merged into each event when the Lambda has `PAYLOAD_CHUNK_ENABLED=1`, `PAYLOAD_CHUNK_S3_BUCKET`, and S3 read permission on that bucket.\nEach event may include **address_labels**: a map of Alephium address (base58) to the primary **address_label** row for that address (`label`, optional **icon** URL, **mapped_label**, **source`), for addresses appearing on that event (`from`, `to`, `with`, `token_address`).\n","operationId":"getTxEvents","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"txid","in":"path","required":true,"description":"Transaction hash (hex)","schema":{"type":"string","example":"ba076401862824ef18b7fe436fcf99de9dea4066e91671473205df2ee34619d3"}}],"responses":{"200":{"description":"List of normalized events for the transaction","content":{"application/json":{"schema":{"type":"object","required":["transaction_id","events"],"properties":{"transaction_id":{"type":"string"},"events":{"type":"array","items":{"$ref":"#/components/schemas/NormalizedEvent"}},"meta":{"type":"object","properties":{"payload_chunk_hydration_enabled":{"type":"boolean","description":"When false, offloaded JSON was not merged (configure PAYLOAD_CHUNK_* on the Lambda)."}}}}}}}},"400":{"description":"Missing or invalid txid"},"500":{"description":"Server error"},"503":{"description":"Database not configured"}}}},"/transaction/{transaction_id}":{"get":{"tags":["Transaction"],"summary":"Get transaction by hash (decorated)","description":"Proxies `GET /transactions/{transaction_hash}` from the Alephium explorer backend and adds **alphscan** when the database is configured:\n**events** — all normalized events for this hash (same shape as GET `/transaction/{transaction_id}/events`, including per-event **address_labels** and payload hydration when enabled);\n**meta.payload_chunk_hydration_enabled** — whether offloaded JSON was merged;\noptional **address_labels** — map of address to primary label for addresses on the tx inputs/outputs and the main normalized event (same idea as decorated transaction lists).\nWhen the database is not configured, returns the raw explorer transaction JSON with no **alphscan** key.\n","operationId":"getTransactionByHash","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"transaction_id","in":"path","required":true,"description":"Transaction hash (hex)","schema":{"type":"string"}}],"responses":{"200":{"description":"Explorer transaction JSON, optionally with alphscan","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Same fields as the Alephium explorer **Transaction** object; when enriched, includes **alphscan** with full **events** and **meta**.","properties":{"alphscan":{"$ref":"#/components/schemas/TransactionDetailAlphscan"}}}}}},"400":{"description":"Missing transaction_id"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (invalid API key, plan, or origin)"},"500":{"description":"Server error"},"502":{"description":"Could not reach Alephium backend"}}}},"/block/{block_hash}":{"get":{"tags":["Blocks"],"summary":"Get block by hash (decorated)","description":"Proxies `GET /blocks/{block_hash}` from the Alephium explorer backend. When the database is configured and the block has **txNumber** greater than zero,\nfetches the block's transactions (first page, up to 100) and adds **alphscan**: **genesis_mints** lists main normalized events with category `token` and sub_kind `genesis_mint` (token mint at this block);\n**coinbases** lists main events for transactions marked `coinbase: true` on the explorer response. Values are `null` when none apply.\nWhen the database is not configured, returns the raw explorer block JSON with no **alphscan** key.\n","operationId":"getBlockByHash","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"block_hash","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Explorer block JSON, optionally with alphscan","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"alphscan":{"$ref":"#/components/schemas/BlockAlphscan"}}}}}},"400":{"description":"Missing block hash"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (invalid API key, plan, or origin)"},"500":{"description":"Server error"},"502":{"description":"Could not reach Alephium backend"}}}},"/block/{block_hash}/transactions":{"get":{"tags":["Blocks"],"summary":"List transactions in a block (decorated)","description":"Proxies `GET /blocks/{block_hash}/transactions` from the Alephium explorer backend and decorates each transaction like GET `/addresses/{address}/transactions`\n(**alphscan** always includes `main_event_pending`; when false, `dapp_id`, `category`, `sub_kind`, `type` come from the main event; optional **address_labels**). Paging `page` (default 1) and `limit` (default 20, max 100).\n","operationId":"getBlockTransactions","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"block_hash","in":"path","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","schema":{"type":"integer","default":1,"minimum":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"minimum":1,"maximum":100}}],"responses":{"200":{"description":"List of transactions, each optionally decorated with Alphscan metadata","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AlephiumTransaction"}}}}},"400":{"description":"Missing block hash"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (invalid API key, plan, or origin)"},"500":{"description":"Server error"},"502":{"description":"Could not reach Alephium backend"},"503":{"description":"Database not configured"}}}},"/events/all":{"get":{"tags":["Events"],"summary":"List or poll normalized events","description":"Returns normalized events from RDS with optional filters. Public (no API key required).\n**List:** omit `poll` or `after_id` – returns newest events first. Use `after_id` (last event id from previous page) for pagination.\n**Poll:** set `poll=1` and `after_id` to the last event id you have – returns only new events after that (for long-polling feed).\n**Filters:** dapp_id, address (from or to), token_address, category (comma-separated e.g. dex,cex), sub_kind (comma-separated e.g. buy,sell,deposit,withdraw).\n","operationId":"getEventsAll","security":[],"x-access-level":"Public","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":50},"description":"Max events to return (1–200)."},{"name":"after_id","in":"query","schema":{"type":"string"},"description":"Cursor for pagination (list) or last seen event id (poll)."},{"name":"poll","in":"query","schema":{"type":"string","enum":["0","1"]},"description":"If 1 and after_id set, return only new events after that id."},{"name":"dapp_id","in":"query","schema":{"type":"string"},"description":"Filter by dapp (e.g. elexium-dex)."},{"name":"address","in":"query","schema":{"type":"string"},"description":"Filter by from or to address."},{"name":"token_address","in":"query","schema":{"type":"string"},"description":"Filter by token address."},{"name":"category","in":"query","schema":{"type":"string"},"description":"Filter by event category (comma-separated). e.g. dex,cex,transfer."},{"name":"sub_kind","in":"query","schema":{"type":"string"},"description":"Filter by subtype (comma-separated). e.g. buy,sell,deposit,withdraw,swap."}],"responses":{"200":{"description":"List of normalized events (or new events when poll=1).","content":{"application/json":{"schema":{"type":"object","properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/NormalizedEvent"}},"poll":{"type":"boolean","description":"true when poll=1 was used"}}}}}},"500":{"description":"Server error"},"503":{"description":"Database not configured"}}}},"/series/available":{"get":{"tags":["Series"],"summary":"List available series definitions","description":"Returns the list of timeseries and list metrics supported by the indexer-series service.\nRequires a valid API key, but is **not** restricted to admin keys.\n","operationId":"getSeriesAvailable","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","responses":{"200":{"description":"Series configuration (timeseries + lists)","content":{"application/json":{"schema":{"type":"object","required":["timeseries","lists"],"properties":{"timeseries":{"type":"array","items":{"type":"object","required":["id","scales","pointKeys","chartType","dimensions"],"properties":{"id":{"type":"string","description":"Series id (e.g. token_tvl, token_price, chain_metrics)"},"scales":{"type":"array","items":{"type":"string"}},"pointKeys":{"type":"array","items":{"type":"string"}},"chartType":{"$ref":"#/components/schemas/TimeseriesChartType"},"dimensions":{"type":"array","items":{"type":"string"}}}}},"lists":{"type":"array","items":{"type":"object","required":["id","dimensions","sortKey","pageSize"],"properties":{"id":{"type":"string"},"dimensions":{"type":"array","items":{"type":"string"}},"sortKey":{"type":"string"},"pageSize":{"type":"integer"}}}}}}}}},"401":{"description":"Missing or invalid API key"},"500":{"description":"Server error"}}}},"/series/{seriesid}/instances":{"get":{"tags":["Series"],"summary":"List discovered timeseries instances for one series","description":"Rows written by indexer-series for each distinct (series_id, dimensions), e.g. DIA pair `dia_oracle_token_price` + `{ \"pair\": \"BTC/USD\" }`.\n`seriesid` is the timeseries id (path); results ordered by `last_seen_at` descending.\n","operationId":"getSeriesInstances","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"seriesid","in":"path","required":true,"schema":{"type":"string"},"description":"Timeseries id (e.g. dia_oracle_token_price)."},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":200}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Paginated list","content":{"application/json":{"schema":{"type":"object","properties":{"instances":{"type":"array","items":{"$ref":"#/components/schemas/SeriesInstanceSummary"}},"limit":{"type":"integer"},"offset":{"type":"integer"},"count":{"type":"integer"}}}}}},"401":{"description":"Missing or invalid API key"}}}},"/series/instances/{instanceid}":{"get":{"tags":["Series"],"summary":"Get one series instance","operationId":"getSeriesInstance","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"instanceid","in":"path","required":true,"schema":{"type":"string"},"description":"64-char hex id from list GET /series/{seriesid}/instances."}],"responses":{"200":{"description":"Instance metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeriesInstanceDetail"}}}},"404":{"description":"Not found"}}},"patch":{"tags":["Series"],"summary":"Patch series instance metadata (admin)","operationId":"patchSeriesInstanceMetadata","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"instanceid","in":"path","required":true,"schema":{"type":"string"},"description":"64-char hex id from list GET /series/{seriesid}/instances."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rawArchivePageDays":{"type":"integer","minimum":1,"maximum":366,"description":"Override raw scale (\"0\") archive page width for this instance."}}}}}},"responses":{"200":{"description":"Updated instance metadata","content":{"application/json":{"schema":{"type":"object","properties":{"instanceId":{"type":"string"},"metadata":{"type":"object","nullable":true}}}}}},"400":{"description":"Invalid request"},"403":{"description":"Admin only"},"404":{"description":"Not found"}}}},"/series/instances/{instanceid}/scales":{"get":{"tags":["Series"],"summary":"Allowed scales for an instance","description":"Scales come from the static series definition; optional has_data joins timeseries_segments.","operationId":"getSeriesInstanceScales","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"instanceid","in":"path","required":true,"schema":{"type":"string"}},{"name":"has_data","in":"query","schema":{"type":"string","enum":["0","1","true","false"]},"description":"When 1 or true, each scale includes hasData from timeseries_segments."}],"responses":{"200":{"description":"Scales for this series_id + dimensions","content":{"application/json":{"schema":{"type":"object","properties":{"instanceId":{"type":"string"},"seriesId":{"type":"string"},"dimensions":{"type":"object","additionalProperties":{"type":"string"}},"pendingPoints":{"type":"integer"},"scales":{"type":"array","items":{"type":"object","properties":{"scale":{"type":"string"},"hasData":{"type":"boolean"},"segmentCount":{"type":"integer"},"totalPoints":{"type":"integer","format":"int64"},"minPointTs":{"type":"integer","format":"int64","nullable":true},"maxPointTs":{"type":"integer","format":"int64","nullable":true},"pendingPoints":{"type":"integer"}}}}}}}}}}}},"/series/instances/{instanceid}/bucket":{"get":{"tags":["Series"],"summary":"Overlapping storage segments for a logical time bucket","description":"Returns segment ids and S3 keys for segments that overlap the logical OHLCV window for `bucket_start_ts`.\n`timeseriesStorage` is `segments`; `key` / `pageUrl` may be null when points live on S3 only.\n","operationId":"getSeriesInstanceBucket","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"instanceid","in":"path","required":true,"schema":{"type":"string"}},{"name":"scale","in":"query","required":true,"schema":{"type":"string"}},{"name":"bucket_start_ts","in":"query","required":true,"schema":{"type":"integer","format":"int64"},"description":"Logical bucket anchor (ms); aligned to archive window server-side."}],"responses":{"200":{"description":"Segment overlap metadata for the bucket","content":{"application/json":{"schema":{"type":"object","properties":{"instanceId":{"type":"string"},"seriesId":{"type":"string"},"scale":{"type":"string"},"bucketStartTs":{"type":"integer"},"pageStartTs":{"type":"integer"},"dimensions":{"type":"object","additionalProperties":{"type":"string"}},"bucket":{"type":"string"},"timeseriesStorage":{"type":"string","enum":["segments"]},"key":{"type":"string","nullable":true},"pageUrl":{"type":"string","nullable":true},"keyOrUrl":{"type":"string","nullable":true},"segmentIds":{"type":"array","items":{"type":"string"}},"segmentS3Keys":{"type":"array","items":{"type":"string"}}}}}}},"400":{"description":"Invalid scale or missing query params"},"403":{"description":"Admin only"}}}},"/series/instances/{instanceid}/{scale}/chart":{"get":{"tags":["Series"],"summary":"Fetch merged chart points (server-side)","description":"Merges data from **multiple** `timeseries_segments` rows (DB and/or S3) plus\n`metrics_point_buffer` for this instance and scale.\n\n**Query `key` (optional):** when set, each item is `{ t, y, kind }` with `y` = that `pointKey`. When **omitted**,\neach item is `{ t, values, kind }` with `values` containing every `pointKey` that is finite on that row.\n\n**Default:** optional window params. The API resolves the latest timestamp from segments + pending, then\nreturns the **most recent** `limit` points (default 1000, max 5000), sorted ascending by `t`. At most 128\nsegments are scanned per request (`window.truncated` if capped).\n\n**Modes:** `until_ts` + `limit` — points with `t <= until_ts`, last `limit` by time. `from_ts` + `limit` —\npoints with `t >= from_ts`, first `limit` chronologically. `from_ts` + `to_ts` (+ optional `limit`) —\nclosed range; if more than `limit` points exist, the first `limit` from `from_ts` are returned.\n\n`bucket_start_ts` is **not** supported on this route (use admin **bucket** / **bucket-data** for storage inspection).\n\nDoes not require `METRICS_BASE_URL` / browser CORS because the API reads page data server-side.\n","operationId":"getSeriesInstanceChart","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"instanceid","in":"path","required":true,"schema":{"type":"string"}},{"name":"scale","in":"path","required":true,"schema":{"type":"string"},"description":"Timeseries scale (e.g. 0, 1m, 1h, 1d). URL-encoded if needed."},{"name":"key","in":"query","required":false,"schema":{"type":"string"},"description":"Optional. Which `pointKey` to extract as `y`. Omit to return all available point keys per row in `values`."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":1000,"minimum":1,"maximum":5000},"description":"Max points returned after window filtering (window modes only)."},{"name":"until_ts","in":"query","required":false,"schema":{"type":"integer","format":"int64"},"description":"Upper bound (ms); return the last `limit` points with t <= until_ts."},{"name":"from_ts","in":"query","required":false,"schema":{"type":"integer","format":"int64"},"description":"Lower bound (ms) for `from_ts`+`limit` or `from_ts`+`to_ts` range."},{"name":"to_ts","in":"query","required":false,"schema":{"type":"integer","format":"int64"},"description":"Upper bound (ms) for range mode (use with `from_ts`)."}],"responses":{"200":{"description":"Merged chart points","content":{"application/json":{"schema":{"type":"object","required":["instanceId","seriesId","scale","chartType","points","window","audit"],"properties":{"instanceId":{"type":"string"},"seriesId":{"type":"string"},"scale":{"type":"string"},"chartType":{"$ref":"#/components/schemas/TimeseriesChartType"},"key":{"type":"string","description":"Present only when the request included `key` (single-series projection)."},"points":{"type":"array","items":{"oneOf":[{"$ref":"#/components/schemas/SeriesInstanceChartPointY"},{"$ref":"#/components/schemas/SeriesInstanceChartPointMulti"}]}},"window":{"$ref":"#/components/schemas/SeriesInstanceChartWindow"},"audit":{"$ref":"#/components/schemas/SeriesInstanceChartAudit"}}}}}},"400":{"description":"Invalid scale/key, deprecated query params, or missing path params"}}}},"/series/instances/{instanceid}/segments":{"get":{"tags":["Series"],"summary":"List storage segments for an instance and scale","operationId":"getSeriesInstanceSegments","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"instanceid","in":"path","required":true,"schema":{"type":"string"}},{"name":"scale","in":"query","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","default":100,"maximum":500}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Segment list","content":{"application/json":{"schema":{"type":"object","properties":{"instanceId":{"type":"string"},"seriesId":{"type":"string"},"scale":{"type":"string"},"dimensions":{"type":"object","additionalProperties":{"type":"string"}},"timeseriesStorage":{"type":"string","enum":["segments"]},"limit":{"type":"integer"},"offset":{"type":"integer"},"segments":{"type":"array","items":{"$ref":"#/components/schemas/SeriesInstanceSegmentRow"}}}}}}},"403":{"description":"Admin only"}}}},"/series/instances/{instanceid}/bucket-data":{"get":{"tags":["Series"],"summary":"Fetch merged points for a logical bucket (server-side)","operationId":"getSeriesInstanceBucketData","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"instanceid","in":"path","required":true,"schema":{"type":"string"}},{"name":"scale","in":"query","required":true,"schema":{"type":"string"}},{"name":"bucket_start_ts","in":"query","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Merged points for the logical bucket","content":{"application/json":{"schema":{"type":"object","properties":{"instanceId":{"type":"string"},"seriesId":{"type":"string"},"scale":{"type":"string"},"bucketStartTs":{"type":"integer","format":"int64"},"pageStartTs":{"type":"integer","format":"int64"},"dimensions":{"type":"object","additionalProperties":{"type":"string"}},"points":{"type":"array","items":{"type":"object"}}}}}}},"403":{"description":"Admin only"}}}},"/series/instances/{instanceid}/segment-data":{"get":{"tags":["Series"],"summary":"Fetch points for one storage segment (server-side)","operationId":"getSeriesInstanceSegmentData","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"instanceid","in":"path","required":true,"schema":{"type":"string"}},{"name":"scale","in":"query","required":true,"schema":{"type":"string"}},{"name":"segment_id","in":"query","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Segment points","content":{"application/json":{"schema":{"type":"object","properties":{"instanceId":{"type":"string"},"seriesId":{"type":"string"},"scale":{"type":"string"},"segmentId":{"type":"string"},"dimensions":{"type":"object","additionalProperties":{"type":"string"}},"points":{"type":"array","items":{"type":"object"}}}}}}},"403":{"description":"Admin only"},"404":{"description":"Segment not found for this instance"}}}},"/price/source/all":{"get":{"tags":["Price"],"summary":"List price sources","description":"Returns configured price sources (e.g. binance, coingecko, coinmarketcap, dia) with capabilities (spot, candles, trades) and supported denominations.","operationId":"getPriceSourceAll","security":[],"x-access-level":"Public","responses":{"200":{"description":"List of price sources","content":{"application/json":{"schema":{"type":"object","properties":{"sources":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"supportsSpot":{"type":"boolean"},"supportsCandles":{"type":"boolean"},"supportsTrades":{"type":"boolean"},"supportedDenominations":{"type":"array","items":{"type":"string"}},"enabled":{"type":"boolean"},"availableCount":{"type":"integer","description":"Number of pairs available from this source"},"watchedCount":{"type":"integer","description":"Number of pairs being watched (enabled)"}}}}}}}}},"503":{"description":"Database not configured"}}}},"/price/source/{srcid}/pair/all":{"get":{"tags":["Price"],"summary":"List configured pairs for a source","description":"Returns token_price_source rows for the given price source. Token legs and contracts are in `tokens` (token_price_map). Legacy fields `token_id`, `chain_id`, `denomination`, `token_address` are derived when possible for older clients.","operationId":"getPriceSourcePairAll","security":[],"x-access-level":"Public","parameters":[{"name":"srcid","in":"path","required":true,"schema":{"type":"string"},"description":"Price source id (e.g. mexc, gateio)."}],"responses":{"200":{"description":"Pairs configured for the source","content":{"application/json":{"schema":{"type":"object","properties":{"source_id":{"type":"string"},"pairs":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"source_id":{"type":"string"},"pair_symbol":{"type":"string"},"pair_label":{"type":"string","description":"Human-readable label (e.g. Elexium pool symbols)"},"pool_created_at":{"type":"string","format":"date-time","description":"Pool creation time when known (ISO 8601)"},"tokens":{"type":"array","description":"Token legs from token_price_map","items":{"type":"object","properties":{"id":{"type":"integer"},"token_price_source_id":{"type":"integer"},"type":{"type":"string"},"dapp":{"type":"string","nullable":true},"chain":{"type":"string"},"token_id":{"type":"string"},"token_contract":{"type":"string","nullable":true},"in_consolidated_market":{"type":"boolean"}}}},"token_id":{"type":"string","description":"Derived primary leg (backward compatibility)"},"chain":{"type":"string"},"chain_id":{"type":"integer","description":"Derived when chain is alph (8738)"},"denomination":{"type":"string","description":"Often quote token_id when inferrable"},"available":{"type":"boolean"},"enabled":{"type":"boolean"},"enable_trades":{"type":"boolean","description":"Include in trade watcher (normalized events)"},"includeInTVL":{"type":"boolean","description":"Include pair in aggregated TVL when true"},"token_address":{"type":"string","nullable":true,"description":"Derived from primary token_contract when present"},"decimals":{"type":"integer","nullable":true},"scales_meta":{"type":"object","description":"Per-scale first/last OHLCV datapoint (ms). Keys are scale (e.g. 1h, 1d); values are { first_ts, last_ts }.","additionalProperties":{"type":"object","properties":{"first_ts":{"type":"number"},"last_ts":{"type":"number"}}}}}}}}}}}},"404":{"description":"Source not found"},"503":{"description":"Database not configured"}}}},"/price/source/{srcid}/pair/available":{"get":{"tags":["Price"],"summary":"List available CEX pairs for a source","description":"Returns pairs discovered from the CEX API (populated by ingest\\:cex-available-pairs). Use with pair/add to add to watch list.","operationId":"getPriceSourcePairAvailable","security":[],"x-access-level":"Public","parameters":[{"name":"srcid","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Available pairs","content":{"application/json":{"schema":{"type":"object","properties":{"source_id":{"type":"string"},"available":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"source_id":{"type":"string"},"pair_symbol":{"type":"string"},"base_asset":{"type":"string"},"quote_asset":{"type":"string"}}}}}}}}},"503":{"description":"Database not configured"}}}},"/price/source/{srcid}/pair/add":{"post":{"tags":["Price"],"summary":"Add a pair to watch list (admin)","description":"Adds a pair to token_price_source.\n- **CEX / from list:** body must include pair_symbol or pair_id (from available list); optional token_id, chain_id.\n- **DEX by pool address:** for source uniswap or pancakeswap, body can include pair_symbol (pool contract address, 0x + 40 hex) and token_id (required); pair is added without being in the available list (for low‑TVL pools e.g. ALPH).\n","operationId":"postPriceSourcePairAdd","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"srcid","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"pair_symbol":{"type":"string"},"pair_id":{"type":"integer"},"token_id":{"type":"string"},"chain_id":{"type":"integer","default":8738}}}}}},"responses":{"200":{"description":"Pair added","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"id":{"type":"integer"},"pair_symbol":{"type":"string"}}}}}},"400":{"description":"Missing pair_symbol or pair_id; or for DEX add by address, missing token_id or invalid pool address"},"404":{"description":"Pair not in available list (CEX / from-list flow only)"},"503":{"description":"Database not configured"}}}},"/price/source/{srcid}/pair/{pairid}/update":{"post":{"tags":["Price"],"summary":"Update a configured pair (admin)","description":"Updates token_price_source row. Body may include enabled, available, enable_trades, includeInTVL (or include_in_tvl) only (token metadata is edited via pair token endpoints).","operationId":"postPriceSourcePairUpdate","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"srcid","in":"path","required":true,"schema":{"type":"string"}},{"name":"pairid","in":"path","required":true,"description":"token_price_source.id","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"available":{"type":"boolean"},"enable_trades":{"type":"boolean","description":"Include in trade watcher (generate normalized events)"},"includeInTVL":{"type":"boolean","description":"Include pair in aggregated TVL"},"include_in_tvl":{"type":"boolean","description":"Alias for includeInTVL"}}}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"id":{"type":"integer"}}}}}},"404":{"description":"Pair not found"},"503":{"description":"Database not configured"}}}},"/price/source/{srcid}/pair/{pairid}/del":{"post":{"tags":["Price"],"summary":"Remove a pair from watch list (admin)","description":"Deletes the token_price_source row.","operationId":"postPriceSourcePairDel","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"srcid","in":"path","required":true,"schema":{"type":"string"}},{"name":"pairid","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"deleted":{"type":"integer"}}}}}},"404":{"description":"Pair not found"},"503":{"description":"Database not configured"}}}},"/price/source/{srcid}/pair/{pairid}/token/all":{"get":{"tags":["Price"],"summary":"List all tokens mapped to a pair","description":"Returns token_price_map rows for the given price source pair. Use with token/update to change token mapping.","operationId":"getPriceSourcePairTokenAll","security":[],"x-access-level":"Public","parameters":[{"name":"srcid","in":"path","required":true,"schema":{"type":"string"}},{"name":"pairid","in":"path","required":true,"schema":{"type":"string"},"description":"token_price_source id (pair id)"}],"responses":{"200":{"description":"Tokens mapped to this pair","content":{"application/json":{"schema":{"type":"object","properties":{"source_id":{"type":"string"},"pair_id":{"type":"integer"},"pair_symbol":{"type":"string"},"tokens":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"token_price_source_id":{"type":"integer"},"type":{"type":"string","enum":["cex","dex","api","oracle","aggregator"]},"dapp":{"type":"string","nullable":true},"chain":{"type":"string"},"token_id":{"type":"string"},"token_contract":{"type":"string","nullable":true},"in_consolidated_market":{"type":"boolean"}}}}}}}}},"404":{"description":"Pair not found"},"503":{"description":"Database not configured"}}}},"/price/source/{srcid}/pair/{pairid}/token/update":{"post":{"tags":["Price"],"summary":"Update a token mapping for a pair (admin)","description":"Updates one token_price_map row for this pair. Body must include id (token_price_map id); optional token_id, type, dapp, chain, token_contract, in_consolidated_market.","operationId":"postPriceSourcePairTokenUpdate","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"srcid","in":"path","required":true,"schema":{"type":"string"}},{"name":"pairid","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"integer","description":"token_price_map row id"},"token_id":{"type":"string"},"type":{"type":"string","enum":["cex","dex","api","oracle","aggregator"]},"dapp":{"type":"string","nullable":true},"chain":{"type":"string"},"token_contract":{"type":"string","nullable":true},"in_consolidated_market":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"id":{"type":"integer"}}}}}},"404":{"description":"Pair or token mapping not found"},"503":{"description":"Database not configured"}}}},"/price/source/{srcid}/pair/{pairid}/token/add":{"post":{"tags":["Price"],"summary":"Add a token mapping to a pair (admin)","description":"Creates a token_price_map row for this pair. Body must include type, chain, token_id.","operationId":"postPriceSourcePairTokenAdd","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"srcid","in":"path","required":true,"schema":{"type":"string"}},{"name":"pairid","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","chain","token_id"],"properties":{"type":{"type":"string","enum":["cex","dex","api","oracle","aggregator"]},"chain":{"type":"string"},"token_id":{"type":"string"},"dapp":{"type":"string","nullable":true},"token_contract":{"type":"string","nullable":true},"in_consolidated_market":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"id":{"type":"integer","description":"token_price_map row id"}}}}}},"400":{"description":"Missing required fields or invalid body"},"404":{"description":"Pair not found"},"503":{"description":"Database not configured"}}}},"/price/source/{srcid}/pair/{pairid}/token/del":{"post":{"tags":["Price"],"summary":"Delete a token mapping for a pair (admin)","description":"Deletes one token_price_map row for this pair. Body must include id (token_price_map row id).","operationId":"postPriceSourcePairTokenDel","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"srcid","in":"path","required":true,"schema":{"type":"string"}},{"name":"pairid","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"integer","description":"token_price_map row id to delete"}}}}}},"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"deleted":{"type":"integer"}}}}}},"404":{"description":"Pair or token mapping not found"},"503":{"description":"Database not configured"}}}},"/price/pair/{pairid}/spot":{"get":{"tags":["Price"],"summary":"Get spot price for a pair","description":"Returns latest spot price for the given pair (token_price_source id). Optional query timestamp returns price at that time from OHLCV; averageWindow returns average over 1m, 5m, 15m, 1h, 4h, 1d, 1w.","operationId":"getPricePairSpot","security":[],"x-access-level":"Public","parameters":[{"name":"pairid","in":"path","required":true,"schema":{"type":"string"},"description":"token_price_source id (pair id)"},{"name":"timestamp","in":"query","schema":{"type":"integer"},"description":"Return price at this time (ms) from OHLCV."},{"name":"averageWindow","in":"query","schema":{"type":"string","enum":["1m","5m","15m","1h","4h","1d","1w"]},"description":"Return average price over this window (uses OHLCV)."},{"name":"scale","in":"query","schema":{"type":"string","default":"1h"},"description":"Candle scale when using timestamp or averageWindow."}],"responses":{"200":{"description":"Spot price (or null if no data).","content":{"application/json":{"schema":{"type":"object","properties":{"pair_id":{"type":"integer"},"pair":{"type":"string"},"source":{"type":"string"},"denomination":{"type":"string"},"token_id":{"type":"string"},"price":{"type":"number","nullable":true},"timestamp":{"type":"number"},"updated_at":{"type":"string","format":"date-time"},"from_spot_table":{"type":"boolean"}}}}}},"404":{"description":"Pair not found"},"500":{"description":"Server error"},"503":{"description":"Database not configured"}}}},"/price/pair/{pairid}/ohlcv":{"get":{"tags":["Price"],"summary":"Get OHLCV candles for a pair","description":"Returns OHLCV for the given pair (token_price_source id), merged from the table (last ~48H) and S3 archive (older). Data is returned latest-first.\nSet S3_OHLCV_BUCKET (and S3_OHLCV_PREFIX) on the API to enable S3 merge for ranges older than the table window.\nUse scale and either (page, pageSize) for latest-first paging, or (start, end, limit) for a time range.\n","operationId":"getPricePairOhlcv","security":[],"x-access-level":"Public","parameters":[{"name":"pairid","in":"path","required":true,"schema":{"type":"string"},"description":"token_price_source id (pair id)"},{"name":"scale","in":"query","schema":{"type":"string","default":"1h"},"description":"Candle interval (1m, 3m, 5m, 15m, 1h, 4h, 1d, 1w)."},{"name":"page","in":"query","schema":{"type":"integer","default":0},"description":"Page index (0 = latest candles)."},{"name":"pageSize","in":"query","schema":{"type":"integer","default":100},"description":"Candles per page (max 1000)."},{"name":"start","in":"query","schema":{"type":"integer"},"description":"Start timestamp (ms). Use with end and limit."},{"name":"end","in":"query","schema":{"type":"integer"},"description":"End timestamp (ms)."},{"name":"limit","in":"query","schema":{"type":"integer","default":100},"description":"Max points when using start/end."}],"responses":{"200":{"description":"OHLCV array","content":{"application/json":{"schema":{"type":"object","properties":{"pair_id":{"type":"integer"},"pair":{"type":"string"},"source":{"type":"string"},"denomination":{"type":"string"},"scale":{"type":"string"},"ohlcv":{"type":"array","items":{"type":"object","properties":{"t":{"type":"number"},"o":{"type":"number"},"h":{"type":"number"},"l":{"type":"number"},"c":{"type":"number"},"v":{"type":"number"}}}}}}}}},"404":{"description":"Pair not found"},"500":{"description":"Server error"},"503":{"description":"Database not configured"}}}},"/system/plans":{"get":{"tags":["Plans"],"summary":"List API plans","description":"Returns available plans with limits, throttle and price. Public endpoint.","operationId":"getSystemPlans","security":[],"x-access-level":"Public","responses":{"200":{"description":"List of plans","content":{"application/json":{"schema":{"type":"object","required":["plans"],"properties":{"plans":{"type":"array","items":{"$ref":"#/components/schemas/ApiPlan"}}}}}}}}}},"/system/keys":{"get":{"tags":["Keys"],"summary":"List API keys","description":"Returns API keys for the authenticated user. Admin can pass `user_id` to list another user's keys.","operationId":"getSystemKeys","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"user_id","in":"query","required":false,"description":"User ID (admin only). Omit to list keys for the key owner.","schema":{"type":"string"}}],"responses":{"200":{"description":"List of keys with origins","content":{"application/json":{"schema":{"type":"object","required":["keys"],"properties":{"keys":{"type":"array","items":{"$ref":"#/components/schemas/ApiKey"}}}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"}}},"post":{"tags":["Keys"],"summary":"Create API key (admin)","description":"Creates a new API key for a user. Admin only. The raw key is returned once.","operationId":"createSystemKey","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["userId","planId"],"properties":{"userId":{"type":"string","description":"Owner user ID (e.g. Telegram ID)"},"planId":{"type":"string","enum":["free","pro","enterprise"]},"level":{"type":"string","enum":["user","admin"],"default":"user"}}}}}},"responses":{"200":{"description":"Key created; raw key returned once","content":{"application/json":{"schema":{"type":"object","required":["key","keyId","key_prefix"],"properties":{"key":{"type":"string"},"keyId":{"type":"string"},"key_prefix":{"type":"string"}}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (admin only)"}}}},"/system/key/{keyid}/origin/add":{"post":{"tags":["Keys"],"summary":"Add origin to API key","description":"Appends an origin to the key's allowed_origins. Owner or admin.","operationId":"addKeyOrigin","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"keyid","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["origin"],"properties":{"origin":{"type":"string","description":"Origin to allow (e.g. https://app.example.com)"}}}}}},"responses":{"200":{"description":"Origin added"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"}}}},"/system/key/{keyid}/origin/del":{"post":{"tags":["Keys"],"summary":"Remove origin from API key","description":"Removes an origin from the key's allowed_origins. Owner or admin.","operationId":"deleteKeyOrigin","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"keyid","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["origin"],"properties":{"origin":{"type":"string"}}}}}},"responses":{"200":{"description":"Origin removed"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"}}}},"/openapi.json":{"get":{"tags":["Docs"],"summary":"OpenAPI 3.0 spec","operationId":"getOpenApiSpec","security":[],"x-access-level":"Public","responses":{"200":{"description":"JSON OpenAPI specification"}}}},"/system/key/{keyid}/plan/set":{"post":{"tags":["Keys"],"summary":"Set key plan (admin)","description":"Assign a plan to a key without payment. Admin only.","operationId":"setKeyPlan","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"keyid","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["planId"],"properties":{"planId":{"type":"string"}}}}}},"responses":{"200":{"description":"Plan updated"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (admin only)"}}}},"/system/key/{keyid}/delete":{"post":{"tags":["Keys"],"summary":"Revoke API key (admin)","description":"Revokes a key by id. Admin only.","operationId":"deleteSystemKey","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"keyid","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Key revoked"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (admin only)"}}}},"/system/key/{keyid}/update":{"post":{"tags":["Keys"],"summary":"Patch key (admin)","description":"Update key valid_until or last_payment_at. Admin only.","operationId":"patchSystemKey","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"keyid","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"valid_until":{"type":"string","format":"date-time"},"last_payment_at":{"type":"string","format":"date-time"}}}}}},"responses":{"200":{"description":"Key updated"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (admin only)"}}}},"/system/plans/upsert":{"post":{"tags":["Plans"],"summary":"Create or update plan (admin)","description":"Upsert a plan by id. Admin only.","operationId":"upsertPlan","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"plan_id":{"type":"string"},"name":{"type":"string"},"rpm":{"type":"integer"},"rpd":{"type":"integer"},"price":{"type":"string"},"price_alph":{"type":"string"},"validity_days":{"type":"integer"}}}}}},"responses":{"200":{"description":"Plan created or updated"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (admin only)"}}}},"/token/all":{"get":{"tags":["Token"],"summary":"List registered tokens (paginated)","description":"Returns registered tokens with pagination. Uses S3 when available (limited filter/sort), otherwise database.\n**Pagination:** page (default 1), pageSize (default 20). Use pageSize=-1 to return all. maxPageSize 999.\n**Filters:** chain (chain id), registered (true|false), moderation (show|hide), market_display (true|false), dapps (comma-separated), category (category id).\n**Search:** search — case-insensitive substring on token id, contract address, symbol, symbol on-chain, or name (database path only; skips S3).\n**Sort:** sort (symbol | circulating_supply_usd | mint_time), order (asc | desc). Default sort symbol, order asc.\n","operationId":"getTokenAll","security":[],"x-access-level":"Public","parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"pageSize","in":"query","description":"Page size. Use -1 to return all. Max 999.","schema":{"type":"integer","default":20}},{"name":"chain","in":"query","description":"Filter by chain id (e.g. 8738 for Alephium).","schema":{"type":"integer"}},{"name":"registered","in":"query","description":"Filter by registered status.","schema":{"type":"boolean"}},{"name":"moderation","in":"query","description":"Filter by moderation status.","schema":{"type":"string","enum":["show","hide"]}},{"name":"market_display","in":"query","description":"Filter by market_display flag.","schema":{"type":"boolean"}},{"name":"dapps","in":"query","description":"Filter by dapp(s). Comma-separated list.","schema":{"type":"string"}},{"name":"category","in":"query","description":"Filter by category id (token must have this category).","schema":{"type":"string"}},{"name":"search","in":"query","description":"Substring match on token id, contract address, symbol, symbol_onchain, or name (max 200 chars).","schema":{"type":"string","maxLength":200}},{"name":"sort","in":"query","description":"Sort field.","schema":{"type":"string","enum":["symbol","circulating_supply_usd","mint_time"],"default":"symbol"}},{"name":"order","in":"query","description":"Sort order.","schema":{"type":"string","enum":["asc","desc"],"default":"asc"}}],"responses":{"200":{"description":"Token list with pagination","content":{"application/json":{"schema":{"type":"object","properties":{"networkId":{"type":"integer"},"tokens":{"type":"array","items":{"$ref":"#/components/schemas/TokenListEntry"}},"total":{"type":"integer"},"page":{"type":"integer"},"pageSize":{"type":"integer"}}}}}}}}},"/token/filter-options":{"get":{"tags":["Token"],"summary":"Token filter options","description":"Returns chains, dapps, and categories for use in token list filters. Public.","operationId":"getTokenFilterOptions","security":[],"x-access-level":"Public","responses":{"200":{"description":"Filter options","content":{"application/json":{"schema":{"type":"object","properties":{"chains":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"short_name":{"type":"string"}}}},"dapps":{"type":"array","items":{"type":"string"}},"categories":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"sort_order":{"type":"integer"}}}}}}}}}}}},"/token/{tokenid}/details":{"get":{"tags":["Token"],"summary":"Token details","description":"Returns details for a single token plus **bridged** rows (same shape as GET /token/{tokenid}/bridged/all items). **bridged** is always present (empty array when none). For 64-char hex Alephium token ids, bridged rows are also matched by resolving the id to a group address and querying `contract_address` (e.g. Wormhole RemoteTokenPool), merged with `native_token_id` matches.","operationId":"getTokenDetails","security":[],"x-access-level":"Public","parameters":[{"name":"tokenid","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Token details","content":{"application/json":{"schema":{"type":"object","required":["token","bridged"],"properties":{"token":{"type":"object","properties":{"id":{"type":"string"},"contractAddress":{"type":"string"},"name":{"type":"string"},"symbol":{"type":"string"},"symbolOnChain":{"type":"string"},"decimals":{"type":"integer"},"categories":{"type":"array","items":{"type":"string"}},"dapp":{"type":"string"},"logoURI":{"type":"string"},"description":{"type":"string"},"originChain":{"type":"string"},"unchainedLogoURI":{"type":"string"},"maxSupply":{"type":"string"},"circulatingSupply":{"type":"string"},"burnedSupply":{"type":"string"},"lockSupply":{"type":"string"},"createdAt":{"type":"number","description":"Registry creation time (Unix ms)"},"minter":{"type":"string","description":"Minter address (deployer / first tx)"},"mintTx":{"type":"string","description":"Mint transaction hash"},"mintTime":{"type":"number","description":"On-chain mint time (Unix ms)"},"updatedAt":{"type":"number","description":"Registry last update (Unix ms)"},"registered":{"type":"boolean","description":"Whether token is registered"},"source":{"type":"string","description":"Data source"},"chainId":{"type":"integer","description":"Chain ID"},"moderation":{"type":"string","description":"show | hide"},"marketDisplay":{"type":"boolean","description":"Show in market lists"},"circulatingSupplyUsd":{"type":"number","description":"Circulating supply in USD"},"website":{"type":"string","description":"From token.metadata.website"},"metadata":{"type":"object","description":"Full token.metadata JSON"}}},"bridged":{"type":"array","description":"native_token_bridged rows for this token (same items as GET /token/{tokenid}/bridged/all).","items":{"type":"object","properties":{"id":{"type":"string","description":"Surrogate row id (BIGINT as string)"},"native_token_id":{"type":"string"},"chain_id":{"type":"integer"},"contract_address":{"type":"string"},"mapping_kind":{"type":"string","enum":["legacy_ticker_bridge","wormhole_remote_pool"]},"origin_wormhole_chain_id":{"type":"integer","nullable":true},"origin_token_id_hex":{"type":"string","nullable":true,"description":"0x-prefixed hex"},"alephium_contract_id_hex":{"type":"string","nullable":true,"description":"0x-prefixed hex"},"external_asset_id":{"type":"string","nullable":true},"origin_evm_contract_address":{"type":"string","nullable":true,"description":"EVM 0x token on origin chain when known"},"wormhole_pool_decimals":{"type":"integer","nullable":true},"origin_wormhole_chain_name":{"type":"string","nullable":true},"origin_token_explorer_url":{"type":"string","nullable":true}}}}}}}}},"404":{"description":"Token not found"}}}},"/token/{tokenid}/pairs":{"get":{"tags":["Token","Price"],"summary":"List price pairs for a token","description":"Returns all price pairs (token_price_source) that have a token mapping for this token_id, with available scales and for each scale the date range (first_ts, last_ts) of available OHLCV data.","operationId":"getTokenPairs","security":[],"x-access-level":"Public","parameters":[{"name":"tokenid","in":"path","required":true,"schema":{"type":"string"},"description":"Token id (e.g. ALPH, BTC)."},{"name":"chain","in":"query","schema":{"type":"string"},"description":"Optional chain filter (e.g. alph)."}],"responses":{"200":{"description":"Pairs with scales and date ranges","content":{"application/json":{"schema":{"type":"object","properties":{"token_id":{"type":"string"},"chain":{"type":"string","nullable":true},"pairs":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","description":"token_price_source id (pair id)"},"source_id":{"type":"string"},"pair_symbol":{"type":"string"},"pair_label":{"type":"string","description":"Human-readable pair label when set (e.g. DEX pool)"},"available":{"type":"boolean"},"enabled":{"type":"boolean"},"enable_trades":{"type":"boolean"},"includeInTVL":{"type":"boolean","description":"Include pair in aggregated TVL when true"},"available_scales":{"type":"array","items":{"type":"string"},"description":"Scale keys (e.g. 1h, 1d) with data."},"scales":{"type":"array","items":{"type":"object","properties":{"scale":{"type":"string"},"first_ts":{"type":"number","description":"First datapoint timestamp (ms)"},"last_ts":{"type":"number","description":"Last datapoint timestamp (ms)"},"date_range":{"type":"object","properties":{"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"}}}}}}}}}}}}}},"400":{"description":"Missing tokenid"},"503":{"description":"Database not configured"}}}},"/category/all":{"get":{"tags":["Category"],"summary":"List categories","description":"Returns categories (L1, DEFI, DEX, etc.) with count_token and count_dapp. Public. Add ?include_deleted=true for soft-deleted.","operationId":"getCategoryAll","security":[],"x-access-level":"Public","parameters":[{"name":"include_deleted","in":"query","schema":{"type":"boolean"},"description":"Include soft-deleted categories"}],"responses":{"200":{"description":"List of categories","content":{"application/json":{"schema":{"type":"object","required":["categories"],"properties":{"categories":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"sort_order":{"type":"integer"},"deleted":{"type":"boolean"},"count_token":{"type":"integer","description":"Number of tokens in this category"},"count_dapp":{"type":"integer","description":"Number of dapps linked to this category"}}}}}}}}}}}},"/category/add":{"post":{"tags":["Category"],"summary":"Add category (admin)","description":"Add a new category. Re-activates if previously soft-deleted. Admin only.","operationId":"addCategory","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"string"},"sort_order":{"type":"integer"}}}}}},"responses":{"200":{"description":"Category added"},"400":{"description":"id required"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (admin only)"}}}},"/category/del":{"post":{"tags":["Category"],"summary":"Soft delete category (admin)","description":"Soft-deletes a category. Admin only.","operationId":"deleteCategory","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}}}}},"responses":{"200":{"description":"Category soft-deleted"},"400":{"description":"id required"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (admin only)"}}}},"/token/{tokenid}/update":{"post":{"tags":["Token"],"summary":"Update token (admin)","description":"PATCH-style update. Only non-null fields are applied. Admin only.","operationId":"tokenUpdate","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"tokenid","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"category_ids":{"type":"array","items":{"type":"string"},"description":"Up to 3 category ids, empty to clear"},"dapp":{"type":"string","nullable":true},"decimals":{"type":"integer","nullable":true},"symbol":{"type":"string","nullable":true},"symbol_onchain":{"type":"string","nullable":true},"name":{"type":"string","nullable":true},"metadata":{"type":"object","nullable":true,"description":"Replace token.metadata JSON"},"metadata_merge":{"type":"object","description":"Shallow-merge into metadata (JSONB ||); ignored if metadata is set in the same request"},"logo_uri":{"type":"string","description":"Merge into metadata.logoURI when non-empty"},"website":{"type":"string","description":"Merge into metadata.website when non-empty"},"registered":{"type":"boolean"},"deleted":{"type":"boolean","description":"Set false to undelete"}}}}}},"responses":{"200":{"description":"Token updated"},"400":{"description":"No fields to update"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (admin only)"},"404":{"description":"Token not found"}}}},"/token/{tokenid}/del":{"post":{"tags":["Token"],"summary":"Soft delete token (admin)","description":"Sets token.deleted = true. Admin only.","operationId":"tokenDelete","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"tokenid","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Token soft-deleted"},"400":{"description":"tokenid required"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (admin only)"},"404":{"description":"Token not found"}}}},"/token/bridged/all":{"get":{"tags":["Token"],"summary":"List all bridged token mappings","description":"Returns all native_token_bridged rows. Legacy ticker→EVM rows use mapping_kind legacy_ticker_bridge; Wormhole RemoteTokenPool rows use wormhole_remote_pool (BYTEA fields as 0x hex in JSON).","operationId":"tokenBridgedAll","security":[],"x-access-level":"Public","responses":{"200":{"description":"All bridged mappings","content":{"application/json":{"schema":{"type":"object","properties":{"bridged":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Surrogate row id (BIGINT as string)"},"native_token_id":{"type":"string"},"chain_id":{"type":"integer"},"contract_address":{"type":"string"},"mapping_kind":{"type":"string","enum":["legacy_ticker_bridge","wormhole_remote_pool"]},"origin_wormhole_chain_id":{"type":"integer","nullable":true},"origin_token_id_hex":{"type":"string","nullable":true,"description":"0x-prefixed hex"},"alephium_contract_id_hex":{"type":"string","nullable":true,"description":"0x-prefixed hex"},"external_asset_id":{"type":"string","nullable":true},"origin_evm_contract_address":{"type":"string","nullable":true,"description":"EVM 0x token on origin chain when known"},"wormhole_pool_decimals":{"type":"integer","nullable":true},"origin_wormhole_chain_name":{"type":"string","nullable":true},"origin_token_explorer_url":{"type":"string","nullable":true}}}}}}}}},"503":{"description":"Database not configured"}}}},"/token/{tokenid}/bridged/all":{"get":{"tags":["Token"],"summary":"List bridged mappings for a token","description":"Returns bridged rows for native_token_id matching the path tokenid (same JSON shape as /token/bridged/all items).","operationId":"tokenBridgedByTokenAll","security":[],"x-access-level":"Public","parameters":[{"name":"tokenid","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Bridged mappings for the token","content":{"application/json":{"schema":{"type":"object","properties":{"token_id":{"type":"string"},"bridged":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"native_token_id":{"type":"string"},"chain_id":{"type":"integer"},"contract_address":{"type":"string"},"mapping_kind":{"type":"string","enum":["legacy_ticker_bridge","wormhole_remote_pool"]},"origin_wormhole_chain_id":{"type":"integer","nullable":true},"origin_token_id_hex":{"type":"string","nullable":true},"alephium_contract_id_hex":{"type":"string","nullable":true},"external_asset_id":{"type":"string","nullable":true},"origin_evm_contract_address":{"type":"string","nullable":true},"wormhole_pool_decimals":{"type":"integer","nullable":true},"origin_wormhole_chain_name":{"type":"string","nullable":true},"origin_token_explorer_url":{"type":"string","nullable":true}}}}}}}}},"503":{"description":"Database not configured"}}}},"/token/{tokenid}/bridged/add":{"post":{"tags":["Token"],"summary":"Add bridged mapping (admin)","description":"Maps this token to a contract address on a chain (e.g. bridged BTC on Alephium).","operationId":"tokenBridgedAdd","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"tokenid","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["contract_address"],"properties":{"chain_id":{"type":"integer","default":8738},"contract_address":{"type":"string"}}}}}},"responses":{"200":{"description":"Added","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"token_id":{"type":"string"},"chain_id":{"type":"integer"},"contract_address":{"type":"string"}}}}}},"400":{"description":"contract_address required"},"503":{"description":"Database not configured"}}}},"/token/{tokenid}/bridged/del":{"post":{"tags":["Token"],"summary":"Remove bridged mapping (admin)","operationId":"tokenBridgedDel","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"tokenid","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"chain_id":{"type":"integer","default":8738}}}}}},"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"deleted":{"type":"integer"}}}}}},"503":{"description":"Database not configured"}}}},"/chain/all":{"get":{"tags":["Chain"],"summary":"List chains","description":"Returns chains with pagination. page (default 1), pageSize (default 20). pageSize=-1 returns all. maxPageSize 999. Public.","operationId":"chainAll","security":[],"x-access-level":"Public","parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"pageSize","in":"query","description":"Page size. Use -1 to return all.","schema":{"type":"integer","default":20}},{"name":"include_deleted","in":"query","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Paginated list of chains","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ChainRow"}},"total":{"type":"integer"},"page":{"type":"integer"},"pageSize":{"type":"integer"}}}}}}}}},"/chain/add":{"post":{"tags":["Chain"],"summary":"Add chain from chainlist (admin)","description":"Fetches chain by chainId from chainlist API and inserts/updates. Admin only.","operationId":"chainAdd","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["chainId"],"properties":{"chainId":{"type":"integer","description":"Chain ID from chainlist.org"}}}}}},"responses":{"200":{"description":"Chain added or updated"},"400":{"description":"chainId required"},"403":{"description":"Admin only"},"404":{"description":"Chain not found in chainlist"}}}},"/chain/{chainid}/update":{"post":{"tags":["Chain"],"summary":"Update chain (admin)","description":"Update chain fields by id. Admin only.","operationId":"chainUpdate","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"chainid","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"chain":{"type":"string"},"short_name":{"type":"string"},"network_id":{"type":"integer"},"native_currency":{"type":"object"},"rpc":{"type":"array","items":{"type":"string"}},"explorers":{"type":"array"},"icon":{"type":"string"},"info_url":{"type":"string"},"slip44":{"type":"integer"},"wormhole_id":{"type":"integer","nullable":true},"avatar_url":{"type":"string","nullable":true},"evm_explorer_base_url":{"type":"string","nullable":true,"description":"HTTPS origin only, no path"}}}}}},"responses":{"200":{"description":"Chain updated"},"400":{"description":"chainid required or no fields to update"},"403":{"description":"Admin only"}}}},"/chain/{chainid}/avatar":{"post":{"tags":["Chain"],"summary":"Upload chain avatar to CDN (admin)","description":"Accepts base64 image, writes PNG to S3 media bucket, sets chain.avatar_url. Requires S3_MEDIA_BUCKET and CLOUDFRONT_BASE_URL.","operationId":"chainAvatarUpload","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"chainid","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["imageBase64"],"properties":{"imageBase64":{"type":"string","description":"Raw base64 or data URL (image/png, image/jpeg, etc.)"}}}}}},"responses":{"200":{"description":"Uploaded; returns avatar_url"},"400":{"description":"Invalid body or image"},"403":{"description":"Admin only"},"503":{"description":"S3/CDN not configured"}}}},"/chain/{chainid}/delete":{"post":{"tags":["Chain"],"summary":"Soft delete chain (admin)","description":"Sets chain.deleted = true. Admin only.","operationId":"chainDelete","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"chainid","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Chain soft-deleted"},"400":{"description":"chainid required"},"403":{"description":"Admin only"},"404":{"description":"Chain not found"}}}},"/chain/search":{"get":{"tags":["Chain"],"summary":"Search chains via chainlist API","description":"Searches chainlist.org API by name, symbol, or chain ID. Public.","operationId":"chainSearch","security":[],"x-access-level":"Public","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Search results from chainlist","content":{"application/json":{"schema":{"type":"object","properties":{"results":{"type":"array"},"total":{"type":"integer"},"page":{"type":"integer"},"perPage":{"type":"integer"}}}}}},"400":{"description":"q required"}}}},"/addresses/all":{"get":{"tags":["Addresses"],"summary":"List address labels (paginated)","description":"Returns address_label rows. page (default 1), pageSize (default 20). pageSize=-1 returns all. maxPageSize 999.","operationId":"getAddressesAll","security":[],"x-access-level":"Public","parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"pageSize","in":"query","description":"Use -1 to return all. Max 999.","schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"Paginated list","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array"},"total":{"type":"integer"},"page":{"type":"integer"},"pageSize":{"type":"integer"}}}}}}}}},"/addresses/label/all":{"get":{"tags":["Addresses"],"summary":"List address labels (paginated)","description":"Same as /addresses/all. page, pageSize (default 20), pageSize=-1 for all. maxPageSize 999.","operationId":"getAddressesLabelAll","security":[],"x-access-level":"Public","parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"pageSize","in":"query","schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"Paginated list","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array"},"total":{"type":"integer"},"page":{"type":"integer"},"pageSize":{"type":"integer"}}}}}}}}},"/contracts/all":{"get":{"tags":["Contracts"],"summary":"List contracts (paginated)","description":"Returns contract rows. page (default 1), pageSize (default 20). pageSize=-1 returns all. maxPageSize 999.\nOptional **dapp** filters by exact dapp string. **dapp_options=1** adds **dapp_options** (distinct non-empty dapp values) to the response.\nItems join **token** on contract address and may include **token_name**, **token_symbol**, **token_logo_uri**, **contract_icon** (from **contract.metadata.icon**, e.g. bridge pool token), **display_logo_uri** (coalesce: **contract_icon**, **token_logo_uri**, **dapp_logo_uri**), **token_lp_kind**, **lp_token0_logo_uri**, **lp_token1_logo_uri**, **token_metadata**. **nft_registry_*** fields and the full **display_logo_uri** chain including NFT registry apply on **/contract/{address}/children** and **/contract/{address}/details**, not on this list endpoint.\n","operationId":"getContractsAll","security":[],"x-access-level":"Public","parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"pageSize","in":"query","description":"Use -1 to return all. Max 999.","schema":{"type":"integer","default":20}},{"name":"dapp","in":"query","description":"Exact match on contract.dapp","schema":{"type":"string"}},{"name":"dapp_options","in":"query","description":"If 1 or true, response includes dapp_options array","schema":{"type":"string","enum":["1","true","0","false"]}}],"responses":{"200":{"description":"Paginated list","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array"},"total":{"type":"integer"},"page":{"type":"integer"},"pageSize":{"type":"integer"},"dapp_options":{"type":"array","items":{"type":"string"},"description":"Present when dapp_options=1"}}}}}}}}},"/contract/{address}/details":{"get":{"tags":["Contracts"],"summary":"Get one contract with fields","description":"Returns contract row and contract_fields rows for address. 404 if missing.\n**contract** may include token join fields (**token_name**, **token_symbol**, **token_logo_uri**, **contract_icon**, **display_logo_uri**, **token_lp_kind**, **lp_token0_logo_uri**, **lp_token1_logo_uri**, **token_metadata**) and optional **nft_registry_display_name** / **nft_registry_logo_uri** from **nft** / **nft_collection** when present. **display_logo_uri** prefers **contract_icon**, then **token_logo_uri**, then **nft_registry_logo_uri**, then **dapp_logo_uri** (use this for avatars when you want token/pool art over the dapp icon).\n","operationId":"getContractRecord","security":[],"x-access-level":"Public","parameters":[{"name":"address","in":"path","required":true,"description":"Contract address (Alephium address)","schema":{"type":"string"}}],"responses":{"200":{"description":"Contract and fields","content":{"application/json":{"schema":{"type":"object","properties":{"contract":{"type":"object"},"fields":{"type":"array"},"address_labels":{"$ref":"#/components/schemas/ContractAddressLabels","description":"Present when the contract address has at least one row in **address_label**."}}}}}},"400":{"description":"Missing address"},"404":{"description":"Contract not found"}}}},"/contract/{address}/children":{"get":{"tags":["Contracts"],"summary":"List child contracts (paginated)","description":"Returns contract rows whose **parent_address** equals **address** (path).\npage (default 1), pageSize (default 15). pageSize=-1 returns all. maxPageSize 999.\nItems may include **token_name**, **token_symbol**, **token_logo_uri**, **contract_icon**, **display_logo_uri** when the child address matches a row in **token** or has **contract.metadata.icon**, and **nft_registry_display_name** / **nft_registry_logo_uri** when the child exists in **nft** or **nft_collection** (no extra queries). **display_logo_uri** prefers **contract_icon**, then **token_logo_uri**, then **nft_registry_logo_uri**, then **dapp_logo_uri**.\n","operationId":"getContractChildren","security":[],"x-access-level":"Public","parameters":[{"name":"address","in":"path","required":true,"description":"Parent contract address (Alephium address)","schema":{"type":"string"}},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"pageSize","in":"query","description":"Use -1 to return all. Max 999.","schema":{"type":"integer","default":15}}],"responses":{"200":{"description":"Paginated child contracts","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array"},"total":{"type":"integer"},"page":{"type":"integer"},"pageSize":{"type":"integer"}}}}}},"400":{"description":"Missing parent address"}}}},"/contract/{address}/recompute-n-childs":{"post":{"tags":["Contracts"],"summary":"Recompute stored child count (admin)","description":"Sets **contract.n_childs** for **address** to `COUNT(*)` of rows with **parent_address** = **address**.\nRequires admin API key.\n","operationId":"postContractRecomputeNChilds","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"address","in":"path","required":true,"description":"Parent contract address","schema":{"type":"string"}}],"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"type":"object","properties":{"address":{"type":"string"},"n_childs":{"type":"integer"}}}}}},"403":{"description":"Not admin"},"404":{"description":"No contract row for address"}}}},"/nft/collection/all":{"get":{"tags":["NFT"],"summary":"List NFT collections (paginated)","description":"Returns rows from **nft_collection**. **Pagination:** page (default 1), pageSize (default 20), pageSize=-1 returns all (max 999).\nOptional **dapp** filters by originating dapp id (e.g. elexium-dex).\n","operationId":"getNftCollectionAll","security":[],"x-access-level":"Public","parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"pageSize","in":"query","description":"Use -1 to return all. Max 999.","schema":{"type":"integer","default":20}},{"name":"dapp","in":"query","description":"Filter by dapp id (matches `nft_collection.dapp`)","schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated NFT collections","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/NftCollectionRow"}},"total":{"type":"integer"},"page":{"type":"integer"},"pageSize":{"type":"integer"}}}}}}}}},"/nft/collection/{address}/details":{"get":{"tags":["NFT"],"summary":"Get one NFT collection by collection contract address","description":"Returns a single **nft_collection** row (including `dapp` when set). 404 if missing.","operationId":"getNftCollectionDetails","security":[],"x-access-level":"Public","parameters":[{"name":"address","in":"path","required":true,"description":"Collection contract address (Alephium)","schema":{"type":"string"}}],"responses":{"200":{"description":"Collection row","content":{"application/json":{"schema":{"type":"object","properties":{"collection":{"$ref":"#/components/schemas/NftCollectionRow"},"trait_definitions":{"type":"array","description":"Trait names from **nft_collection_trait** (catalog; per-NFT values are on GET /nft/{address}/details).","items":{"$ref":"#/components/schemas/NftCollectionTraitDefRow"}}}}}}},"404":{"description":"Not found"}}}},"/nft/collection/{address}/update":{"post":{"tags":["NFT"],"summary":"Update NFT collection row (admin)","description":"Patches **nft_collection** display, registry, and moderation fields.","operationId":"postNftCollectionUpdate","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"address","in":"path","required":true,"description":"Collection contract address","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"dapp":{"type":"string","nullable":true},"display_name":{"type":"string","nullable":true},"display_description":{"type":"string","nullable":true},"display_image":{"type":"string","nullable":true},"registered":{"type":"boolean"},"prefer_resolved_over_state":{"type":"boolean"},"moderation":{"type":"string","enum":["show","hide"]},"registration_meta":{"type":"object","nullable":true},"registration_meta_merge":{"type":"object"},"moderation_meta":{"type":"object","nullable":true}}}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"collection_address":{"type":"string"}}}}}},"403":{"description":"Admin only"},"404":{"description":"Not found"}}}},"/nft/all":{"get":{"tags":["NFT"],"summary":"List NFTs (paginated)","description":"Returns **nft** rows joined with collection display fields. Optional **collection** query filters by collection contract address.\nOptional **dapp** filters by originating dapp id (e.g. elexium-dex).\nEach item includes provenance (`mint_time`, `mint_tx`, `minter_address`), logical owner (`owner_address`), and optional custody (`holding_contract_address` when staked or in marketplace escrow).\n","operationId":"getNftAll","security":[],"x-access-level":"Public","parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"pageSize","in":"query","description":"Use -1 to return all. Max 999.","schema":{"type":"integer","default":20}},{"name":"collection","in":"query","description":"Filter by collection contract address","schema":{"type":"string"}},{"name":"dapp","in":"query","description":"Filter by dapp id (matches `nft.dapp`)","schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated NFTs","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/NftRow"}},"total":{"type":"integer"},"page":{"type":"integer"},"pageSize":{"type":"integer"}}}}}}}}},"/nft/{address}/details":{"get":{"tags":["NFT"],"summary":"Get one NFT by NFT contract address","description":"Returns a single **nft** row (with collection join fields). Path **address** is the NFT sub-contract address.\nIncludes mint provenance and `owner_address` / `holding_contract_address` when populated.\n","operationId":"getNftDetails","security":[],"x-access-level":"Public","parameters":[{"name":"address","in":"path","required":true,"description":"NFT contract address (Alephium)","schema":{"type":"string"}}],"responses":{"200":{"description":"NFT row","content":{"application/json":{"schema":{"type":"object","properties":{"nft":{"$ref":"#/components/schemas/NftRow"},"traits":{"type":"array","description":"Per-NFT trait values from **nft_trait** (ordered by collection display_order).","items":{"$ref":"#/components/schemas/NftTraitValueRow"}}}}}}},"404":{"description":"Not found"}}}},"/nft/{address}/update":{"post":{"tags":["NFT"],"summary":"Update NFT row (admin)","description":"Patches **nft** display, registry, moderation, and optional **owner_address** (e.g. curator correction).","operationId":"postNftUpdate","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"address","in":"path","required":true,"description":"NFT contract address","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"dapp":{"type":"string","nullable":true},"display_name":{"type":"string","nullable":true},"display_description":{"type":"string","nullable":true},"display_image":{"type":"string","nullable":true},"owner_address":{"type":"string","nullable":true},"registered":{"type":"boolean"},"prefer_resolved_over_state":{"type":"boolean"},"moderation":{"type":"string","enum":["show","hide"]},"registration_meta":{"type":"object","nullable":true},"registration_meta_merge":{"type":"object"},"moderation_meta":{"type":"object","nullable":true}}}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"nft_contract_address":{"type":"string"}}}}}},"403":{"description":"Admin only"},"404":{"description":"Not found"}}}},"/dapp/{dappid}/details":{"get":{"tags":["Dapps"],"summary":"Dapp details","description":"Returns the full dapp record (same fields as items in `/dapp/all`) plus:\n- **tokens**: list of tokens whose `dapp` field matches this dapp (up to 200, ordered by symbol)\n- **contracts**: list of contract addresses registered under this dapp (up to 500, ordered by address)\n","operationId":"getDappDetails","security":[],"x-access-level":"Public","parameters":[{"name":"dappid","in":"path","required":true,"description":"Dapp slug (e.g. `elexium-dex`, `wormhole`)","schema":{"type":"string"}}],"responses":{"200":{"description":"Dapp details with associated tokens and contracts","content":{"application/json":{"schema":{"type":"object","required":["dapp","tokens","contracts"],"properties":{"dapp":{"$ref":"#/components/schemas/DappEntry"},"tokens":{"type":"array","description":"Tokens associated with this dapp (up to 200)","items":{"type":"object","properties":{"token_id":{"type":"string"},"symbol":{"type":"string"},"name":{"type":"string"}}}},"contracts":{"type":"array","description":"Contracts registered under this dapp (up to 500)","items":{"type":"object","properties":{"address":{"type":"string"},"name":{"type":"string"}}}}}}}}},"400":{"description":"Missing dappid"},"404":{"description":"Dapp not found"},"500":{"description":"Server error"}}}},"/dapp/all":{"get":{"tags":["Dapps"],"summary":"List dapps (paginated)","description":"Returns dapp rows with category_ids (up to 3 per dapp). Public.\n**Pagination:** page (default 1), pageSize (default 20). Use pageSize=-1 to return all. maxPageSize 999.\n","operationId":"getDappsAll","security":[],"x-access-level":"Public","parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"pageSize","in":"query","description":"Page size. Use -1 to return all. Max 999.","schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"Paginated list of dapps","content":{"application/json":{"schema":{"type":"object","required":["items","total","page","pageSize"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/DappEntry"}},"total":{"type":"integer"},"page":{"type":"integer"},"pageSize":{"type":"integer"}}}}}}}}},"/dapp/add":{"post":{"tags":["Dapps"],"summary":"Add dapp (admin)","description":"Create or upsert a dapp. Admin only. On conflict (dapp_id), updates name/short_name/icon/link/description.","operationId":"addDapp","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["dapp_id"],"properties":{"dapp_id":{"type":"string","description":"Unique dapp identifier"},"name":{"type":"string"},"short_name":{"type":"string","description":"Optional compact label for explorer lists"},"icon":{"type":"string","description":"Icon URL"},"link":{"type":"string","description":"Dapp URL"},"description":{"type":"string"},"metadata":{"type":"object","description":"Merged into dapp.metadata on upsert (JSONB ||) when column exists"}}}}}},"responses":{"200":{"description":"Dapp added or updated","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"dapp_id":{"type":"string"}}}}}},"400":{"description":"dapp_id required"},"403":{"description":"Admin only"}}}},"/dapp/{dappid}/del":{"post":{"tags":["Dapps"],"summary":"Delete dapp (admin)","description":"Permanently delete a dapp and its category links. Admin only.","operationId":"deleteDapp","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"dappid","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Dapp deleted","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"deleted":{"type":"boolean"}}}}}},"400":{"description":"dappid required"},"403":{"description":"Admin only"}}}},"/dapp/{dappid}/update":{"post":{"tags":["Dapps"],"summary":"Update dapp (admin)","description":"PATCH-style update. Only provided fields are updated. Admin only.","operationId":"updateDapp","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"dappid","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"short_name":{"type":"string","description":"Optional compact label for explorer lists"},"icon":{"type":"string"},"link":{"type":"string"},"description":{"type":"string"},"metadata":{"type":"object","description":"Merged into dapp.metadata (JSONB ||) when column exists"}}}}}},"responses":{"200":{"description":"Dapp updated","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"dapp_id":{"type":"string"}}}}}},"400":{"description":"dapp_id required"},"403":{"description":"Admin only"}}}},"/dapp/{dappid}/category/add":{"post":{"tags":["Dapps"],"summary":"Link category to dapp (admin)","description":"Add a category link to a dapp. Max 3 categories per dapp. Category must exist (see Category). Admin only.","operationId":"addDappCategory","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"dappid","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["category_id"],"properties":{"category_id":{"type":"string"},"sort_order":{"type":"integer","default":0}}}}}},"responses":{"200":{"description":"Link added","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"dapp_id":{"type":"string"},"category_id":{"type":"string"}}}}}},"400":{"description":"dapp_id and category_id required","or already 3 categories":null},"403":{"description":"Admin only"}}}},"/dapp/{dappid}/category/del":{"post":{"tags":["Dapps"],"summary":"Unlink category from dapp (admin)","description":"Remove a category link from a dapp. Admin only.","operationId":"deleteDappCategory","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"dappid","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["category_id"],"properties":{"category_id":{"type":"string"}}}}}},"responses":{"200":{"description":"Link removed","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"deleted":{"type":"boolean"}}}}}},"400":{"description":"dapp_id and category_id required"},"403":{"description":"Admin only"}}}},"/dapp/furnace/burns/token/{tokenId}":{"get":{"tags":["dapps:furnace"],"summary":"Furnace burns by token","description":"Returns all burn events (ALPH and token burns) for the given token across all Furnace contracts.\nResults are ordered newest-first. Cursor-based pagination via `nextKey`.\n","operationId":"getFurnaceBurnsByToken","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"tokenId","in":"path","required":true,"description":"Token contract id (hex) or `ALPH`","schema":{"type":"string"}},{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"Paginated list of burn events for the token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DappPagedResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Query failed"}}}},"/dapp/furnace/burns/wallet/{walletId}":{"get":{"tags":["dapps:furnace"],"summary":"Furnace burns by wallet","description":"Returns all burn events from Furnace attributed to the given wallet address.\nResults are ordered newest-first. Cursor-based pagination via `nextKey`.\n","operationId":"getFurnaceBurnsByWallet","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"walletId","in":"path","required":true,"description":"Alephium wallet address (base58)","schema":{"type":"string"}},{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"Paginated list of burn events for the wallet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DappPagedResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Query failed"}}}},"/dapp/chainreaction/plays/token/{tokenId}":{"get":{"tags":["dapps:chainreaction"],"summary":"ChainReaction plays by token","description":"Returns all `PlayerJoined` and `ChainEnded` events for games played with the given token.\nResults are ordered newest-first. Cursor-based pagination via `nextKey`.\n","operationId":"getChainreactionPlaysByToken","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"tokenId","in":"path","required":true,"description":"Token contract id (hex)","schema":{"type":"string"}},{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"Paginated list of play events for the token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DappPagedResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Query failed"}}}},"/dapp/chainreaction/plays/wallet/{walletId}":{"get":{"tags":["dapps:chainreaction"],"summary":"ChainReaction plays by wallet","description":"Returns all `PlayerJoined` and `ChainEnded` events for games involving the given wallet.\nResults are ordered newest-first. Cursor-based pagination via `nextKey`.\n","operationId":"getChainreactionPlaysByWallet","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"walletId","in":"path","required":true,"description":"Alephium wallet address (base58)","schema":{"type":"string"}},{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"Paginated list of play events for the wallet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DappPagedResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Query failed"}}}},"/dapp/elexium/ex/summary":{"get":{"tags":["dapps:elexium"],"summary":"EX token summary (price, supply, market cap, pool/lock counts)","description":"Returns a snapshot of key EX token metrics. When S3 caching is configured, this\nendpoint is served from a pre-computed JSON file pushed by the watcher (O(1), no\nDynamoDB scans). Falls back to live computation when no cache is available.\n\nThe response includes:\n- `price` / `priceAlph` — latest daily OHLC for EX/USD and EX/ALPH\n- `circulatingSupply` — from the latest `Minter.Mint` event (raw 18-decimal string)\n- `marketCap` — `price.close × circulatingSupply / 1e18` (decimal string)\n- `poolCount`, `veNftCount` — DEX pool and veNFT counts\n- `exInPools` — EX locked across all DEX liquidity pools\n- `exLockedVeNft` — net EX locked in VotingEscrow positions\n- `exBurned` — cumulative EX burned (furnace + chainreaction + early veNFT exits)\n- `exByWallet` — labeled wallet EX balances (treasury, team, etc.)\n\n**Note:** TVL in USD is not included. Use `GET /dapp/elexium/ex/pools/tvl` for raw reserves.\n","operationId":"getElexiumExSummary","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","responses":{"200":{"description":"EX token summary snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExSummary"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}}}},"/dapp/elexium/ex/price":{"get":{"tags":["dapps:elexium"],"summary":"Latest EX token price","description":"Returns the most recent daily OHLC item for the EX token. Equivalent to\n`GET /dapp/elexium/dex/ex/price` — provided as a cleaner top-level path.\n","operationId":"getElexiumExPriceLatest","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","responses":{"200":{"description":"Most recent daily EX price OHLC","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExDailyOhlc"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"No price data available yet"}}}},"/dapp/elexium/ex/price/history":{"get":{"tags":["dapps:elexium"],"summary":"EX token daily price history","description":"Returns paginated daily OHLC history for the EX token, most-recent day first.\nEquivalent to `GET /dapp/elexium/dex/ex/price/history` — provided as a cleaner top-level path.\n","operationId":"getElexiumExPriceHistoryV2","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"Paginated daily OHLC history","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","example":"EX"},"items":{"type":"array","items":{"$ref":"#/components/schemas/ExDailyOhlc"}},"nextKey":{"type":"string","nullable":true}}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"}}}},"/dapp/elexium/ex/price/day/{date}":{"get":{"tags":["dapps:elexium"],"summary":"EX token price for a specific day","description":"O(1) `GetItem` fetch of the EX daily OHLC for the given calendar day.\nEquivalent to `GET /dapp/elexium/dex/ex/price/day/{date}`.\n","operationId":"getElexiumExPriceDayV2","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"date","in":"path","required":true,"description":"Calendar day in `YYYY-MM-DD` format.","schema":{"type":"string","example":"2024-11-15"}}],"responses":{"200":{"description":"Daily OHLC item for the given date","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExDailyOhlc"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"No data for that date"}}}},"/dapp/elexium/ex/pools/tvl":{"get":{"tags":["dapps:elexium"],"summary":"EX protocol TVL snapshot (pool reserves)","description":"Returns the current TVL snapshot derived from all DEX pool reserves stored in\n`alphscan-elexium-pools`. Reserves are in raw 18-decimal token units — convert\nto USD using token prices from the DIA oracle or `GET /dapp/elexium/dex/ex/price`.\n\nPools are grouped into `stable` and `volatile` categories.\n\n**Note:** Historical TVL timeseries is not yet available. Only the latest reserve\nvalues (overwritten on each on-chain `Sync` event) are stored in DynamoDB. A watcher\nextension writing daily snapshots to a separate table is required for history.\n","operationId":"getElexiumExTvl","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","responses":{"200":{"description":"Current TVL snapshot from pool reserves","content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string","description":"Informational note about data limitations"},"totalPools":{"type":"integer","description":"Total number of pools"},"stablePoolCount":{"type":"integer","description":"Number of stable pools"},"volatilePoolCount":{"type":"integer","description":"Number of volatile pools"},"pools":{"type":"array","items":{"type":"object","properties":{"pairAddress":{"type":"string","description":"Pair contract address (base58)"},"token0":{"type":"string","description":"token0 contract ID (hex); all-zeros = native ALPH"},"token1":{"type":"string","description":"token1 contract ID (hex)"},"stable":{"type":"boolean","description":"Whether this is a stable (Curve-style) pool"},"reserve0":{"type":"string","description":"Latest reserve of token0 (raw 18-decimal units)"},"reserve1":{"type":"string","description":"Latest reserve of token1 (raw 18-decimal units)"},"lastSyncTimestamp":{"type":"integer","description":"Unix timestamp (ms) of the last Sync event"}}}}}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}}}},"/dapp/elexium/ex/burns":{"get":{"tags":["dapps:elexium"],"summary":"EX token burn events (raw, paginated)","description":"Returns individual EX token burn events indexed from Furnace, Chainreaction, and\nveNFT early-exit contracts. Results are sorted newest-first.\n\nFilter by wallet address with `?wallet=<address>` and/or by source with `?source=<name>`.\nCursor-based pagination via `nextKey`.\n","operationId":"getElexiumExBurns","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"},{"name":"wallet","in":"query","description":"Filter burn events by originating wallet address.","schema":{"type":"string"}},{"name":"source","in":"query","description":"Filter burn events by source contract.","schema":{"type":"string","enum":["furnace","chainreaction","elexium-venft"]}}],"responses":{"200":{"description":"Paginated list of EX burn events","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"eventKey":{"type":"string"},"tokenId":{"type":"string"},"amount":{"type":"string","description":"Raw token amount (18 decimals)"},"source":{"type":"string","enum":["furnace","chainreaction","elexium-venft"]},"wallet":{"type":"string"},"timestamp":{"type":"integer","description":"Event timestamp (ms)"}}}},"source":{"type":"string","nullable":true,"description":"Active source filter (echoed back when ?source= was provided)"},"nextKey":{"type":"string","nullable":true},"totalBurned":{"type":"string","nullable":true,"description":"Cumulative total EX burned across all sources (from stats row)"}}}}}},"400":{"description":"Invalid source value"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"}}}},"/dapp/elexium/ex/burns/history":{"get":{"tags":["dapps:elexium"],"summary":"EX token daily burn history (aggregated)","description":"Returns daily aggregated EX burn totals broken down by source\n(`furnace`, `chainreaction`, `elexium-venft`), sorted newest-first.\n\nResults are served from an S3 cache populated by the Elexium watcher (Phase F).\nFalls back to a live DynamoDB scan on cache miss.\n\nCursor-based pagination via `nextKey` (default page size 1000 — typically returns\nthe full history in a single request).\n","operationId":"getElexiumExBurnsHistory","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"Daily burn aggregates","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["date","total","bySource"],"properties":{"date":{"type":"string","description":"UTC calendar day (YYYY-MM-DD)","example":"2025-06-17"},"total":{"type":"string","description":"Total EX burned that day (raw, 18 decimals)"},"bySource":{"type":"object","description":"Per-source breakdown (raw amounts, 18 decimals)","properties":{"furnace":{"type":"string"},"chainreaction":{"type":"string"},"elexium-venft":{"type":"string"}}}}}},"itemsWithoutDate":{"type":"integer","description":"Number of burn events with no recoverable timestamp (excluded from daily totals)"},"nextKey":{"type":"string","nullable":true},"updatedAt":{"type":"integer","description":"Unix ms timestamp of when the S3 cache was last written","nullable":true}}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"}}}},"/dapp/elexium/ex/supply/history":{"get":{"tags":["dapps:elexium"],"summary":"EX token daily supply snapshots (history)","description":"Returns paginated daily supply snapshots, newest first. Each row is computed once\nper day by Phase F of the Elexium watcher and includes circulating supply, EX locked\nin pools and veNFT, cumulative burns, labeled wallet balances, and pool/veNFT counts.\n\nResults are served from an S3 cache populated by the Elexium watcher (Phase F).\nFalls back to a live DynamoDB scan on cache miss.\n\nCursor-based pagination via `nextKey` (default page size 1000).\n","operationId":"getElexiumExSupplyHistory","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"Paginated list of daily supply snapshots","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ExSupplyDay"}},"nextKey":{"type":"string","nullable":true}}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"}}}},"/dapp/elexium/ex/supply/day/{date}":{"get":{"tags":["dapps:elexium"],"summary":"EX token supply snapshot for a specific day","description":"O(1) `GetItem` fetch of the daily supply snapshot for the given calendar day.\n","operationId":"getElexiumExSupplyDay","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"date","in":"path","required":true,"description":"Calendar day in `YYYY-MM-DD` format.","schema":{"type":"string","example":"2025-06-17"}}],"responses":{"200":{"description":"Daily supply snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExSupplyDay"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"No snapshot for that date"}}}},"/dapp/elexium/ex/mints":{"get":{"tags":["dapps:elexium"],"summary":"EX token mints","description":"Returns all `Mint` events from the Elexium Minter contract (weekly EX emissions).\nResults are ordered newest-first. Cursor-based pagination via `nextKey`.\n","operationId":"getElexiumMints","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"Paginated list of EX mint events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DappPagedResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Query failed"}}}},"/dapp/elexium/epochs":{"get":{"tags":["dapps:elexium"],"summary":"EX emission epochs","description":"Returns pre-computed weekly EX emission epoch summaries with actual on-chain dates,\nsummed emissions, circulating supply, and aggregated vote stats.\n\nData is served from an S3 cache (`{prefix}/epochs/all.json`) updated by the Elexium\nwatcher Phase G after each run. Falls back to a DynamoDB scan of the\n`alphscan-elexium-epochs` table (~85 rows) on cache miss.\n\nUse `pnpm run build:epochs` to bootstrap or force a full rebuild without re-indexing.\n\n- `sumEmissions` — **sum** of all `weekly` values across all Mint events for the epoch\n- `totalSupply` — max `circulatingSupply` across Mint events for the epoch\n- `dateStart`/`dateEnd` — derived from actual `blockTimestamp` of events (not formula)\n- `voteCount` — number of `Voted` events for the epoch\n- `totalVotingPower` — sum of all vote weights (raw 18-decimal string)\n\nSorted newest first by default (`?order=desc`). Pass `?order=asc` for oldest first.\n","operationId":"getElexiumEpochs","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"},{"name":"order","in":"query","required":false,"description":"Sort order — `desc` (newest first, default) or `asc` (oldest first).","schema":{"type":"string","enum":["desc","asc"],"default":"desc"}}],"responses":{"200":{"description":"Paginated list of epoch summaries","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ElexiumEpoch"}},"total":{"type":"integer","description":"Total number of epochs available"},"nextKey":{"type":"string","nullable":true},"updatedAt":{"type":"integer","nullable":true,"description":"Unix ms timestamp of when the S3 cache was last written"}}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Query failed"}}}},"/dapp/elexium/epochs/{epochNum}":{"get":{"tags":["dapps:elexium"],"summary":"Single epoch detail","description":"Returns the pre-computed epoch summary for a given epoch number (S3-first, DynamoDB fallback).\n","operationId":"getElexiumEpoch","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"epochNum","in":"path","required":true,"description":"Epoch number (positive integer).","schema":{"type":"integer","minimum":1,"example":5}}],"responses":{"200":{"description":"Epoch summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ElexiumEpoch"}}}},"400":{"description":"Invalid epoch number"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Epoch not found"},"500":{"description":"Query failed"}}}},"/dapp/elexium/staking/rewards":{"get":{"tags":["dapps:elexium"],"summary":"All staking reward events","description":"Returns all `DistributeReward` events from the Voter contract and `Harvest` events from\nall Gauge contracts. Results are ordered newest-first. Cursor-based pagination via `nextKey`.\n","operationId":"getElexiumRewards","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"Paginated list of reward events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DappPagedResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Query failed"}}}},"/dapp/elexium/staking/rewards/wallet/{address}":{"get":{"tags":["dapps:elexium"],"summary":"Staking rewards by wallet","description":"Returns `DistributeReward` and `Harvest` reward events attributed to the given wallet address.\nResults are ordered newest-first. Cursor-based pagination via `nextKey`.\n","operationId":"getElexiumRewardsByWallet","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"address","in":"path","required":true,"description":"Alephium wallet address (base58)","schema":{"type":"string"}},{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"Paginated list of reward events for the wallet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DappPagedResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Query failed"}}}},"/dapp/elexium/votes/voter/{address}":{"get":{"tags":["dapps:elexium"],"summary":"Votes cast by a voter address","description":"Returns all `Voted` events from the Voter contract cast by the given address.\nResults are ordered newest-first. Cursor-based pagination via `nextKey`.\n","operationId":"getElexiumVotesByVoter","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"address","in":"path","required":true,"description":"Voter wallet address (base58)","schema":{"type":"string"}},{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"Paginated list of vote events for the voter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DappPagedResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Query failed"}}}},"/dapp/elexium/votes/pool/{address}":{"get":{"tags":["dapps:elexium"],"summary":"Votes for a pool address","description":"Returns all `Voted` events for the given pool (gauge) contract address.\nResults are ordered newest-first. Cursor-based pagination via `nextKey`.\n","operationId":"getElexiumVotesByPool","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"address","in":"path","required":true,"description":"Pool (gauge) contract address (base58)","schema":{"type":"string"}},{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"Paginated list of vote events for the pool","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DappPagedResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Query failed"}}}},"/dapp/elexium/votes/epoch/{epochId}":{"get":{"tags":["dapps:elexium"],"summary":"Votes for an epoch","description":"Returns all `Voted` events that occurred during the given epoch (weekly index, integer).\nResults are ordered newest-first. Cursor-based pagination via `nextKey`.\n","operationId":"getElexiumVotesByEpoch","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"epochId","in":"path","required":true,"description":"Epoch number (integer, weeks since Unix epoch)","schema":{"type":"integer"}},{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"Paginated list of vote events for the epoch","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DappPagedResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Query failed"}}}},"/dapp/elexium/votes/epoch/{epochId}/pools":{"get":{"tags":["dapps:elexium"],"summary":"Final vote distribution per epoch","description":"Returns the aggregated reward distribution across all voted gauge/pool pairs for a\ngiven epoch. Each pool's `votePercent` is computed as its share of the total\n`DistributeReward` amount emitted by the Voter contract for that epoch, which is\ndirectly proportional to the votes it received.\n\nResults are sorted by `votePercent` descending (highest-voted pool first).\nNo pagination — typically fewer than 20 active gauges per epoch.\n","operationId":"getElexiumEpochVotePools","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"epochId","in":"path","required":true,"description":"Epoch number (integer, 1-indexed from 2024-10-31)","schema":{"type":"integer"}}],"responses":{"200":{"description":"Aggregated vote distribution for the epoch","content":{"application/json":{"schema":{"type":"object","properties":{"epoch":{"type":"integer","description":"The epoch number"},"totalAmount":{"type":"string","description":"Total reward distributed across all pools (raw token amount as string)"},"pools":{"type":"array","items":{"type":"object","properties":{"gaugeId":{"type":"string","description":"Gauge contract ID (hex ByteVec)"},"amount":{"type":"string","description":"Reward amount distributed to this gauge (raw token amount as string)"},"votePercent":{"type":"number","format":"float","description":"Percentage of total epoch votes this gauge received (2 decimal places)"},"blockTimestamp":{"type":"integer","description":"Unix timestamp (ms) of the distribution transaction"}}}}}}}}},"400":{"description":"Invalid epoch — must be an integer"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Query failed"}}}},"/dapp/elexium/votes/venft/{tokenId}":{"get":{"tags":["dapps:elexium"],"summary":"Votes cast by a specific veNFT","description":"Returns all `Voted` events from the Voter contract that were cast using the given\nveNFT token ID, sorted newest-first.\n\nThe `Voted(voter, tokenId, weight)` event stores the `veNftTokenId` (U256) alongside the\nvoter wallet address. This endpoint filters by `veNftTokenId` across all vote records.\n\n**Implementation note:** The underlying DynamoDB table is keyed by `voterAddress`, not by\n`veNftTokenId`. The query uses a full table scan with a filter expression. A GSI on\n`veNftTokenId` may be added in a future version for improved scalability.\n\nPagination uses an offset-based cursor encoded in `nextKey` (base64 JSON).\nThe `total` field returns the count of all matching votes.\n","operationId":"getElexiumVotesByVenft","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"tokenId","in":"path","required":true,"description":"veNFT token ID (U256 as string).","schema":{"type":"string"}},{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"Paginated list of vote events cast by the veNFT","content":{"application/json":{"schema":{"type":"object","properties":{"veNftTokenId":{"type":"string","description":"The queried veNFT token ID"},"total":{"type":"integer","description":"Total number of vote events found for this veNFT"},"items":{"type":"array","items":{"type":"object","properties":{"voterAddress":{"type":"string","description":"Wallet address that cast the vote"},"veNftTokenId":{"type":"string","description":"veNFT token ID used to vote (U256 as string)"},"weight":{"type":"string","description":"Vote weight (raw token units as string)"},"epoch":{"type":"integer","description":"Weekly epoch number in which the vote was cast"},"blockTimestamp":{"type":"integer","description":"Unix timestamp (ms) of the vote transaction"},"txId":{"type":"string","description":"Transaction ID of the vote"},"eventKey":{"type":"string","description":"Internal event key (contractAddress:eventIndex:txId)"}}}},"pageSize":{"type":"integer"},"nextKey":{"type":"string","nullable":true}}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Query failed"}}}},"/dapp/elexium/venft":{"get":{"tags":["dapps:elexium"],"summary":"List all veNFTs","description":"Returns a paginated list of all veNFTs ever minted via `CREATE_LOCK` (depositType=1)\nevents from the `VotingEscrowCollection` contract, sorted newest-first.\n\nEach item represents the initial lock creation for one unique veNFT. This is a\n**mint registry** — it does not reflect subsequent `INCREASE_LOCK_AMOUNT`,\n`INCREASE_UNLOCK_TIME`, or `Withdraw` events. For the full deposit/withdraw history\nof a specific veNFT, call `GET /dapp/elexium/venft/{tokenId}/history`.\n\nPagination uses an offset-based cursor encoded in `nextKey` (base64 JSON).\nThe `total` field returns the count of all CREATE_LOCK events across all pages.\n","operationId":"getElexiumVenftList","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"Paginated list of all veNFT mint events","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"integer","description":"Total number of veNFTs minted"},"items":{"type":"array","items":{"$ref":"#/components/schemas/VenftLockEvent"}},"pageSize":{"type":"integer"},"nextKey":{"type":"string","nullable":true}}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}}}},"/dapp/elexium/venft/wallet/{address}":{"get":{"tags":["dapps:elexium"],"summary":"veNFT lock/unlock events for a wallet","description":"Returns all `VotingEscrowCollection` Deposit and Withdraw events where the given\nwallet address is the `provider`, most-recent first. Useful for listing all veNFTs\never created or topped up by a wallet.\n","operationId":"getElexiumVenftByWallet","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"address","in":"path","required":true,"description":"Wallet address (provider).","schema":{"type":"string"}},{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"Paginated list of veNFT lock/unlock events for the wallet","content":{"application/json":{"schema":{"type":"object","properties":{"address":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/VenftLockEvent"}},"nextKey":{"type":"string","nullable":true}}}}}},"401":{"description":"Unauthorized"}}}},"/dapp/elexium/venft/{tokenId}/mints":{"get":{"tags":["dapps:elexium"],"summary":"veNFT mint (CREATE_LOCK) events","description":"Returns only the `CREATE_LOCK_TYPE` (depositType=1) Deposit events for the given\nveNFT tokenId. Typically one event per veNFT (the initial lock creation).\n","operationId":"getElexiumVenftMints","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"tokenId","in":"path","required":true,"description":"veNFT token ID (U256 as string).","schema":{"type":"string"}},{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"CREATE_LOCK Deposit events for the veNFT","content":{"application/json":{"schema":{"type":"object","properties":{"tokenId":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/VenftLockEvent"}},"nextKey":{"type":"string","nullable":true}}}}}},"401":{"description":"Unauthorized"}}}},"/dapp/elexium/venft/{tokenId}/history":{"get":{"tags":["dapps:elexium"],"summary":"veNFT full lock amount history","description":"Returns all Deposit and Withdraw events for the given veNFT tokenId in chronological\norder. The client can reconstruct the cumulative locked EX amount over time by summing\nDeposit `value` and subtracting Withdraw `value` values. `depositType` indicates the\nreason for each deposit (0=DEPOSIT_FOR, 1=CREATE_LOCK, 2=INCREASE_LOCK_AMOUNT,\n3=INCREASE_UNLOCK_TIME, 4=MERGE, 5=SPLIT).\n","operationId":"getElexiumVenftHistory","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"tokenId","in":"path","required":true,"description":"veNFT token ID (U256 as string).","schema":{"type":"string"}},{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"Full Deposit+Withdraw history for the veNFT","content":{"application/json":{"schema":{"type":"object","properties":{"tokenId":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/VenftLockEvent"}},"nextKey":{"type":"string","nullable":true}}}}}},"401":{"description":"Unauthorized"}}}},"/dapp/elexium/dex/pools":{"get":{"tags":["dapps:elexium"],"summary":"List all Elexium DEX pools","description":"Returns all pools discovered from PairFactory `PairCreated` events, including\ntheir token0/token1 contract IDs, latest reserves from `Sync` events, and\nwhether the pool is the ALPH/EX pool used for price computation.\n","operationId":"getElexiumDexPools","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","responses":{"200":{"description":"All known Elexium DEX pools","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"integer"},"pools":{"type":"array","items":{"type":"object","properties":{"pairAddress":{"type":"string","description":"Pair contract address (base58)"},"pairContractId":{"type":"string","description":"Pair contract ID (hex)"},"token0":{"type":"string","description":"token0 contract ID (hex); all-zeros = native ALPH"},"token1":{"type":"string","description":"token1 contract ID (hex)"},"stable":{"type":"boolean","description":"True for stable swap pools"},"pairIndex":{"type":"integer","description":"Pool creation order (1-indexed)"},"isAlphEx":{"type":"boolean","description":"True for the ALPH/EX pool used in price calculation"},"reserve0":{"type":"string","description":"Latest reserve0 from Sync event (raw U256)"},"reserve1":{"type":"string","description":"Latest reserve1 from Sync event (raw U256)"},"lastSyncTimestamp":{"type":"integer","description":"Block timestamp (ms) of the last Sync event"}}}}}}}}},"401":{"description":"Unauthorized"}}}},"/dapp/elexium/dex/pools/{pairAddress}/swaps":{"get":{"tags":["dapps:elexium"],"summary":"Swaps for an Elexium DEX pool","description":"Returns paginated `Swap` events for the given pair contract address,\nordered by most-recent first.\n","operationId":"getElexiumDexPoolSwaps","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"pairAddress","in":"path","required":true,"description":"Pair contract address (base58)","schema":{"type":"string"}},{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"Paginated list of swap events","content":{"application/json":{"schema":{"type":"object","properties":{"pairAddress":{"type":"string"},"items":{"type":"array","items":{"type":"object","properties":{"eventKey":{"type":"string"},"sender":{"type":"string"},"amount0In":{"type":"string"},"amount1In":{"type":"string"},"amount0Out":{"type":"string"},"amount1Out":{"type":"string"},"to":{"type":"string"},"blockTimestamp":{"type":"integer"},"txId":{"type":"string"}}}},"nextKey":{"type":"string","nullable":true}}}}}},"401":{"description":"Unauthorized"}}}},"/dapp/elexium/dex/ex/price":{"get":{"tags":["dapps:elexium"],"summary":"Latest EX token price (most recent daily OHLC)","description":"Returns the most recent daily OHLC item for the EX token. The `close` field\nis the last computed EX/USD price for that day.\n","operationId":"getElexiumExPrice","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","responses":{"200":{"description":"Most recent daily EX price OHLC","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExDailyOhlc"}}}},"401":{"description":"Unauthorized"},"404":{"description":"No price data available yet"}}}},"/dapp/elexium/dex/ex/price/history":{"get":{"tags":["dapps:elexium"],"summary":"EX token daily OHLC history","description":"Returns paginated daily OHLC history for the EX token, most-recent day first.\nEach item covers one calendar day (`YYYY-MM-DD`). Past completed days are served\nfrom S3 cache (fast). The default page size is 365.\n","operationId":"getElexiumExPriceHistory","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"Paginated daily OHLC history","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","example":"EX"},"items":{"type":"array","items":{"$ref":"#/components/schemas/ExDailyOhlc"}},"nextKey":{"type":"string","nullable":true}}}}}},"401":{"description":"Unauthorized"}}}},"/dapp/elexium/dex/ex/price/day/{date}":{"get":{"tags":["dapps:elexium"],"summary":"EX token OHLC for a specific day","description":"O(1) `GetItem` fetch of the daily OHLC record for the given calendar day.\n","operationId":"getElexiumExPriceDay","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"date","in":"path","required":true,"description":"Calendar day in `YYYY-MM-DD` format.","schema":{"type":"string","example":"2024-11-15"}}],"responses":{"200":{"description":"Daily OHLC item","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExDailyOhlc"}}}},"401":{"description":"Unauthorized"},"404":{"description":"No data for that date"}}}},"/dapp/elexium/dex/ex/price/candles/5m":{"get":{"tags":["dapps:elexium"],"summary":"EX token 5-minute OHLC candles","description":"Returns 5-minute OHLC candles for the EX token, newest first. Optionally filter\nby a time range using `from` and `to` (Unix milliseconds). Without a range, returns\nthe most recent candles. Past completed days are served from S3 cache.\n","operationId":"getElexiumExPriceCandles5m","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"},{"name":"from","in":"query","required":false,"description":"Start of range (Unix ms, inclusive).","schema":{"type":"integer"}},{"name":"to","in":"query","required":false,"description":"End of range (Unix ms, inclusive).","schema":{"type":"integer"}}],"responses":{"200":{"description":"5-minute OHLC candles","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","example":"EX"},"items":{"type":"array","items":{"$ref":"#/components/schemas/OhlcCandle"}},"nextKey":{"type":"string","nullable":true}}}}}},"401":{"description":"Unauthorized"}}}},"/dapp/elexium/dex/ex/price/candles/1h":{"get":{"tags":["dapps:elexium"],"summary":"EX token 1-hour OHLC candles","description":"Returns 1-hour OHLC candles for the EX/USD price of the EX token. Filter by time\nrange using `from` and `to` (Unix milliseconds). Without a range, returns the most\nrecent candles (newest first). Past completed days are served from S3 cache.\n","operationId":"getElexiumExPriceCandles1h","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"},{"name":"from","in":"query","required":false,"description":"Start of range (Unix ms, inclusive).","schema":{"type":"integer"}},{"name":"to","in":"query","required":false,"description":"End of range (Unix ms, inclusive).","schema":{"type":"integer"}}],"responses":{"200":{"description":"1-hour OHLC candles","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","example":"EX"},"items":{"type":"array","items":{"$ref":"#/components/schemas/OhlcCandle"}},"nextKey":{"type":"string","nullable":true}}}}}},"401":{"description":"Unauthorized"}}}},"/dapp/elexium/dex/ex/price-alph":{"get":{"tags":["dapps:elexium"],"summary":"Latest EX/ALPH price (most recent daily OHLC)","description":"Returns the most recent daily OHLC item for the EX/ALPH ratio.\nThe `close` field is the last computed EX/ALPH price (ALPH per EX) for that day.\n","operationId":"getElexiumExPriceAlph","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","responses":{"200":{"description":"Most recent daily EX/ALPH OHLC","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExDailyOhlc"}}}},"401":{"description":"Unauthorized"},"404":{"description":"No price data available yet"}}}},"/dapp/elexium/dex/ex/price-alph/history":{"get":{"tags":["dapps:elexium"],"summary":"EX/ALPH daily OHLC history","description":"Returns paginated daily OHLC history for the EX/ALPH price ratio, most-recent day\nfirst. Each item covers one calendar day (`YYYY-MM-DD`). Past completed days are\nserved from S3 cache (fast). The default page size is 365.\n","operationId":"getElexiumExPriceAlphHistory","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"Paginated daily EX/ALPH OHLC history","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","example":"EX/ALPH"},"items":{"type":"array","items":{"$ref":"#/components/schemas/ExDailyOhlc"}},"nextKey":{"type":"string","nullable":true}}}}}},"401":{"description":"Unauthorized"}}}},"/dapp/elexium/dex/ex/price-alph/day/{date}":{"get":{"tags":["dapps:elexium"],"summary":"EX/ALPH OHLC for a specific day","description":"O(1) `GetItem` fetch of the daily EX/ALPH OHLC record for the given calendar day.\n","operationId":"getElexiumExPriceAlphDay","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"date","in":"path","required":true,"description":"Calendar day in `YYYY-MM-DD` format.","schema":{"type":"string","example":"2024-11-15"}}],"responses":{"200":{"description":"Daily EX/ALPH OHLC item","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExDailyOhlc"}}}},"401":{"description":"Unauthorized"},"404":{"description":"No data for that date"}}}},"/dapp/elexium/dex/ex/price-alph/candles/5m":{"get":{"tags":["dapps:elexium"],"summary":"EX/ALPH 5-minute OHLC candles","description":"Returns 5-minute OHLC candles for the EX/ALPH price ratio. Filter by time range\nusing `from` and `to` (Unix milliseconds). Without a range, returns the most recent\ncandles (newest first). Past completed days are served from S3 cache.\n","operationId":"getElexiumExPriceAlphCandles5m","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"},{"name":"from","in":"query","required":false,"description":"Start of range (Unix ms, inclusive).","schema":{"type":"integer"}},{"name":"to","in":"query","required":false,"description":"End of range (Unix ms, inclusive).","schema":{"type":"integer"}}],"responses":{"200":{"description":"5-minute EX/ALPH OHLC candles","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","example":"EX/ALPH"},"items":{"type":"array","items":{"$ref":"#/components/schemas/OhlcCandle"}},"nextKey":{"type":"string","nullable":true}}}}}},"401":{"description":"Unauthorized"}}}},"/dapp/elexium/dex/ex/price-alph/candles/1h":{"get":{"tags":["dapps:elexium"],"summary":"EX/ALPH 1-hour OHLC candles","description":"Returns 1-hour OHLC candles for the EX/ALPH price ratio. Filter by time range\nusing `from` and `to` (Unix milliseconds). Without a range, returns the most recent\ncandles (newest first). Past completed days are served from S3 cache.\n","operationId":"getElexiumExPriceAlphCandles1h","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"},{"name":"from","in":"query","required":false,"description":"Start of range (Unix ms, inclusive).","schema":{"type":"integer"}},{"name":"to","in":"query","required":false,"description":"End of range (Unix ms, inclusive).","schema":{"type":"integer"}}],"responses":{"200":{"description":"1-hour EX/ALPH OHLC candles","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","example":"EX/ALPH"},"items":{"type":"array","items":{"$ref":"#/components/schemas/OhlcCandle"}},"nextKey":{"type":"string","nullable":true}}}}}},"401":{"description":"Unauthorized"}}}},"/dapp/dia-oracle/price/{symbol}":{"get":{"tags":["dapps:dia-oracle"],"summary":"Latest oracle daily OHLC for a symbol","description":"Returns the most recent daily OHLC item for the given symbol\n(e.g. `ALPH/USD`, `BTC/USD`, `ETH/USD`). The `close` field is the last\nprice tick of the most recent day indexed.\nSymbol matching is case-insensitive.\n","operationId":"getDiaOracleLatestPrice","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"symbol","in":"path","required":true,"description":"Oracle symbol (e.g. ALPH/USD, BTC/USD). URL-encode the slash.","schema":{"type":"string"}}],"responses":{"200":{"description":"Latest daily OHLC for the symbol","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OracleDailyOhlc"}}}},"401":{"description":"Unauthorized"},"404":{"description":"No oracle data for that symbol"}}}},"/dapp/dia-oracle/price/{symbol}/history":{"get":{"tags":["dapps:dia-oracle"],"summary":"Historical daily OHLC for a symbol","description":"Returns paginated daily OHLC history for the given oracle symbol, most-recent\nday first. Each item contains OHLC stats and a `ticks` array of individual\noracle updates within that day.\n","operationId":"getDiaOraclePriceHistory","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"symbol","in":"path","required":true,"description":"Oracle symbol (e.g. ALPH/USD, BTC/USD). URL-encode the slash.","schema":{"type":"string"}},{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"Paginated daily OHLC history","content":{"application/json":{"schema":{"type":"object","properties":{"symbol":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/OracleDailyOhlc"}},"nextKey":{"type":"string","nullable":true}}}}}},"401":{"description":"Unauthorized"}}}},"/dapp/dia-oracle/price/{symbol}/day/{date}":{"get":{"tags":["dapps:dia-oracle"],"summary":"Oracle daily OHLC for a specific day","description":"O(1) `GetItem` fetch of the full daily OHLC + ticks for the given symbol and day.\n","operationId":"getDiaOraclePriceDay","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"symbol","in":"path","required":true,"description":"Oracle symbol (e.g. ALPH/USD). URL-encode the slash.","schema":{"type":"string"}},{"name":"date","in":"path","required":true,"description":"Calendar day in `YYYY-MM-DD` format.","schema":{"type":"string","example":"2024-11-15"}}],"responses":{"200":{"description":"Daily OHLC + ticks item","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OracleDailyOhlc"}}}},"401":{"description":"Unauthorized"},"404":{"description":"No data for that symbol/date"}}}},"/dapp/dia-oracle/price/{symbol}/candles/5m":{"get":{"tags":["dapps:dia-oracle"],"summary":"Oracle 5-minute OHLC candles for a symbol","description":"Returns 5-minute OHLC candles for the given oracle symbol. Optionally filter by\ntime range using `from` and `to` (Unix milliseconds). Without a range, returns\nthe most recent candles.\n","operationId":"getDiaOraclePriceCandles5m","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"symbol","in":"path","required":true,"description":"Oracle symbol (e.g. ALPH/USD). URL-encode the slash.","schema":{"type":"string"}},{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"},{"name":"from","in":"query","required":false,"description":"Start of range (Unix ms, inclusive).","schema":{"type":"integer"}},{"name":"to","in":"query","required":false,"description":"End of range (Unix ms, inclusive).","schema":{"type":"integer"}}],"responses":{"200":{"description":"5-minute OHLC candles","content":{"application/json":{"schema":{"type":"object","properties":{"symbol":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/OhlcCandle"}},"nextKey":{"type":"string","nullable":true}}}}}},"401":{"description":"Unauthorized"}}}},"/dapp/alphbanx/loans":{"get":{"tags":["dapps:alphbanx"],"summary":"AlphBanx active loans","description":"Returns the current loan positions mirrored from the abx-mirror service.\nCursor-based pagination via `nextKey`. Requires user authentication.\n","operationId":"getAlphBanxLoans","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"Paginated list of loan positions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DappPagedResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Query failed"}}}},"/dapp/alphbanx/auctions":{"get":{"tags":["dapps:alphbanx"],"summary":"AlphBanx active auctions","description":"Returns the current liquidation auctions mirrored from the abx-mirror service.\nCursor-based pagination via `nextKey`. Requires user authentication.\n","operationId":"getAlphBanxAuctions","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"Paginated list of auctions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DappPagedResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Query failed"}}}},"/dapp/alphbanx/stakers":{"get":{"tags":["dapps:alphbanx"],"summary":"AlphBanx staker positions","description":"Returns staker positions mirrored from the abx-mirror service.\nCursor-based pagination via `nextKey`. Requires user authentication.\n","operationId":"getAlphBanxStakers","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"Paginated list of staker positions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DappPagedResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Query failed"}}}},"/addresses/{addr}/labels":{"get":{"tags":["Addresses"],"summary":"List labels for an address","description":"Returns address labels for the given address. Public.","operationId":"getAddressLabels","security":[],"x-access-level":"Public","parameters":[{"name":"addr","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of labels","content":{"application/json":{"schema":{"type":"object","required":["labels"],"properties":{"labels":{"type":"array","items":{"type":"object","properties":{"address":{"type":"string"},"label":{"type":"string"},"source":{"type":"string"},"mapped_label":{"type":"string"},"metadata":{"type":"object"},"icon":{"type":"array","description":"Ordered CDN logos (pools may include two entries). Replaces legacy single URL + icon_hash.","items":{"$ref":"#/components/schemas/AddressLabelIconSlot"}},"display_order":{"type":"integer","description":"Sort ascending among labels for the same address; lower is more prominent"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}}}}}}}}}}},"/addresses/search":{"get":{"tags":["Addresses"],"summary":"Search addresses with autocomplete","description":"Search addresses by address or label text. Returns primary labels for matching addresses.","operationId":"searchAddresses","security":[],"x-access-level":"Public","parameters":[{"name":"q","in":"query","required":true,"description":"Search query (address or label text)","schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum results to return (default 10, max 50)","schema":{"type":"integer","default":10,"maximum":50}}],"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"type":"object","properties":{"results":{"type":"array","items":{"type":"object","properties":{"address":{"type":"string"},"primary_label":{"type":"string"},"dapp_icon":{"type":"string","nullable":true}}}}}}}}},"400":{"description":"Missing search query parameter 'q'"}}}},"/addresses/{addr}/label/add":{"post":{"tags":["Addresses"],"summary":"Add address label (admin)","description":"Add or update an address label. Admin only. Address in path.","operationId":"addAddressLabel","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"addr","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["label","source"],"properties":{"label":{"type":"string"},"source":{"type":"string"},"mapped_label":{"type":"string"},"metadata":{"type":"object"}}}}}},"responses":{"200":{"description":"Label added"},"400":{"description":"label, source required"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (admin only)"}}}},"/addresses/{addr}/label/del":{"post":{"tags":["Addresses"],"summary":"Delete address label (admin)","description":"Delete an address label by (address, label, source). Address in path. Admin only.","operationId":"delAddressLabel","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"addr","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["label","source"],"properties":{"label":{"type":"string"},"source":{"type":"string"}}}}}},"responses":{"200":{"description":"Label deleted"},"400":{"description":"label, source required"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (admin only)"}}}},"/addresses/{addr}/label/reorder":{"post":{"tags":["Addresses"],"summary":"Reorder address label (admin)","description":"Move a label row up or down in the canonical sort (display_order, then label, then source).\nSwaps with the adjacent row and re-assigns display_order to 0..n-1 for all labels of the address.\n","operationId":"reorderAddressLabel","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"addr","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["label","source","direction"],"properties":{"label":{"type":"string"},"source":{"type":"string"},"direction":{"type":"string","enum":["up","down"]}}}}}},"responses":{"200":{"description":"Reordered"},"400":{"description":"Invalid input or cannot move further"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (admin only)"},"404":{"description":"Label row not found"}}}},"/addresses/{address}/transactions":{"get":{"tags":["Addresses"],"summary":"Transactions for an address (decorated)","description":"Proxies `GET /addresses/{address}/transactions` from the Alephium explorer backend and decorates each transaction with an `alphscan` object when the database is configured.\n**alphscan** always includes **main_event_pending** (true until a main normalized event exists for that hash). When false, **alphscan** includes event metadata (`dapp_id`, `category`, `sub_kind`, `type`) from that main event.\nOptional **address_labels** (primary label + icon per labeled address on inputs/outputs and the main event) are included when any involved address has a label.\nPaging mirrors the Alephium backend: `page` (default 1) and `limit` (default 20, max 100).\n","operationId":"getAddressTransactions","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"address","in":"path","required":true,"description":"Alephium address (base58)","schema":{"type":"string"}},{"name":"page","in":"query","schema":{"type":"integer","default":1,"minimum":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"minimum":1,"maximum":100}}],"responses":{"200":{"description":"List of transactions, each optionally decorated with Alphscan metadata","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AlephiumTransaction"}}}}},"400":{"description":"Missing address"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (invalid API key, plan, or origin)"},"502":{"description":"Could not reach Alephium backend"},"503":{"description":"Database not configured"}}}},"/addresses/{address}/tokens/{tokenid}/transactions":{"get":{"tags":["Addresses"],"summary":"Token transactions for an address (decorated)","description":"Proxies `GET /addresses/{address}/tokens/{tokenid}/transactions` from the Alephium explorer backend and decorates each transaction with an `alphscan` object when the database is configured.\nSame contract as GET `/addresses/{address}/transactions`: **main_event_pending** plus optional main-event fields and **address_labels**.\nPaging: `page` (default 1) and `limit` (default 20, max 100).\n","operationId":"getAddressTokenTransactions","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"address","in":"path","required":true,"description":"Alephium address (base58)","schema":{"type":"string"}},{"name":"tokenid","in":"path","required":true,"description":"Token contract id","schema":{"type":"string"}},{"name":"page","in":"query","schema":{"type":"integer","default":1,"minimum":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"minimum":1,"maximum":100}}],"responses":{"200":{"description":"List of transactions, each optionally decorated with Alphscan metadata","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AlephiumTransaction"}}}}},"400":{"description":"Missing address or tokenid"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (invalid API key, plan, or origin)"},"502":{"description":"Could not reach Alephium backend"},"503":{"description":"Database not configured"}}}},"/token/{tokenid}/transactions":{"get":{"tags":["Token"],"summary":"Transactions for a token (decorated)","description":"Proxies `GET /tokens/{tokenid}/transactions` from the Alephium explorer backend and decorates each transaction with an `alphscan` object when the database is configured.\nSame contract as GET `/addresses/{address}/transactions`: **main_event_pending** plus optional main-event fields and **address_labels**.\nPaging: `page` (default 1) and `limit` (default 20, max 100).\n","operationId":"getTokenTransactions","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"tokenid","in":"path","required":true,"description":"Token contract id","schema":{"type":"string"}},{"name":"page","in":"query","schema":{"type":"integer","default":1,"minimum":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"minimum":1,"maximum":100}}],"responses":{"200":{"description":"List of transactions, each optionally decorated with Alphscan metadata","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AlephiumTransaction"}}}}},"400":{"description":"Missing tokenid"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (invalid API key, plan, or origin)"},"502":{"description":"Could not reach Alephium backend"},"503":{"description":"Database not configured"}}}},"/token/{tokenid}/burns":{"get":{"tags":["Token"],"summary":"Cross-dapp burns for a token","description":"Returns all burn events for the given token across all dapps (Furnace and ChainReaction),\nconsolidated from the `alphscan-burns` table.\nResults are ordered newest-first. Cursor-based pagination via `nextKey`.\n","operationId":"getTokenBurns","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"tokenid","in":"path","required":true,"description":"Token contract id (hex) or `ALPH`","schema":{"type":"string"}},{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/NextKey"}],"responses":{"200":{"description":"Paginated list of burn events for the token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DappPagedResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Query failed"}}}},"/system/plans/delete":{"post":{"tags":["Plans"],"summary":"Delete plan (admin)","description":"Delete a plan by id. Fails if keys reference it. Admin only.","operationId":"deletePlan","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["plan_id"],"properties":{"plan_id":{"type":"string"}}}}}},"responses":{"200":{"description":"Plan deleted"},"400":{"description":"Plan in use"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (admin only)"}}}},"/system/telegram/admins":{"get":{"tags":["Telegram"],"summary":"List Telegram admins (admin)","description":"List Telegram user IDs that are bot admins. Admin only.","operationId":"getTelegramAdmins","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","responses":{"200":{"description":"List of admin user IDs","content":{"application/json":{"schema":{"type":"object","properties":{"admins":{"type":"array","items":{"type":"string"}}}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (admin only)"}}}},"/system/telegram/admins/add":{"post":{"tags":["Telegram"],"summary":"Add Telegram admin (admin)","operationId":"addTelegramAdmin","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["telegram_user_id"],"properties":{"telegram_user_id":{"type":"string"},"username":{"type":"string"}}}}}},"responses":{"200":{"description":"Admin added"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (admin only)"}}}},"/system/telegram/admins/remove":{"post":{"tags":["Telegram"],"summary":"Remove Telegram admin (admin)","operationId":"removeTelegramAdmin","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["telegram_user_id"],"properties":{"telegram_user_id":{"type":"string"}}}}}},"responses":{"200":{"description":"Admin removed"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (admin only)"}}}},"/system/banned":{"get":{"tags":["Banned"],"summary":"List banned users (admin)","description":"List banned Telegram user IDs. Admin only.","operationId":"getBannedList","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","responses":{"200":{"description":"List of banned user IDs","content":{"application/json":{"schema":{"type":"object","properties":{"banned":{"type":"array","items":{"type":"string"}}}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (admin only)"}}}},"/system/banned/add":{"post":{"tags":["Banned"],"summary":"Ban user (admin)","operationId":"addBanned","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["telegram_user_id"],"properties":{"telegram_user_id":{"type":"string"}}}}}},"responses":{"200":{"description":"User banned"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (admin only)"}}}},"/system/banned/remove":{"post":{"tags":["Banned"],"summary":"Unban user (admin)","operationId":"removeBanned","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["telegram_user_id"],"properties":{"telegram_user_id":{"type":"string"}}}}}},"responses":{"200":{"description":"User unbanned"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (admin only)"}}}},"/system/payment/next-index":{"get":{"tags":["Payment"],"summary":"Next payment derivation index (admin)","description":"Returns next index for a new deposit address. Admin only.","operationId":"getPaymentNextIndex","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","responses":{"200":{"description":"Next index","content":{"application/json":{"schema":{"type":"object","properties":{"next_index":{"type":"integer"}}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (admin only)"}}}},"/system/payment/request":{"post":{"tags":["Payment"],"summary":"Create payment request (admin)","description":"Create a pending payment (new key or upgrade). Admin only.","operationId":"createPaymentRequest","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"telegram_user_id":{"type":"string"},"plan_id":{"type":"string"},"key_id":{"type":"string"},"amount_alph":{"type":"string"},"address":{"type":"string"}}}}}},"responses":{"200":{"description":"Pending payment created"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (admin only)"}}}},"/system/payment/verify":{"post":{"tags":["Payment"],"summary":"Verify payment (admin)","description":"Verify tx on chain, match to pending payment, create or upgrade key. Admin only.","operationId":"verifyPayment","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["tx_id"],"properties":{"tx_id":{"type":"string"}}}}}},"responses":{"200":{"description":"Payment verified and key created/updated"},"400":{"description":"Tx not found or no matching pending payment"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (admin only)"}}}},"/system/payment/pending":{"get":{"tags":["Payment"],"summary":"List pending payments (admin)","description":"List pending payment requests for a user. Admin only.","operationId":"getPaymentPending","security":[{"ApiKeyAuth":[]}],"x-access-level":"Admin","parameters":[{"name":"telegram_user_id","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of pending payments","content":{"application/json":{"schema":{"type":"object","properties":{"pending":{"type":"array"}}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden (admin only)"}}}},"/system/payment/history":{"get":{"tags":["Payment"],"summary":"Payment history","description":"List paid payments for the user. User sees own only; admin can pass telegram_user_id.","operationId":"getPaymentHistory","security":[{"ApiKeyAuth":[]}],"x-access-level":"User","parameters":[{"name":"telegram_user_id","in":"query","required":false,"description":"User ID (admin only)","schema":{"type":"string"}}],"responses":{"200":{"description":"List of paid payments","content":{"application/json":{"schema":{"type":"object","properties":{"history":{"type":"array"}}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"}}}},"/system/wireguard/ping":{"get":{"tags":["WireGuard"],"summary":"Ping WireGuard host","description":"Test that the Lambda can reach the WireGuard EC2 instance (TCP connect to WIREGUARD_IP, default 10.7.0.1).\nUses TCP on port 22 by default (ICMP not available in Lambda). Public.\n","operationId":"getSystemWireguardPing","security":[],"x-access-level":"Public","responses":{"200":{"description":"Host reachable via WireGuard","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"host":{"type":"string"},"port":{"type":"integer"},"message":{"type":"string"}}}}}},"503":{"description":"Not reachable or WIREGUARD_IP not configured","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"error":{"type":"string"}}}}}}}}},"/system/wireguard/postgresql":{"get":{"tags":["WireGuard"],"summary":"Test PostgreSQL via WireGuard","description":"Test that the Lambda can connect to PostgreSQL through the WireGuard EC2 instance (host from WIREGUARD_PG_HOST, default 10.7.0.1).\nRuns SELECT 1. Public.\n","operationId":"getSystemWireguardPostgresql","security":[],"x-access-level":"Public","responses":{"200":{"description":"PostgreSQL reachable via WireGuard","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"message":{"type":"string"}}}}}},"503":{"description":"Connection failed or not configured","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"detail":{"type":"string"}}}}}}}}},"/system/wireguard/tables":{"get":{"tags":["WireGuard"],"summary":"List database tables","description":"Returns list of tables from the database (DATABASE_URL / DATABASE_READ_URL).\nUses information_schema.tables; excludes pg_catalog and information_schema. Public.\n","operationId":"getSystemWireguardTables","security":[],"x-access-level":"Public","responses":{"200":{"description":"List of tables (schema + name)","content":{"application/json":{"schema":{"type":"object","required":["tables"],"properties":{"tables":{"type":"array","items":{"type":"object","properties":{"schema":{"type":"string"},"name":{"type":"string"}}}}}}}}},"500":{"description":"Server error"},"503":{"description":"Database not configured"}}}},"/system/database/schema-stats":{"get":{"tags":["System"],"summary":"Database schema statistics snapshot","description":"Returns snapshots from `db_schema_stats_*` (ingestion `ingest:db-schema-stats`). Two sources are stored:\n**alphscan** (this RDS, default) and **explorer** (Alephium explorer-backend DB, when `EXPLORER_BACKEND_DATABASE_URL` is set on ingestion).\nQuery `source=alphscan|explorer` selects the latest successful run for that source; `run_id` loads a specific run (ignores `source`).\n","operationId":"getSystemDatabaseSchemaStats","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"run_id","in":"query","required":false,"schema":{"type":"integer","minimum":1},"description":"Snapshot run id; omit for latest successful run for the given source."},{"name":"source","in":"query","required":false,"schema":{"type":"string","enum":["alphscan","explorer"],"default":"alphscan"},"description":"Which stored snapshot stream when `run_id` is omitted."}],"responses":{"200":{"description":"Snapshot with tables and columns","content":{"application/json":{"schema":{"type":"object","required":["run","tables","columns"],"properties":{"run":{"type":"object","properties":{"id":{"type":"integer"},"snapshot_source":{"type":"string","description":"alphscan | explorer"},"created_at":{"type":"string","format":"date-time"},"finished_at":{"type":"string","format":"date-time","nullable":true},"database_name":{"type":"string"},"pg_version":{"type":"string","nullable":true},"total_database_bytes":{"type":"string","description":"Total DB size (text bigint)"},"table_count":{"type":"integer"},"column_count":{"type":"integer"},"index_count":{"type":"integer"},"status":{"type":"string"},"error":{"type":"string","nullable":true}}},"tables":{"type":"array","items":{"type":"object"}},"columns":{"type":"array","items":{"type":"object"}},"indexes":{"type":"array","description":"Per-index on-disk size (pg_relation_size); omitted on older snapshots before migration.","items":{"type":"object"}}}}}}},"400":{"description":"Invalid run_id or source"},"403":{"description":"Admin only"},"404":{"description":"No snapshot yet"},"500":{"description":"Server error"}}}},"/system/payload-chunk":{"get":{"tags":["System"],"summary":"Payload chunk store (admin)","description":"Inspect `payload_entry`, `payload_staging`, open/sealed chunks, and optionally list S3 objects under the payload bucket.\nQuery `resource`: `overview` (default, aggregates + small samples), `entries`, `staging`, `open`, `sealed`, `s3`.\n","operationId":"getSystemPayloadChunk","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"resource","in":"query","required":false,"schema":{"type":"string","enum":["overview","entries","body","staging","open","sealed","s3"],"default":"overview"}},{"name":"domain","in":"query","required":false,"schema":{"type":"string"},"description":"Filter `entries` by payload domain."},{"name":"state","in":"query","required":false,"schema":{"type":"string","enum":["pending","sealed"]},"description":"Filter `entries` by state."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"prefix","in":"query","required":false,"schema":{"type":"string"},"description":"S3 prefix for `resource=s3` (defaults to payload key prefix)."},{"name":"max_keys","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"continuation_token","in":"query","required":false,"schema":{"type":"string"},"description":"S3 ListObjectsV2 continuation token."},{"name":"open_chunk_id","in":"query","required":false,"schema":{"type":"string","format":"uuid"},"description":"Filter `entries` by `payload_entry.open_chunk_id`."},{"name":"sealed_chunk_id","in":"query","required":false,"schema":{"type":"string","format":"uuid"},"description":"Filter `entries` by `payload_entry.sealed_chunk_id`, or `resource=sealed` to one sealed chunk row."},{"name":"entry_id","in":"query","required":false,"schema":{"type":"string","format":"uuid"},"description":"Filter `entries` or `staging` by payload entry UUID."},{"name":"chunk_id","in":"query","required":false,"schema":{"type":"string","format":"uuid"},"description":"When `resource=open`, return only this `payload_chunk_open` row."}],"responses":{"200":{"description":"Overview, table rows, or S3 listing","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Invalid resource"},"403":{"description":"Admin only"},"500":{"description":"Server error"}}},"post":{"tags":["System"],"summary":"Seal open payload chunk (admin)","description":"Triggers sealing (gzip + upload to S3 + update payload_entry locators + clear staging) for a single open chunk.\n","operationId":"postSystemPayloadChunkSeal","security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["action","open_chunk_id"],"properties":{"action":{"type":"string","enum":["seal"]},"open_chunk_id":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad request"},"403":{"description":"Admin only"},"500":{"description":"Server error"}}}},"/telegram/webhook":{"post":{"tags":["Webhook"],"summary":"Telegram bot webhook","description":"Receives Telegram updates for the apikey bot. Public (Telegram servers only).","operationId":"telegramWebhook","security":[],"x-access-level":"Public","responses":{"200":{"description":"OK"}}}}},"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Your API key. Enter once – sent as X-API-Key and Authorization Bearer (API Gateway requires both)."}},"parameters":{"PageSize":{"name":"pageSize","in":"query","description":"Number of items per page (1–1000, default 1000)","schema":{"type":"integer","default":1000,"minimum":1,"maximum":1000}},"NextKey":{"name":"nextKey","in":"query","description":"Opaque cursor returned in the previous response to fetch the next page","schema":{"type":"string"}}},"schemas":{"VenftLockEvent":{"type":"object","description":"A single VotingEscrowCollection Deposit or Withdraw event for a veNFT.\nDeposit events have `depositType`, `locktime`. Withdraw events do not.\n","properties":{"tokenId":{"type":"string","description":"veNFT token ID (U256 as string)."},"eventKey":{"type":"string","description":"Unique sort key — `{contractAddress}#{seqNum}`."},"eventType":{"type":"string","enum":["Deposit","Withdraw"]},"provider":{"type":"string","description":"Wallet address that initiated the deposit/withdrawal."},"value":{"type":"string","description":"Amount of EX tokens locked or unlocked (raw U256)."},"locktime":{"type":"integer","description":"Lock expiry timestamp (seconds). Present on Deposit events only."},"depositType":{"type":"integer","description":"Reason for the deposit. Only present on Deposit events.\n0=DEPOSIT_FOR, 1=CREATE_LOCK, 2=INCREASE_LOCK_AMOUNT,\n3=INCREASE_UNLOCK_TIME, 4=MERGE, 5=SPLIT\n"},"ts":{"type":"integer","description":"Oracle/contract timestamp of the event (seconds)."},"txId":{"type":"string"},"blockHash":{"type":"string"},"indexedAt":{"type":"integer","description":"Wall-clock time (ms) when the item was indexed."}}},"OhlcCandle":{"type":"object","description":"A single OHLC candle covering a fixed time bucket (e.g. 5 minutes).","properties":{"candleTs":{"type":"integer","description":"Start timestamp of the bucket (Unix ms, 5-min aligned).","example":1731628800000},"open":{"type":"number","description":"Opening price for the bucket."},"high":{"type":"number","description":"Highest price in the bucket."},"low":{"type":"number","description":"Lowest price in the bucket."},"close":{"type":"number","description":"Closing (last) price in the bucket."},"avg":{"type":"number","description":"Average price across all ticks in the bucket."},"count":{"type":"integer","description":"Number of price ticks accumulated in the bucket."}}},"ExDailyOhlc":{"type":"object","description":"Daily OHLC summary for the EX token price (EX/USD).","properties":{"token":{"type":"string","example":"EX"},"date":{"type":"string","description":"Calendar day (YYYY-MM-DD).","example":"2024-11-15"},"open":{"type":"number"},"high":{"type":"number"},"low":{"type":"number"},"close":{"type":"number","description":"Last computed EX/USD price of the day."},"avg":{"type":"number"},"count":{"type":"integer"},"exPriceAlph":{"type":"number","description":"EX/ALPH ratio at the last Sync of the day."},"alphUsd":{"type":"number","description":"ALPH/USD oracle price used for the last computation of the day."},"alphReserve":{"type":"string","description":"ALPH reserve (raw U256) at the last Sync."},"exReserve":{"type":"string","description":"EX reserve (raw U256) at the last Sync."},"lastSyncTimestamp":{"type":"integer","description":"Block timestamp (ms) of the last Sync event of the day."},"indexedAt":{"type":"integer","description":"Wall-clock time (ms) when the item was last written."}}},"OracleDailyOhlc":{"type":"object","description":"Daily OHLC summary for a DIA oracle symbol (e.g. ALPH/USD), including individual ticks.","properties":{"symbol":{"type":"string","example":"ALPH/USD"},"date":{"type":"string","description":"Calendar day (YYYY-MM-DD).","example":"2024-11-15"},"open":{"type":"number"},"high":{"type":"number"},"low":{"type":"number"},"close":{"type":"number","description":"Last oracle price update value of the day (USD)."},"avg":{"type":"number"},"count":{"type":"integer","description":"Number of OracleUpdate events in the day."},"ticks":{"type":"array","description":"Individual oracle updates within the day, in chronological order.","items":{"type":"object","properties":{"ts":{"type":"integer","description":"Oracle update timestamp (ms)."},"v":{"type":"number","description":"Price in USD."},"raw":{"type":"string","description":"Raw U256 value from the event (8 implied decimals)."}}}}}},"ElexiumEpoch":{"type":"object","description":"Pre-computed weekly EX emission epoch summary. Dates and totals are derived from\nactual on-chain `blockTimestamp` values, not a fixed formula — so epoch 1 (which was\nshorter than 7 days) is represented correctly.\n","required":["epoch","dateStart","dateEnd","startTs","endTs","sumEmissions","totalSupply","voteCount","totalVotingPower","computedAt"],"properties":{"epoch":{"type":"integer","description":"Epoch number (positive integer, starts at 1).","example":5},"dateStart":{"type":"string","description":"Date of the earliest on-chain event in this epoch (YYYY-MM-DD, UTC).","example":"2024-11-28"},"dateEnd":{"type":"string","description":"Date of the latest on-chain event in this epoch (YYYY-MM-DD, UTC).","example":"2024-12-04"},"startTs":{"type":"integer","description":"Timestamp (Unix ms) of the earliest on-chain event in this epoch.","example":1732752000000},"endTs":{"type":"integer","description":"Timestamp (Unix ms) of the latest on-chain event in this epoch.","example":1733356799999},"sumEmissions":{"type":"string","description":"Sum of all `weekly` values across every Mint event in this epoch (raw 18-decimal string).","example":"200000000000000000000000"},"totalSupply":{"type":"string","description":"Maximum `circulatingSupply` value across Mint events for this epoch (raw 18-decimal string).","example":"1000000000000000000000000"},"voteCount":{"type":"integer","description":"Number of `Voted` events recorded during this epoch.","example":412},"totalVotingPower":{"type":"string","description":"Sum of all veNFT vote weights cast during this epoch (raw 18-decimal string).","example":"45000000000000000000000000"},"computedAt":{"type":"string","format":"date-time","description":"ISO timestamp of when this epoch summary was last computed."}}},"ExWalletBalance":{"type":"object","description":"EX token balance for a labeled wallet address.","properties":{"label":{"type":"string","description":"Human-readable label (e.g. \"treasury\", \"team\").","example":"treasury"},"address":{"type":"string","description":"Alephium wallet address.","example":"1AbcDef..."},"amount":{"type":"string","description":"EX balance in raw 18-decimal units.","example":"1000000000000000000000000"}}},"ExSupplyDay":{"type":"object","description":"Daily EX token supply snapshot computed by the watcher (Phase F).","properties":{"date":{"type":"string","description":"Calendar day (YYYY-MM-DD).","example":"2025-06-17"},"circulatingSupply":{"type":"string","description":"Total circulating supply from the latest Minter.Mint event (raw 18-decimal).","example":"123456789000000000000000"},"epoch":{"type":"integer","nullable":true,"description":"Emission epoch number at that date."},"exInPools":{"type":"string","description":"Total EX locked across all DEX liquidity pools (raw 18-decimal).","example":"5000000000000000000000000"},"exLockedVeNft":{"type":"string","description":"Net EX locked in VotingEscrow positions (deposits − withdrawals, raw 18-decimal).","example":"20000000000000000000000000"},"exBurned":{"type":"string","description":"Cumulative EX burned from all sources (raw 18-decimal).","example":"500000000000000000000000"},"exByWallet":{"type":"array","items":{"$ref":"#/components/schemas/ExWalletBalance"},"description":"EX balances for labeled wallets (treasury, team, etc.)."},"poolCount":{"type":"integer","description":"Number of active DEX pools."},"veNftCount":{"type":"integer","description":"Number of unique CREATE_LOCK veNFT positions."},"computedAt":{"type":"string","format":"date-time","description":"ISO timestamp when this snapshot was computed."}}},"ExSummary":{"type":"object","description":"Latest EX token summary snapshot. Served from S3 cache when available (O(1)),\notherwise computed live from DynamoDB.\n","properties":{"date":{"type":"string","description":"Date of the supply snapshot (YYYY-MM-DD).","nullable":true},"price":{"allOf":[{"$ref":"#/components/schemas/ExDailyOhlc"}],"nullable":true,"description":"Latest daily EX/USD OHLC, or null if no price data yet."},"priceAlph":{"allOf":[{"$ref":"#/components/schemas/ExDailyOhlc"}],"nullable":true,"description":"Latest daily EX/ALPH OHLC, or null if no price data yet."},"circulatingSupply":{"type":"string","nullable":true,"description":"Current circulating supply (raw 18-decimal units as string).","example":"123456789000000000000000"},"epoch":{"type":"integer","nullable":true,"description":"Weekly epoch number of the latest mint event."},"marketCap":{"type":"string","nullable":true,"description":"Market cap in USD as a decimal string (price.close × supply / 1e18).","example":"4567890.123456"},"poolCount":{"type":"integer","description":"Total number of active DEX pools."},"veNftCount":{"type":"integer","description":"Number of unique CREATE_LOCK veNFT positions."},"exInPools":{"type":"string","nullable":true,"description":"Total EX locked across all DEX pools (raw 18-decimal)."},"exLockedVeNft":{"type":"string","nullable":true,"description":"Net EX locked in VotingEscrow (raw 18-decimal)."},"exBurned":{"type":"string","nullable":true,"description":"Cumulative EX burned from all sources (raw 18-decimal)."},"exByWallet":{"type":"array","nullable":true,"items":{"$ref":"#/components/schemas/ExWalletBalance"},"description":"EX balances for labeled wallets (treasury, team, etc.)."},"computedAt":{"type":"string","format":"date-time","nullable":true,"description":"ISO timestamp when the cached summary was last computed."}}},"DappPagedResponse":{"type":"object","description":"Generic paginated response used by dapp data endpoints","required":["items","pageSize"],"properties":{"items":{"type":"array","description":"Page of result objects (schema varies per endpoint)","items":{"type":"object","additionalProperties":true}},"pageSize":{"type":"integer","description":"Number of items requested per page"},"nextKey":{"type":"string","nullable":true,"description":"Cursor for the next page. Null when there are no more results."}}},"TimeseriesChartType":{"type":"string","description":"Suggested UI chart kind for a timeseries (from metrics catalog).","enum":["ohlcv","line","stackedBar","pie"]},"SeriesInstanceChartPointY":{"type":"object","description":"One row per timestamp when `key` was requested.","required":["t","y","kind"],"properties":{"t":{"type":"integer","format":"int64"},"y":{"type":"number"},"kind":{"type":"string","enum":["segment","pending"]}}},"SeriesInstanceChartPointMulti":{"type":"object","description":"One row per timestamp when `key` was omitted; `values` uses catalog `pointKey` names.","required":["t","values","kind"],"properties":{"t":{"type":"integer","format":"int64"},"values":{"type":"object","additionalProperties":{"type":"number"}},"kind":{"type":"string","enum":["segment","pending"]}}},"SeriesInstanceChartAudit":{"type":"object","description":"Chart handler audit (GET /chart). Timing fields are milliseconds; counter fields are segment/point counts. Unused timings are 0.","properties":{"totalMs":{"type":"integer","description":"End-to-end handler time"},"instanceLookupMs":{"type":"integer","description":"Instance row query + validation"},"pendingBufferMs":{"type":"integer","description":"Pending JSON read from scale buffer table"},"pendingConsolidateMs":{"type":"integer","description":"mergePendingForScale or legacy pending page prep"},"maxPointTsQueryMs":{"type":"integer","description":"resolveMaxPointTsForScale when mode is default"},"segmentMetaQueryMs":{"type":"integer","description":"Sum of segment id/t_min/t_max batch queries"},"segmentBodiesLoadMs":{"type":"integer","description":"Sum of S3/DB segment body loads"},"segmentMergeMs":{"type":"integer","description":"Sum of mergePagePoints over segment batches"},"mergePendingIntoSegmentsMs":{"type":"integer","description":"Merging pending into segment points"},"filterSortSliceMs":{"type":"integer","description":"Window filter","sort":null,"and limit slice":null},"toChartRowsMs":{"type":"integer","description":"dataPointsToChartRows projection"},"segmentsBodiesLoaded":{"type":"integer","description":"Segment bodies loaded for this request"},"segmentPointsLoaded":{"type":"integer","description":"Sum of point row counts in loaded segment payloads"},"segmentMergePointsIn":{"type":"integer","description":"Sum of mergePagePoints inputs (existing+incoming lengths) for segment merges"},"segmentMergePointsOut":{"type":"integer","description":"Sum of mergePagePoints output lengths for segment merges"},"mergePendingPointsIn":{"type":"integer","description":"mergePagePoints input size for final pending merge"},"mergePendingPointsOut":{"type":"integer","description":"mergePagePoints output size for final pending merge"}},"required":["totalMs","instanceLookupMs","pendingBufferMs","pendingConsolidateMs","maxPointTsQueryMs","segmentMetaQueryMs","segmentBodiesLoadMs","segmentMergeMs","mergePendingIntoSegmentsMs","filterSortSliceMs","toChartRowsMs","segmentsBodiesLoaded","segmentPointsLoaded","segmentMergePointsIn","segmentMergePointsOut","mergePendingPointsIn","mergePendingPointsOut"]},"SeriesInstanceChartWindow":{"type":"object","description":"How the chart series was selected (always present).","properties":{"mode":{"type":"string","enum":["default","until","from","range"]},"fromTs":{"type":"integer","format":"int64","nullable":true},"toTs":{"type":"integer","format":"int64","nullable":true},"untilTs":{"type":"integer","format":"int64","nullable":true},"limit":{"type":"integer"},"segmentsScanned":{"type":"integer","description":"Storage segments whose bodies were merged into the chart (after time-window pruning)"},"segmentsMetaExamined":{"type":"integer","description":"Segment rows returned from metadata queries (may include rows skipped without body load)"},"segmentsBodiesLoaded":{"type":"integer","description":"Segment bodies actually loaded from DB/S3 for this request"},"truncated":{"type":"boolean","description":"True if the server stopped after scanning the max segment budget (128) before covering the full logical range"},"anchorNewestBucketStartTs":{"type":"integer","format":"int64","nullable":true,"description":"Newest segment t_max (ms) touched in default/until window mode; null if no segment was read"}},"required":["mode","fromTs","toTs","untilTs","limit","segmentsScanned","segmentsMetaExamined","segmentsBodiesLoaded","truncated","anchorNewestBucketStartTs"]},"SeriesInstanceSegmentRow":{"type":"object","properties":{"segmentId":{"type":"string"},"tMin":{"type":"integer","format":"int64"},"tMax":{"type":"integer","format":"int64"},"pointCount":{"type":"integer"},"minPointTs":{"type":"integer","format":"int64","nullable":true},"maxPointTs":{"type":"integer","format":"int64","nullable":true},"updatedAt":{"type":"integer","format":"int64"},"s3Key":{"type":"string","nullable":true}}},"SeriesInstanceTimeseriesStats":{"type":"object","description":"Aggregated `timeseries_segments` for this instance plus `metrics_point_buffer` pending:\n`totalPoints` is segment `point_count` sum plus `pending_count`; min/max merge segment bounds and raw `t` from `pending_json`.\n","properties":{"totalPoints":{"type":"integer","format":"int64"},"minPointTs":{"type":"integer","format":"int64","nullable":true,"description":"Min timestamp (ms) across stored segments and pending points"},"maxPointTs":{"type":"integer","format":"int64","nullable":true},"segmentCount":{"type":"integer","description":"Number of storage segment rows"}}},"SeriesInstanceSummary":{"type":"object","properties":{"instanceId":{"type":"string"},"seriesId":{"type":"string"},"dimensions":{"type":"object","additionalProperties":{"type":"string"}},"displayName":{"type":"string","nullable":true},"sourcePlugin":{"type":"string","nullable":true},"metadata":{"type":"object","nullable":true},"firstSeenAt":{"type":"integer","format":"int64"},"lastSeenAt":{"type":"integer","format":"int64"},"timeseries":{"$ref":"#/components/schemas/SeriesInstanceTimeseriesStats"},"pendingPoints":{"type":"integer","description":"metrics_point_buffer.pending_count for buffer_id = instanceId"}}},"SeriesInstanceDetail":{"allOf":[{"$ref":"#/components/schemas/SeriesInstanceSummary"}]},"NftCollectionRow":{"type":"object","description":"nft_collection table row","properties":{"collection_address":{"type":"string"},"dapp":{"type":"string","nullable":true,"description":"Originating dapp id (e.g. elexium-dex)"},"interface_kind":{"type":"string"},"interface_id_hex":{"type":"string","nullable":true},"collection_uri_state":{"type":"string","nullable":true},"total_supply_state":{"type":"string","nullable":true},"state_synced_at":{"type":"string","format":"date-time","nullable":true},"display_name":{"type":"string","nullable":true},"display_description":{"type":"string","nullable":true},"display_image":{"type":"string","nullable":true},"offchain_metadata":{"type":"object","nullable":true},"resolved_metadata_at":{"type":"string","format":"date-time","nullable":true},"prefer_resolved_over_state":{"type":"boolean"},"royalty_display":{"type":"object","nullable":true},"listing_count":{"type":"integer"},"sales_count":{"type":"integer"},"registered":{"type":"boolean"},"registration_meta":{"type":"object","nullable":true},"moderation":{"type":"string","enum":["show","hide"]},"moderation_meta":{"type":"object","nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"NftRow":{"type":"object","description":"**nft** table row (optionally joined with collection display fields on list/detail APIs).\n`holding_contract_address` is set when the asset is held by a staking or listing contract instead of the owner wallet.\n","properties":{"nft_contract_address":{"type":"string"},"dapp":{"type":"string","nullable":true,"description":"Originating dapp id (e.g. elexium-dex)"},"collection_address":{"type":"string"},"index_in_collection":{"type":"string","description":"U256 index within collection (numeric string)"},"nft_token_id_hex":{"type":"string","nullable":true},"token_uri_state":{"type":"string","nullable":true},"state_synced_at":{"type":"string","format":"date-time","nullable":true},"display_name":{"type":"string","nullable":true},"display_description":{"type":"string","nullable":true},"display_image":{"type":"string","nullable":true},"offchain_metadata":{"type":"object","nullable":true},"resolved_metadata_at":{"type":"string","format":"date-time","nullable":true},"prefer_resolved_over_state":{"type":"boolean"},"listing_count":{"type":"integer"},"sales_count":{"type":"integer"},"registered":{"type":"boolean"},"registration_meta":{"type":"object","nullable":true},"moderation":{"type":"string","enum":["show","hide"]},"moderation_meta":{"type":"object","nullable":true},"mint_time":{"type":"string","format":"date-time","nullable":true,"description":"Creation time from explorer (mint deployment)"},"mint_tx":{"type":"string","nullable":true,"description":"Transaction id that created the NFT contract"},"minter_address":{"type":"string","nullable":true,"description":"Signer of mint tx"},"owner_address":{"type":"string","nullable":true,"description":"Current logical owner (e.g. veNFT voter)"},"holding_contract_address":{"type":"string","nullable":true,"description":"Escrow/staking contract if not in owner wallet"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"collection_interface_kind":{"type":"string","nullable":true},"collection_display_name":{"type":"string","nullable":true},"collection_collection_uri_state":{"type":"string","nullable":true,"description":"Present on GET /nft/{address}/details only"}}},"NftTraitValueRow":{"type":"object","description":"One row from **nft_trait** (token metadata attributes).","properties":{"trait_key":{"type":"string"},"value_text":{"type":"string"},"value_numeric":{"type":"string","nullable":true,"description":"Decimal string from DB when set"},"value_bool":{"type":"boolean","nullable":true}}},"NftCollectionTraitDefRow":{"type":"object","description":"One row from **nft_collection_trait** (trait catalog for a collection).","properties":{"trait_key":{"type":"string"},"definition_source":{"type":"string"},"display_order":{"type":"integer"},"definition_meta":{"type":"object","nullable":true}}},"ApiPlan":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"requests_per_minute":{"type":"integer"},"requests_per_day":{"type":"integer"},"allowed_origins":{"type":"integer"},"price":{"type":"string"}}},"ApiKey":{"type":"object","properties":{"id":{"type":"string"},"key_prefix":{"type":"string"},"user_id":{"type":"string"},"level":{"type":"string"},"plan_id":{"type":"string"},"allowed_origins":{"type":"array","items":{"type":"string"}},"status":{"type":"string"},"created_at":{"type":"string"}}},"TokenListEntry":{"type":"object","description":"Token item in GET /token/all response","properties":{"id":{"type":"string"},"contractAddress":{"type":"string","description":"Token contract address on chain (DB responses)"},"name":{"type":"string"},"symbol":{"type":"string"},"decimals":{"type":"integer"},"description":{"type":"string"},"logoURI":{"type":"string"},"nameOnChain":{"type":"string"},"symbolOnChain":{"type":"string"},"originChain":{"type":"string"},"unchainedLogoURI":{"type":"string"},"category":{"type":"string"},"categories":{"type":"array","items":{"type":"string"}},"dapp":{"type":"string"},"chainId":{"type":"integer"},"moderation":{"type":"string"},"marketDisplay":{"type":"boolean"},"circulatingSupplyUsd":{"type":"number"},"createdAt":{"type":"number","description":"Registry creation time (Unix ms; format with local timezone)"},"minter":{"type":"string"},"mintTx":{"type":"string"},"mintTime":{"type":"number","description":"On-chain mint time (Unix ms; format with local timezone)"},"metadata":{"type":"object","description":"Present on DB-backed lists; raw token.metadata JSON"}}},"ChainRow":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"chain":{"type":"string"},"short_name":{"type":"string"},"network_id":{"type":"integer"},"native_currency":{"type":"object"},"rpc":{"type":"array"},"explorers":{"type":"array"},"icon":{"type":"string"},"info_url":{"type":"string"},"slip44":{"type":"integer"},"wormhole_id":{"type":"integer","nullable":true},"avatar_url":{"type":"string","nullable":true},"evm_explorer_base_url":{"type":"string","nullable":true,"description":"HTTPS origin for EVM /token/0x… links (e.g. https://basescan.org)"},"deleted":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string"},"market_display_token_count":{"type":"integer"}}},"DappEntry":{"type":"object","description":"A dapp in the registry (list from GET /dapps/all)","properties":{"dapp_id":{"type":"string"},"name":{"type":"string"},"short_name":{"type":"string","description":"Optional compact label for explorer lists (falls back to name when absent)"},"icon":{"type":"string","description":"Icon URL"},"link":{"type":"string","description":"Dapp URL"},"description":{"type":"string"},"total_contracts":{"type":"integer"},"total_transactions":{"type":"integer"},"contracts_level0":{"type":"integer"},"user_transactions":{"type":"integer"},"total_alph_burn_fees":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"},"category_ids":{"type":"array","items":{"type":"string"},"description":"Up to 3 category ids"},"metadata":{"type":"object","description":"Optional JSON (ingest / admin merge)"}}},"AddressLabelIconSlot":{"type":"object","required":["url"],"properties":{"url":{"type":"string","description":"HTTPS CDN logo URL"},"hash":{"type":"string","nullable":true,"description":"SHA-256 hex of source image bytes when known"}}},"AddressLabelMainSummary":{"type":"object","description":"Primary label for an address (first row by `display_order`, then `label`, then `source`, matching GET `/addresses/{address}/labels`).","required":["label","source"],"properties":{"label":{"type":"string"},"source":{"type":"string"},"mapped_label":{"type":"string","description":"Mapped label when set (e.g. `exchange:gateio`)."},"icon":{"type":"string","description":"First logo URL when set (same as first entry of `icons` when present)."},"icons":{"type":"array","description":"Ordered logos when the primary label has more than one (e.g. LP pool). Omitted when absent or single-image.","items":{"$ref":"#/components/schemas/AddressLabelIconSlot"}}}},"SlimMainEventSummary":{"type":"object","description":"Primary normalized-event metadata for one transaction hash (used on block summaries).","properties":{"tx_hash":{"type":"string"},"dapp_id":{"type":"string","nullable":true},"category":{"type":"string"},"sub_kind":{"type":"string"},"type":{"type":"string","nullable":true}}},"BlockAlphscan":{"type":"object","description":"Alphscan enrichment on a block (genesis mint and coinbase main events when indexed).","properties":{"genesis_mints":{"type":"array","nullable":true,"items":{"$ref":"#/components/schemas/SlimMainEventSummary"}},"coinbases":{"type":"array","nullable":true,"items":{"$ref":"#/components/schemas/SlimMainEventSummary"}}}},"TransactionDetailAlphscan":{"type":"object","description":"Full normalized events plus optional per-transaction address label map for GET `/transaction/{transaction_id}`.","required":["events","meta"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/NormalizedEvent"}},"meta":{"type":"object","properties":{"payload_chunk_hydration_enabled":{"type":"boolean"}}},"address_labels":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/AddressLabelMainSummary"}}}},"AlphscanDecoration":{"type":"object","description":"Alphscan decoration on each Alephium transaction returned by Alphscan list endpoints (address, address+token, token, block transaction lists).\nAlways includes **main_event_pending**. When false, `dapp_id`, `category`, `sub_kind`, and `type` are set from the main normalized event (`is_main = true`) for that hash (and list filter where applicable). When true, those fields are omitted until indexing completes.\nOptional **address_labels** map involved addresses (inputs/outputs plus main-event `from` / `to` / `with` / `token_address`) that have a label in **address_label**.\n","nullable":true,"properties":{"main_event_pending":{"type":"boolean","description":"True when Alphscan has not yet indexed a main normalized event for this transaction hash in the context of this list endpoint (show a pending / hourglass state in UIs). False when `dapp_id`, `category`, `sub_kind`, and `type` are populated from that main event.\n"},"dapp_id":{"type":"string","nullable":true,"description":"DApp slug (e.g. `elexium-dex`, `wormhole`). Null when the tx is not associated with a known DApp."},"category":{"type":"string","nullable":true,"description":"Normalized event category (e.g. `dex`, `transfer`, `token`, `contract_life`, `oracle`)."},"sub_kind":{"type":"string","nullable":true,"description":"Event sub-kind within the category (e.g. `swap`, `add_liquidity`, `send_to_bridge`, `genesis_mint`, `oracle_update`)."},"type":{"type":"string","nullable":true,"description":"Event sub-sub-kind / type (e.g. `AMM_LP_TOKEN`). May be null."},"address_labels":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/AddressLabelMainSummary"},"description":"Map of Alephium address to primary label summary for addresses on this transaction that have at least one **address_label** row.\nOmitted when empty.\n"}}},"ContractAddressLabels":{"type":"object","required":["labels","primary"],"properties":{"labels":{"type":"array","items":{"type":"object","required":["address","label","source","display_order","is_primary","created_at","updated_at"],"properties":{"address":{"type":"string"},"label":{"type":"string"},"source":{"type":"string"},"mapped_label":{"type":"string"},"metadata":{"type":"object"},"icon":{"type":"array","items":{"$ref":"#/components/schemas/AddressLabelIconSlot"}},"display_order":{"type":"integer"},"is_primary":{"type":"boolean","description":"True for the primary label (same ordering as GET `/addresses/{address}/labels`)."},"created_at":{"type":"string"},"updated_at":{"type":"string"}}}},"primary":{"description":"Same object as the element of **labels** where **is_primary** is true.","allOf":[{"type":"object","required":["address","label","source","display_order","is_primary","created_at","updated_at"],"properties":{"address":{"type":"string"},"label":{"type":"string"},"source":{"type":"string"},"mapped_label":{"type":"string"},"metadata":{"type":"object"},"icon":{"type":"array","items":{"$ref":"#/components/schemas/AddressLabelIconSlot"}},"display_order":{"type":"integer"},"is_primary":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}}]}}},"AlephiumTransaction":{"type":"object","description":"Alephium transaction as returned by the explorer backend. For Alphscan decorated list endpoints (when the database is configured), each item includes an **alphscan** object with **main_event_pending** and optional main-event fields and **address_labels**.\n","properties":{"hash":{"type":"string","description":"Transaction hash (hex)"},"blockHash":{"type":"string"},"timestamp":{"type":"integer","format":"int64","description":"Block timestamp (ms since epoch)"},"inputs":{"type":"array","items":{"type":"object"}},"outputs":{"type":"array","items":{"type":"object"}},"gasAmount":{"type":"integer"},"gasPrice":{"type":"string"},"scriptExecutionOk":{"type":"boolean"},"coinbase":{"type":"boolean"},"alphscan":{"$ref":"#/components/schemas/AlphscanDecoration"}}},"NormalizedEvent":{"type":"object","properties":{"id":{"type":"string"},"schema_version":{"type":"integer"},"chain":{"type":"string"},"fromGroup":{"type":"integer"},"toGroup":{"type":"integer"},"block_number":{"type":"integer"},"tx_hash":{"type":"string"},"log_index":{"type":"integer"},"category":{"type":"string"},"sub_kind":{"type":"string"},"timestamp":{"type":"integer"},"from":{"type":"string"},"to":{"type":"string"},"amount":{"type":"string"},"token_address":{"type":"string"},"isMain":{"type":"boolean","description":"When true, this is the primary representative event for the transaction (e.g. swap, bridge transfer, mint)."},"address_labels":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/AddressLabelMainSummary"},"description":"Optional map of address to primary **address_label** for addresses on this event (`from`, `to`, `with`, `token_address`).\nOmitted when none apply.\n"}}}}}}