Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

HTTP API

The indexer serves a read-only JSON API. Amounts are decimal strings because u64 and u128 exceed the safe integer range of JSON numbers. spot_price and fee_apr are display-only f64 values.

Cross-origin

The API answers cross-origin only for the origins in INDEXER_ALLOWED_ORIGINS. Only GET and POST are allowed, without credentials. The refresh route is state-changing, so no wildcard is accepted. An empty list means same-origin only.

Caching

Every response carries an explicit Cache-Control. The indexer’s view is at most one poll old, so a lifetime longer than a poll adds staleness and nothing else.

RouteCache-Control
GET /pools, GET /pools/{id}public, max-age=5, must-revalidate
GET /pools/{id}/history at 1m or 5mpublic, max-age=5, must-revalidate
GET /pools/{id}/history at 1h, 6h, or 1dpublic, max-age=15, must-revalidate
GET /statusno-store
POST /pools/{id}/refreshno-store
Any non-success, including a 404no-store

A 404 is uncacheable on purpose: until the registry surfaces a pool, the indexer answers 404, and a stored copy would leave the pool page saying not found after the pool exists. The coarser history resolutions get a longer life because a bucket closes within its own period. Vary comes from the CORS layer and names the origin. A CDN in front of the API either honours these headers or bypasses its cache for the API path.

GET /status

Returns the indexer state.

FieldTypeMeaning
registry_idstring or nullRegistry account id, hex
last_registry_blocknumber or nullLast block a registry read covered
known_poolsnumberPool ids discovered from the registry
fetched_poolsnumberPools whose state has been fetched

GET /pools

Returns one page of pool summaries, keyset paginated by pool id.

QueryDefaultMeaning
tokennoneFaucet id, hex or bech32, to keep only pools holding it
limit50Page size, clamped to 1..=500
cursornoneThe next_cursor of the previous page

Response:

{
  "pools": [ { "id": "0x...", "...": "..." } ],
  "next_cursor": "0x..."
}

next_cursor is absent on the last page. The list omits each pool’s fee_schedule, which is the largest part of a summary and is only needed by a pool page.

GET /pools/{id}

Returns one pool summary with its fee_schedule and the newest history points. The response is the summary fields below, plus:

FieldTypeMeaning
fee_schedulearrayOne { root, amount } per priced note script root
historyarrayNewest snapshots, default 1m resolution

GET /pools/{id}/history

Returns the pool’s sampled history.

QueryDefaultMeaning
resolution1mOne of 1m, 5m, 1h, 6h, 1d

The response is an array of snapshot objects. An unknown resolution returns 400. Without a database the response is an empty array rather than an error: the pool itself is still served.

POST /pools/{id}/refresh

Marks one pool due at the next scheduler tick. Returns 202 on acceptance, 404 for an unknown pool id, and 429 with Retry-After when the per-pool cooldown or the global token bucket denies the request. The fetch happens on the tick, not inline.

Pool summary fields

FieldTypeMeaning
idstringPool account id, hex
token0, token1stringFaucet ids, hex
token0_symbol, token1_symbolstring or nullFaucet symbol
token0_decimals, token1_decimalsnumber or nullFaucet decimals
fee_asset_idstring or nullFaucet of the network note fee asset
fee_schedulearray or absent{ root, amount } per note script root; detail only
reserve0, reserve1stringReserves, vault balances minus the protocol pot
lp_supplystringLP supply
kstringreserve0 * reserve1 as u128
spot_pricenumberreserve1 / reserve0, display only
pot0, pot1stringAccrued protocol fees
lp_fee_bpsnumberThe pool’s LP fee tier
protocol_fee_share_bpsnumberThe pool’s protocol share
blocknumberBlock of the last state change
first_seen_unixnumberWall-clock second the indexer first saw the pool
last_change_unixnumberWall-clock second of the last state change
volume_24h_0, volume_24h_1stringTrailing 24 h volume per token
lp_fees_24h_0, lp_fees_24h_1stringTrailing 24 h LP fees per token
protocol_fees_24h_0, protocol_fees_24h_1stringTrailing 24 h protocol fees per token
swaps_24h, adds_24h, removes_24h, collects_24hnumberTrailing 24 h activity counts
fee_aprnumberAnnualised fee yield for liquidity providers, as a fraction
fee_apr_window_secsnumberSeconds the yield is annualised over

Fee APR

Fees accrue in whichever token the swapper paid, so both sides are valued in token0 at the pool’s own price before the ratio is taken. That price values the reserves at 2 * reserve0 in token0 terms, which is the capital the yield is taken against. The rate is annualised over fee_apr_window_secs, which is the pool’s age while it is below 24 hours. A pool watched for ten minutes reports ten minutes of yield stretched to a year.

Snapshot fields

FieldTypeMeaning
blocknumberBlock of the last state change in the bucket
timestampnumberThe pool’s block_timestamp_last
polled_atnumberWall-clock second the bucket opened
reserve0, reserve1stringState at the end of the bucket
open_reserve0, open_reserve1stringState at the bucket’s first sample
high_reserve0, high_reserve1stringReserves at the bucket’s highest price
low_reserve0, low_reserve1stringReserves at the bucket’s lowest price
lp_supplystringLP supply at the close
kstringConstant product at the close
pot0, pot1stringProtocol pot at the close
price0_cumulativestringCumulative price0 at the close
price1_cumulativestringCumulative price1 at the close

A snapshot’s timestamp is the pool’s block_timestamp_last, so it is zero for a pool that has never been operated on and unchanged across samples that saw no state change. reserve0 and reserve1 are the close of the bucket. The open and extreme reserves are stored as pairs because a price is a ratio of two reserves and only the pair reconstructs it exactly.