Docs·Public Data API
Public Data API
Endpoints
Every route with its parameters, defaults and ceilings, the cursor paging contract, and the CSV renderer.
Endpoints#
The s-maxage column is the CDN’s window in seconds. Every response also carries max-age=0, so a browser always revalidates rather than serving a stale figure out of its own disk cache. CSV means the endpoint accepts ?format=csv; cursor means it pages with pagination.next.
| Path | Returns | CSV | Cursor | s-maxage |
|---|---|---|---|---|
/api/v1/health | Chain, environment, factories in scope, which reader variable answered, the /ready probe, and a row count per indexed table | No | No | 5 |
/api/v1/metrics | Every published figure’s derivation, and the figures that are deliberately not published | No | No | 300 |
| Path | Returns | CSV | Cursor | s-maxage |
|---|---|---|---|---|
/api/v1/stats | Lifetime launch and market counts, curve volume over all time / 24h / 7d / 30d, fees by leg, the fee meter, and open interest per currency | No | No | 15 |
/api/v1/stats/daily | The protocol’s UTC-day series, newest first | Yes | No | 60 |
/api/v1/fees | Fees by leg over a window, or by day | Yes | No | 15, or 60 with by=day |
/api/v1/thd/meter | The protocol fee meter, what the ceiling refused for good, and the THD unlock it drives — null when the denominator cannot be read | No | No | 15 |
| Path | Returns | CSV | Cursor | s-maxage |
|---|---|---|---|---|
/api/v1/launches | Every launch on every factory in scope, filterable and sortable | Yes | Yes | 15 |
/api/v1/launches/{token} | One launch, plus progressBps, its graduation row, and whether it sits on a superseded factory | No | No | 15 |
/api/v1/launches/{token}/trades | Curve trades, newest first. side is BUY, SELL or REDEEM | Yes | Yes | 15 |
/api/v1/launches/{token}/holders | The on-chain census (or null) and the log-derived balances, kept apart | Yes | No | 60 |
| Path | Returns | CSV | Cursor | s-maxage |
|---|---|---|---|---|
/api/v1/markets | Prediction markets, filterable by status, subject and currency | Yes | Yes | 15 |
/api/v1/markets/{id} | One market by its bytes32 id, with the predicate decoded and its settlement | No | No | 15 |
/api/v1/markets/{id}/stakes | Every stake on one market, newest first | Yes | Yes | 15 |
/api/v1/settlements | Settlements across all markets, optionally by settler | Yes | Yes | 15 |
/api/v1/settlements/rewards | The settler’s THD reward per settlement and per settler, as the feeder stored it | No | No | 15 |
| Path | Returns | CSV | Cursor | s-maxage |
|---|---|---|---|---|
/api/v1/creators | Creators by volume, with the registry’s own snapshot published beside the derived figures | Yes | Yes | 60 |
/api/v1/creators/{address} | One creator, with the tier name resolved | No | No | 60 |
/api/v1/kols | KOLs by lifetime allocation, with the registry attestation and its trust boundary | Yes | Yes | 60 |
/api/v1/referrers | Code-level referral aggregates. No referee is ever identified | Yes | Yes | 60 |
/api/v1/traders | The trading board. boardStatus is always PARTIAL | Yes | Yes | 60 |
/api/v1/points/{spending|earnings} | One frozen UTC day of a battlepass points board, shared ranks, fee value and pot share | No | No | 60 |
Parameters, sorting and paging#
| Endpoint | Parameters | limit default / max |
|---|---|---|
/launches | lifecycle (CURVE_TRADING | CURVE_COMPLETE | GRADUATED) · force (a force id the index holds, or LIGHT | DARK) · creator (address) · sort · includeDev · limit · cursor · format | 50 / 500 |
/launches/{token}/trades | side (BUY | SELL | REDEEM) · limit · cursor · format | 100 / 1000 |
/launches/{token}/holders | limit · format | 100 / 1000 |
/markets | status (OPEN | SETTLED | VOIDED | PAUSED) · subject (address) · currency (address) · limit · cursor · format | 50 / 500 |
/markets/{id}/stakes | limit · cursor · format | 100 / 1000 |
/settlements | settler (address) · limit · cursor · format | 100 / 1000 |
/creators, /kols, /traders | limit · cursor · format | 50 / 500 |
/referrers | window (7d | 30d | all) · limit · cursor · format | 50 / 500 |
/points/{spending|earnings} | day (YYYY-MM-DD, UTC; a frozen day, default the newest) · limit | 100 / 1000 |
/stats/daily | from, to (YYYY-MM-DD, UTC) · limit · format | 90 / 730 |
/fees | by (leg default, or day) · from, to · limit · format | 90 / 730 |
/health, /metrics, /stats, /thd/meter, /launches/{token}, /markets/{id}, /creators/{address} | None | — |
| Parameter | Behaviour |
|---|---|
| Enumerated values | Case-insensitive on input (?status=open is accepted) and matched against a fixed set. An unaccepted value is a 400 that lists the set |
| Addresses | Case-insensitive on input, lower-case on output. A malformed one is a 400 naming the parameter, the value and its length |
sort | Only on /launches: RECENT (default), OLDEST, VOLUME, RAISED |
includeDev | Included only when the value is exactly true. Anything else, including TRUE or 1, excludes dev launches |
from, to | UTC YYYY-MM-DD. On /fees?by=leg, to is clamped to the indexed block — a window never extends past what has been read |
window | Only on /referrers: all (default) is the lifetime board; 7d and 30d are the leaderboard’s windows, summed from each credit’s block time, with data.window.from inclusive and data.window.to exclusive. Later pages keep the first page’s window. An index without per-credit rows is a 404 API_V1_DATA_NOT_STORED, never lifetime totals |
limit | A whole number within the endpoint’s range. Out of range is a 400 naming the range and the default, and pointing at the cursor rather than at a larger limit |
cursor | See below |
Cursors are opaque and carry their query#
Paging is keyset, not offset: OFFSET re-scans, and on a table being written to continuously it silently repeats or skips rows at every page boundary. Pass pagination.next back as ?cursor= unmodified. It is base64url and its contents are not part of the contract.
pagination.next is null on the last page, and that is determined by the query reading one row beyond the page rather than by the page being full — so a page that happens to end exactly on the last row does not hand back a cursor that returns nothing.
CSV#
?format=csv on any of the twelve tabular endpoints returns RFC 4180 CSV with CRLF line endings and a Content-Disposition filename. Only json (the default) and csv are served; anything else is a 400 naming what was asked for and what is supported, rather than a silent fall back to JSON.
| Behaviour | Why it matters |
|---|---|
| Every cell is quoted | A wei figure is a twenty-something-digit integer. An unquoted numeric cell is converted to a float past fifteen significant digits by every spreadsheet, and the exact figure is gone before the reader has done anything |
A leading =, +, - or @ is prefixed with an apostrophe | A launch name comes from a creator and a market question is free text. Those characters start a formula in every spreadsheet program |
| The header comes from a declared column list | A row missing an optional field cannot shift every later column by one, which is the failure that makes a CSV look fine and reconcile wrong |
| No comment row | The freshness envelope travels in headers instead. A leading comment row breaks the CSV reader in every tool that has one |
| Header | Value |
|---|---|
x-thehood-as-of-block | freshness.asOfBlock |
x-thehood-coverage | FULL or PARTIAL. A partial export presented as complete is the failure the envelope exists to prevent |
x-thehood-scope | The scope, present only when there is one. Punctuation outside one byte is normalised, because an HTTP header value cannot carry an em dash |
x-thehood-notice | freshness.notice as code: headline. detail, present only when there is one. Normalised the same way |
All of those except x-thehood-scope are on the JSON responses as well, so a monitor or a curl -I can read freshness without parsing a body. Every one of them is named in Access-Control-Expose-Headers, so a browser on another origin can actually read it.