Public Data API
Endpoints
Every route with its parameters, defaults and ceilings, the cursor paging contract, the CSV renderer, and every field of every row shape returned.
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/fees/currencies | Lifetime protocol fees per currency as received, by source, with converted, ETH realised, forwarded, Safe-exchanged and burned | No | No | 15 |
/api/v1/fees/daily | Protocol fees per UTC day in each currency; by=currency or by=source; filters currency, source, product, from, to | Yes | Yes | 60 |
/api/v1/fees/receipts | Every protocol fee receipt, newest first, before conversion; filters currency, source, product | Yes | Yes | 15 |
/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 |
| Path | Returns | CSV | Cursor | s-maxage |
|---|---|---|---|---|
/api/v1/leaderboards/{creators|traders|kols} | One THD-paying board over a fixed UTC day, month or all time: each account’s measure and its THD credited and held from that board’s pot, with the pot’s days | No | No | 60 |
/api/v1/drops | Sponsored drops, newest first: pot, fee legs, terms, root, claims and clock | No | No | 15 |
/api/v1/drops/{drop} | One drop, its root and sweep history, the stored snapshot standings, and one account’s leaf and proof when account is sent | No | No | 15 |
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 |
/leaderboards/{creators|traders|kols} | window (day default | month | all) · day (YYYY-MM-DD, UTC, not in the future; default today) · month (YYYY-MM, not in the future; default this month) · page (1 to 100,000; default 1) · limit | 50 / 500 |
/drops | sponsor (address) · limit | 200 / 1000 |
/drops/{drop} | account (address; adds that account’s leaf) | — |
/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 14 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.
Row fields#
The fields below are the row shapes the list and single-resource endpoints return. A field typed wei or base units is a decimal string — see amounts. A timestamp field is an object { unix, iso }, where unix is a decimal string of seconds.
Launch#
| Field | Type | Note |
|---|---|---|
token, curve, creator, creatorFeeRecipient, factory | address | Lower-case. The factory may be a superseded generation |
launchId | integer string | The factory’s own sequence number |
force, forceName | number, LIGHT | DARK | null | The force’s registry id: 0 is LIGHT, 1 is DARK. forceName is null for any other id. Chosen at launch, permanent |
lifecycle | string | CURVE_TRADING, CURVE_COMPLETE, GRADUATED |
dev | boolean | An owner-created test launch. Excluded unless ?includeDev=true |
graduationTargetWei, initialBuyWei | wei | |
initialTokensBought | token base units | |
earlyWalletCap | { status, bps, seconds, untilGraduation } | The creator’s per-wallet cap: bps of total supply (50–250), seconds as an integer string, 4294967295 = until graduation. status: STORED | UNREADABLE | NOT_INDEXED; values null unless stored |
crewSplitter, crewMembers | address | null, number | null | Null on a launch made with no founding crew |
promotedPlacement, promotionPaidWei | number | null, wei | null | Marketing revenue. Never a protocol fee |
launchedAt, block, txHash | timestamp, integer string, hash | |
stats | object | null | null when no trade has been indexed for this launch — not a row of zeros |
stats.trades, .buys, .sells, .uniqueTraders, .holdersDerived | number | holdersDerived is a log-derived count, not a census |
raiseCurrency | object: address, isNativeEth, symbol, decimals | The unit of every amount on this launch. symbol and decimals are null when the index has no listing row for the currency |
stats.curveVolumeWei, .buyVolumeWei, .sellVolumeWei, .tradeFeeWei, .netRaisedWei | base units of raiseCurrency | Wei only when raiseCurrency.isNativeEth. Never add them across launches. netRaisedWei is the raised figure — never realEthReserve, which is zeroed at graduation |
stats.curveVolumeValue | object: ethValueWei, usdValueE18, pricedTrades, unpricedTrades, ethUnpricedTrades, oldestPricedAt, newestPricedAt, valuation | Curve volume at each trade’s event-time price (the CoinGecko price posted on chain and in force at its block). Trades with no price then are left out and counted. The VOLUME sort key |
stats.netRaisedValueWei | wei (may be negative) | netRaisedWei in ETH value, each trade at its own event-time price. The RAISED sort key |
stats.lastFdvWei, .lastPokeAt | wei | null, timestamp | null | null until a pool metrics poke exists. An unmeasured valuation, not a valuation of zero |
/api/v1/launches/{token} returns the same fields plus progressBps (derived from netRaisedWei / graduationTargetWei, capped at 10000, and forced to 10000 once graduated), progressNote, priorFactory, and graduation — which is null unless the launch has graduated, and otherwise carries ethWei, tokenWei, locker, positionId, sqrtPriceX96, block, txHash and at.
Trade#
| Field | Type | Note |
|---|---|---|
id | string | Stable row id. The tie-breaker inside a cursor |
side | BUY | SELL | REDEEM | A REDEEM is a refund out of a curve that never graduated. Filter on side before summing ethWei |
venue, venueKind | address, string | |
trader, recipient | address | |
ethWei, curveQuoteWei, tradeFeeWei | wei | ethWei − curveQuoteWei is the fee this trade actually paid, at the rate that applied at its block |
tokenWei | token base units | |
block, logIndex, txHash, at | integer string, number, hash, timestamp |
Holders#
| Field | Type | Note |
|---|---|---|
census | object | null | null when no census has ever completed. That is unknown, not zero — censusUnavailableReason says what would fix it |
census.holders, .countedSupplyWei, .candidates | number, wei, integer string | The on-chain sweep, with its floor and exclusion list applied |
census.countedAtBlock, .recordedAtBlock, .recordedAt, .txHash | integer string, integer string, timestamp, hash | No contract bounds a census’s age. The consumer decides what is too old, which is why both blocks are published |
derived.holders, .totalSupplyWei | number, wei | null | Non-zero balances in the indexer’s own projection. No floor, no exclusions, so it is always larger. Never mixed with the census |
derived.top[] | holder, balanceWei, transferCount, firstSeenBlock, lastChangeBlock | Largest balance first, up to limit |
Market#
| Field | Type | Note |
|---|---|---|
marketId | bytes32 | The id, not the clone address. address is the clone |
address, factory, oracle, creator | address (oracle may be null) | |
currency, currencyDecimals | address, number | null | The zero address is native ETH. Every amount on the row is in this currency’s base units |
question | string | Free text, written by the creator |
family, metric, comparator, subject, thresholdWei | number | null, address | null, integer string | null | The encoded predicate. Names are resolved on the single-market route |
status | OPEN | SETTLED | VOIDED | PAUSED | Three end states, not two. A settlement with one side empty is SETTLED, refunds everyone at par at zero fee, and is not a void |
paused, featuredTier | boolean, number | null | |
deadline, settlementWindowSeconds, createdAt, block | timestamp, number | null, timestamp, integer string | |
feeBps, marketingBps | number | null | One cut of the whole pot at settlement, not a per-stake fee. Zero in refund mode |
feeRecipient | address | null | PredictionMarketFactory itself, not a payout wallet. Treating it as one attributes every market’s fee to the factory |
stats | object | null | null when nothing has been staked yet |
stats.totalYes, .totalNo, .openInterest | base units of the row’s currency | openInterest is totalYes + totalNo, with the fee not deducted |
stats.paidOut, .refunded, .protocolFee, .marketingFee, .transferShortfall | base units of the row’s currency | transferShortfall is requested minus credited, summed — non-zero only for a fee-on-transfer currency |
stats.stakes, .stakers, .claims | number |
/api/v1/markets/{id} adds a predicate object that resolves the encoded ids to names, and a settlement object that is null until the market settles.
| Field | Values |
|---|---|
familyName | 0 lifecycle · 1 curve · 2 creator |
metricName | 0 GRADUATED · 1 CURVE_COMPLETE · 2 NET_RAISED_WEI · 3 TOKENS_SOLD_BASE_UNITS · 4 PROGRESS_BPS · 5 CURVE_FDV_WEI · 6 CREATOR_LAUNCH_COUNT · 7 CREATOR_GRADUATED_COUNT · 8 CREATOR_TIER · 9 SUPPLY_BURNED · 10 CURVE_TRADE_FEES_WEI · 11 PROTOCOL_FEES_METERED_WEI |
comparatorName | 0 EQ · 1 NEQ · 2 GT · 3 GTE · 4 LT · 5 LTE |
An id with no name resolves to null rather than to a label, so a new metric appearing on chain shows up as an unnamed id rather than as a mislabelled one.
Stake and settlement#
| Field | Type | Note |
|---|---|---|
id, marketId, user | string, bytes32, address | |
side, sideName | boolean, YES | NO | sideName is on the JSON rows; the CSV carries the name in side |
amountRequested, amountCredited | base units of the market’s currency | Sum amountCredited. It is the measured balance delta; the requested figure overstates a fee-on-transfer stake |
totalYesAfter, totalNoAfter | base units of the market’s currency | The running pools immediately after this stake |
block, txHash, at | integer string, hash, timestamp |
| Field | Type | Note |
|---|---|---|
id, marketId, oracle, settler | string, bytes32, address, address | settler is attribution only — settlement is permissionless and unpaid |
outcome | boolean | true is YES. The CSV renders it as YES / NO |
observedValue, thresholdWei | integer string | What the oracle read, against what the predicate required |
deadline, settledAt | timestamp | |
driftSeconds | signed integer string | settledAt − deadline. Negative is an early settle, which is legal where the predicate is already decided |
windowSeconds, windowElapsedBps | number | null | |
block, txHash | integer string, hash | The log’s own block. The settlement event carries no block number of its own |
Creators, KOLs, referrers, traders#
| Field | Type | Note |
|---|---|---|
creator | address | |
launches, graduations | number | Derived from logs |
netRaisedWei, volumeWei, creatorFeeWei, creatorFeeClaimedWei | wei | Derived from logs. Launches that raise in native ETH only |
volumeValueWei, unpricedTrades, unpricedReason, rankValueWei | wei | null, number | null, string | null, wei | Curve volume across every raise currency, each ERC-20 trade at its event-time price; unpriced trades left out and counted. rankValueWei is the ranking key |
registry.launches, .graduated, .netRaisedWei, .tier, .syncedAt | number | null, wei | null, timestamp | null | The registry’s own keeper-driven snapshot, which is what the chain gates a tier on. Never merged with the derived figures |
firstBlock, lastBlock | integer string |
/api/v1/creators/{address} adds registry.tierName, the creator rank name: 0 Unranked, 1 Whittler, 2 Fletcher, 3 Bowyer, 4 Artisan, 5 Master. The tier is derived on every read and never granted.
| Field | Type | Note |
|---|---|---|
account | address | |
allocatedWei, claimedWei | wei | ETH sources only. allocatedWei is what the chain actually paid, summed from allocation logs. No contract holds a lifetime total |
allocatedValueWei, unpricedAllocations, unpricedReason, rankValueWei | wei | null, number | null, string | null, wei | Every allocation, ETH and ERC-20 sources alike, each at its event-time price; unpriced ones left out and counted. rankValueWei is the ranking key |
allocations, windows, sources | number | |
registryFeesWei | wei | null | A different quantity from a different authority: an off-chain attestation, and the one the rank is computed from. The two are not reconciled on chain |
rank, rankRoute, banned | number | null, boolean | null | |
enrolled, xVerified, attestor | boolean | null, address | null | Assertions, not chain-verified facts. The address that asserted them is published beside them — see boundaries |
activeUntil | timestamp | null | Published because the registry’s eligibility check never reads it, so eligibility is not time-bounded |
| Endpoint | Fields |
|---|---|
/referrers | referrer · earnedWei (lifetime, from logs, ETH credits only) · earnedValueWei (ETH and ERC-20 credits at event-time price) · unpricedReceipts · unpricedReason · rankValueWei (the ranking key) · claimedWei · outstandingWei (earned minus claimed, JSON only) · attributedWei (the whole fee that passed through) · receipts · sources · firstBlock · lastBlock |
/referrers?window=7d|30d | The same fields summed over data.window only, ranked by earnedValueWei (rankValueWei equals it). claimedWei and outstandingWei are lifetime-only and absent, listed in data.lifetimeOnlyFields. CSV rows add window, windowFromUnix, windowToUnix |
/traders | trader · volumeWei · buyVolumeWei · sellVolumeWei · tradeFeePaidWei (all ETH launches only) · volumeValueWei (every raise currency at event-time price) · unpricedTrades · unpricedReason · rankValueWei (the ranking key) · trades · buys · sells · tokens · stakes · settlements · voids · firstBlock · lastBlock |
Event-time values#
| Field | Type | Note |
|---|---|---|
valuation.basis | ETH_PLUS_ERC20_AT_EVENT_TIME | ETH_ONLY_INDEX_PREDATES_VALUES | The second means the serving index has no value columns yet: figures are ETH only |
valuation.excludedEvents, valuation.scope | number | null, string | ERC-20 events left out for want of a price at their block. Never a zero for an unknown |
/stats curveVolumeWei, buyVolumeWei, sellVolumeWei, tradeFeeWei | wei | Native-ETH launches only |
/stats curveVolumeValueWei, buyVolumeValueWei, sellVolumeValueWei, erc20Trades | wei, number | Every raise currency at event-time price |
/stats/daily curveVolumeValueWei, tradesUnpriced, stakedValueWei, stakesUnpriced, valueUnavailableReason | wei | null, number, wei | null, number, string | null | null with a reason on a day written before the value columns existed. The day’s other …Wei fields are native ETH only |
/fees erc20ByCurrency[] | currency, symbol, decimals, tradeFee, creator, kol, referrer, toFeeConverter, launchFeeSwept | ERC-20 fee legs, per currency, in that currency’s base units. No ETH total is published for them |
| Field | Type | Meaning |
|---|---|---|
chainId, board, bucket | number, string, string | The board and the THD bucket its pot is: CREATORS, TRADERS or KOLS_REFERRERS |
period | object | kind, day or month, label, fromUnix (inclusive) and toUnix (exclusive); null is unbounded |
measure, totalMeasureWei | string, wei | What the board ranks on, in words, and the sum over every row |
total, page, limit | number | Rows on the board, and the page served |
rows[] | array | rank, account, measureWei, parts (each named part as …Wei), shareBps, unpriced, and thd: credited, creditedClaim, creditedQuest, held in THD base units |
pot | object | computedDays, heldDays, pot, credited, spoils, held, coverage (countedWei, touchedWei, or null), and days[] with each day’s status, code, reason and the same amounts |
heldIsEstimate, unpriced, unknownSubjects, notes | boolean, number, number, object | Whether held is an estimate on this board, ERC-20 legs left out for want of a price, and the units of every figure in words |
| Field | Type | Meaning |
|---|---|---|
live, reason | boolean, string | /drops only. false with a reason and an empty list when the index holds no drop data on this chain |
drop, factory, sponsor, token | address | The drop contract, its factory, who funded it, and the token it pays |
pot, snapshotDay, vestingSeconds, unclaimedRoute, feeOnTransfer | base units, number, number, number, boolean | The terms fixed at funding |
fee | object | tier, currencyShareBps, dropValueUsd18, tokenLeg, feeCurrency, currencyLeg |
funding | object | marketCapUsd18, usdPerToken18, registryCurrency, fixture |
terms | object | null | minPerRecipient, maxPerRecipient, boards; null until the index has stored them |
root, allocatedTotal, recipients, snapshotHash, vetoCount | bytes32 | null, base units | null, number | null, bytes32 | null, number | The published root and its totals |
claimedTotal, claimCount, sweptTotal, fundedAt, txHash | base units, number, base units, unix seconds, hash | Claims and sweeps so far, and the funding transaction |
clock, phase | object, string | windowEnd, publishDeadline, claimStart, firstClaimDeadline, finalDeadline (unix seconds or null); the phase is one of AWAITING_WINDOW, AWAITING_ROOT, ROOT_OVERDUE, VETO_WINDOW, AWAITING_TGE, CLAIMING, LATE_CLAIMS_ONLY, ENDED |
| Field | Type | Meaning |
|---|---|---|
roots[] | array, oldest first | kind (PUBLISHED | VETOED), root, allocatedTotal, recipients, reasonCode, timestamp, txHash |
sweeps[] | array, oldest first | route, destination, amount, reason, timestamp, txHash |
snapshot | object | asOfBlock and boards[], each with board and rows[] of account, rank, score, amount: the snapshot keeper’s stored standings |
leaf | object | null | Null without account. Otherwise account, amount, proof, parts[] (board, amount) and claimed; or code and reason when the account has no leaf |
| Endpoint | Condition | Code | Status |
|---|---|---|---|
/leaderboards/{board} | A board other than creators, traders, kols | API_V1_NOT_FOUND | 404 |
/leaderboards/{board} | A bad window, day, month, page or limit | API_V1_BAD_PARAMETER | 400 |
/drops | sponsor not an address, or limit outside 1–1000 | API_V1_BAD_PARAMETER | 400 |
/drops/{drop} | drop or account not an address | API_V1_BAD_PARAMETER | 400 |
/drops/{drop} | Not a drop the index holds on this chain | API_V1_NOT_FOUND | 404 |