Resources
All endpoints are GET, unauthenticated, under https://api.hypersight.xyz/v1.
Every response includes generatedAt (epoch ms). See
Freshness.
What each one weighs
Sizes decide how you call this. The aggregates are small enough to poll; one curve is not, and the bulk export is a download, not a request.
| Resource | Typical | Largest seen |
|---|---|---|
manifest.json | 1 KB | — |
markets/{id}.json | 1.5 KB median | 3.9 KB |
markets/{id}/price.json | 9 KB | — |
governance.json | 10 KB | — |
changes.json | 44 KB | bounded at 500 entries |
openapi.json | 62 KB | — |
archive.json | 335 KB | grows daily |
events.json | 700 KB | grows daily |
markets/{id}/odds.json | 140 KB | 4.8 MB (145,048 points) |
markets/{id}/trade-odds.json | 130 KB | — |
bulk/markets.000.jsonl.gz | 247 KB gzipped | the whole archive |
A curve is the one thing that can surprise you. A busy market records a
point per price change at the feed’s ~5-second cadence, so odds.json runs
from a few KB to several MB. Read oddsMeta.points in the market document
first — it is there so you can decide before you fetch.
manifest.json
The archive’s table of contents. Also served at the API root (/).
{
"generatedAt": 1787000000000,
"freshness": "regenerated on market settlement (~1 min) and nightly; not continuous",
"license": {
"name": "CC BY 4.0",
"url": "https://creativecommons.org/licenses/by/4.0/",
"attribution": "Hypersight (hypersight.xyz)"
},
"coverage": { "firstExpiryMs": 1777788000000, "lastExpiryMs": 1787000000000 },
"counts": { "settledMarkets": 700, "settledEvents": 300, "marketFiles": 1000 },
"resources": ["/v1/archive.json", "/v1/events.json", "/v1/governance.json", "/v1/markets/{outcomeId}.json"]
}Counts and timestamps above are illustrative — the archive grows daily, and the live manifest is the only truthful copy of its own numbers.
archive.json
Every settled price market (crypto binaries and buckets), newest first.
| Field | Meaning |
|---|---|
outcomeId | HIP-4 outcome id (also the key for /v1/markets/{id}.json) |
underlying | BTC, ETH, SOL, HYPE, … |
period | Market cadence, e.g. 1d |
class | priceBinary (above/below target) or priceBucket (range) |
expiryMs | Expiry timestamp (epoch ms). Price markets always have one |
targetPrice | The strike the question was asked about |
settlePrice | The oracle price the market settled against |
result | up (YES won) or down (NO won) |
yesCoin / noCoin | The HIP-4 coin tickers, e.g. #10570 / #10571 |
bucketLabel | Range label for bucket legs, null for binaries |
totalVolume | Lifetime volume in USDC, YES and NO legs summed — everything the chain counted, including what nobody traded. For the order book alone, add buyNotional + sellNotional; do not subtract (see completeness) |
yesVolume / noVolume | The same dollars, split by which side was bought. null means never captured — not zero (see completeness) |
traders | Distinct wallets that traded this market, both legs unioned, from the on-chain index’s own fills. null means not swept yet — not zero |
splitNotional | Everything in totalVolume that is not a taker buy or sell: the settlement payout, plus merges, negations and minting. Protocol mechanics — no counterparty chose a price. Across the archive it is $208.3M of $498.2M |
buyNotional / sellNotional | Taker buys and sells, in USD, measured from the index’s own fill rows. Their sum is what changed hands. null until the fills sweep has covered the market — never 0 |
settleNotional | The settlement payout alone, inside splitNotional: the protocol redeeming winners at $1. Exposed separately because it is the one member of the lump a reader usually wants back — trading is $290.0M, trading plus the payout is $378.1M, and the $120.3M of merges, negations and mints is in neither |
tailNotional | The post-settle tail: dollars traded after settlement (the winner converging to $1, the losers draining). Already included in totalVolume — subtract it to compare with trackers that cut at settlement. null until the fills sweep has covered the market |
familyTraders | Distinct wallets across every leg of the market’s family (bucket ladder), as a set union — not the sum of each leg’s traders, which double-counts wallets that traded several ranges. Identical on every row of the same family; null on standalone markets |
events.json
Every resolved event market (macro decisions, sports fixtures, one-off questions), with the winning side and, for matches, the final score.
| Field | Meaning |
|---|---|
outcomeId | HIP-4 outcome id |
outcomeLabel | The outcome’s own label, e.g. No change. Distinct from questionTitle, which names the parent question |
side0 / side1 | The two sides as listed on-chain (usually Yes / No) |
winnerSide | 0 or 1: index of the winning side |
winnerLabel | The winning side’s label, resolved for you |
expiryMs | Scheduled expiry (epoch ms). null on every event row today: HL publishes no scheduled expiry for these markets. An outright such as 2026 World Cup Champion resolves when the tournament does, and a fixture resolves when it is played, neither on a date fixed in advance. Date and sort on settledAt |
settledAt | When the market resolved (epoch ms). Always present. This is the event market’s only timestamp |
questionTitle | The parent question, e.g. July Fed funds decision. null on standalone markets, where outcomeLabel is the market’s own name |
questionDescription | The full resolution rules, verbatim. null when the market resolved before we captured it, or when it never had any |
category | e.g. economics/N/A, sports/football. Read from the metadata tag Hyperliquid publishes in a market’s description. 14 markets carry a category we assigned ourselves: Hyperliquid listed them with a one-line description and no tag while naming it on their siblings in the same batch, so the value is taken from those siblings rather than left empty. Everywhere else it is Hyperliquid’s own |
totalVolume | Lifetime volume in USDC, YES and NO legs summed — everything the chain counted, including what nobody traded. For the order book alone, add buyNotional + sellNotional; do not subtract |
yesVolume / noVolume | The same dollars, split by which side was bought. null means never captured — not zero (see completeness) |
traders | Distinct wallets that traded this market, both legs unioned, from the on-chain index’s own fills. null means not swept yet — not zero |
familyTraders | Distinct wallets across every outcome of the same parent question, as a set union — not the sum, which double-counts wallets that traded several outcomes. Identical on every row sharing a questionTitle; null on standalone markets |
splitNotional | Everything in totalVolume that is not a taker buy or sell: the settlement payout, plus merges, negations and minting. Protocol mechanics — no counterparty chose a price. Across the archive it is $208.3M of $498.2M |
buyNotional / sellNotional | Taker buys and sells, in USD, measured from the index’s own fill rows. Their sum is what changed hands. null until the fills sweep has covered the market — never 0 |
settleNotional | The settlement payout alone, inside splitNotional: the protocol redeeming winners at $1. Exposed separately because it is the one member of the lump a reader usually wants back — trading is $290.0M, trading plus the payout is $378.1M, and the $120.3M of merges, negations and mints is in neither |
tailNotional | The post-settle tail: dollars traded after settlement (the winner converging to $1, the losers draining). Already included in totalVolume — subtract it to compare with trackers that cut at settlement. null until the fills sweep has covered the market |
homeTeam / awayTeam / homeScore / awayScore | Final score for sports fixtures, null otherwise |
Every field above is always present on every event row. Optional ones carry
null rather than disappearing, so the shape does not change from row to row.
archive/{YYYY-MM}.json and events/{YYYY-MM}.json
The same rows, sliced by the month a market resolved in. The whole-archive
documents stay the simplest way in, but they grow with the archive; these let
you fetch a slice, or backfill history once and never read it again. The
manifest’s shards array lists every month that exists, with its counts.
Both files exist for every month the manifest lists, with count: 0 and
an empty array when that month had none of that kind. So the obvious loop over
shards never hits a 404.
curl https://api.hypersight.xyz/v1/archive/2026-07.jsonchanges.json
The most recent resolutions, newest first: outcomeId, type, settledAt
and the market’s URL. Poll this instead of re-reading the aggregates.
It is deliberately bounded (500 entries). If your last sync is older than
oldestSettledAt, the feed cannot tell you what you missed, and it says so in
its own note field: re-read archive.json and events.json instead of
assuming the gap is empty.
bulk/manifest.json
Gzipped JSON Lines covering the whole archive, one market per line. A line is
the same document markets/{id}.json serves — market, dataQuality,
deployer, family, flow, oddsMeta, the series URLs and the settlement —
with outcomeId promoted to the top level, because a line has no URL to say
which market it is. Regenerated nightly. Ingest it once, then follow
changes.json.
The two heavy series ship beside it, one line per market, keyed by outcomeId:
odds.*.jsonl.gz and price.*.jsonl.gz. They are separate
files for the same reason they are separate resources: most callers want the
results, not the tapes.
All three are split by size, so read files rather than guessing chunk
names: marketChunks, oddsChunks and priceChunks say how many of each
exist, and the counts move as the archive grows.
# Fetch every chunk the manifest lists, whatever it is called
curl -s https://api.hypersight.xyz/v1/bulk/manifest.json | jq -r '.files[].url' | xargs -I{} curl -O https://api.hypersight.xyz{}openapi.json
An OpenAPI 3.1 description of this surface, generated with the live counts
and coverage window. Every response is described field by field, and the two
row shapes are named schemas (PriceMarket, EventMarket), so a generated
client comes out typed rather than as a bag of any.
npx @openapitools/openapi-generator-cli generate \
-i https://api.hypersight.xyz/v1/openapi.json -g typescript-fetch -o ./clientgovernance.json
Aggregated validator settlement activity: how many settlement actions were observed, vote counts, and the most active validators by address.
| Field | Meaning |
|---|---|
counts.byType | One entry per action type (register, settle) with its count |
counts.actions / finalized | Totals over all observed actions |
counts.votes / validators | Total votes recorded, and how many distinct validators cast them |
counts.lastActionAt | When the newest action was last observed. Published because a governance feed that STOPS looks identical to a healthy one from every count — a dead feed is finalized by definition, so “278 actions, 278 finalized” is both the picture of health and the signature of the failure. Only this date separates them |
topValidators | The most active validators: address, actions voted on, and their own medianLagMs / lagSamples / lagBounded / openingBeatVotes |
voteLag | How long validators take to vote, measured from the action’s opening (see below) |
recent | The 30 latest actions: id, type, title, reason, quorumReached, finalized (0/1), lastSeen |
voteLag
The zero of this axis is the action’s opening, which Hyperliquid does not
publish: it is derived as expireTime - votingWindowMs. That makes one field
load-bearing.
| Field | Meaning |
|---|---|
medianMs | Median lag across every measured vote. null below minSamples |
samples / bounded | Measured votes behind the median, and votes excluded from it because they are upper bounds rather than measurements |
lagResolutionMs | Sampling interval. Below it, vote ORDER is not observable — two validators inside one interval are not comparable |
basis | Where the zero sits (actionOpening) |
votingWindowMs | The assumed window between opening and expiry |
windowViolations | Actions that outlived that window. Must be 0 — anything else means the window changed and every lag here is off by the same amount, with nothing else looking wrong |
minSamples | No median is published below this many measured votes |
This file also carries n, quorum_reached and last_seen as deprecated
aliases of count, quorumReached and lastSeen. They are the raw column
names, kept only because v1 promises nothing disappears. Read the camelCase
ones; a future major version drops the others.
markets/{id}.json
One market in full: the page most builders want.
| Field | Meaning |
|---|---|
type | price or event |
market | The market’s row, exactly as in archive.json / events.json |
dataQuality | The document’s own report card: { complete, missing }. missing lists reason slugs — odds-none (no curve at all), price-series, volume-split, settlement-votes, fills. complete is simply missing.length === 0 |
deployer | Who deployed the market: { address, name, protocol }. Protocol markets (every market until permissionless deployment opens) carry address: null, name: "Hyperliquid", protocol: true; third-party markets carry the deployer address and, when our registry names it, a display name. Docs written before the field shipped simply lack it — absence means protocol |
family | The other legs of the same question: totalVolume across all of them and outcomeIds listing every one. null when the market stands alone |
priceMeta | Summary of what the underlying did while the market was live, at 5-minute resolution: { interval, points, firstTs, lastTs }. null on event markets, which have no ticker, and on markets whose window predates this capture |
priceUrl | Path to that series, or null in the same two cases |
oddsMeta | Summary of the odds series: points, firstTs, lastTs, gaps (a count), maxGapMs, complete, captureRegime and source (see coverage) |
oddsUrl | Path to the series itself, or null when nothing was captured |
tradeOddsMeta | Summary of the TRADE odds: every real transaction price from the raw fills archive (YES coin, buys and sells only, consecutive identical prices collapsed). A different instrument from the sampled mid above, never blended with it — it exists even for markets that settled before the mid capture was born. null = no real trades to derive from |
tradeOddsUrl | Path to markets/{id}/trade-odds.json, or null |
flow | Fills-derived aggregates — traders, fees, notionals, the post-settle tail and four derived stats. The richest field of the doc, so it has its own section. null until the fills sweep has covered the market — not zero |
settlement | The settlement action: reason, quorumReached, finalized, the timestamps, and voterCount. null when none was captured |
settlementUrl | Path to the voter roster, or null. See markets/{id}/settlement.json |
settlementApplicable | Whether this market class settles by validator vote at all. false on every price market: they settle from the oracle (see coverage) |
settlementCaptured | false means the votes were never captured, not that nobody voted. Only meaningful when settlementApplicable is true |
curl https://api.hypersight.xyz/v1/markets/813.json{
"generatedAt": 1787097654338,
"type": "event",
"dataQuality": { "complete": true, "missing": [] },
"market": {
"outcomeId": 813,
"questionTitle": "World Cup Semifinal: France vs Spain",
"side0": "France", "side1": "Spain",
"winnerSide": 1, "winnerLabel": "Spain",
"homeTeam": "France", "homeScore": 0, "awayTeam": "Spain", "awayScore": 2,
"expiryMs": null, "settledAt": 1784055600000,
"totalVolume": 8121997,
"yesVolume": 2301278, "noVolume": 5820719,
"tailNotional": 4927922,
"traders": 1403
},
"family": null,
"oddsMeta": {
"points": 1095, "firstTs": 1783754570921, "lastTs": 1784062640022,
"gaps": [{ "fromTs": 1783756269650, "toTs": 1783757376985 }, "… 66 in total"],
"complete": false, "captureRegime": "event-5s", "source": "book-archive"
},
"oddsUrl": "/v1/markets/813/odds.json",
"tradeOddsMeta": { "points": 8189, "firstTs": 1783755987011, "lastTs": 1784070782196 },
"tradeOddsUrl": "/v1/markets/813/trade-odds.json",
"settlement": {
"quorumReached": true,
"voters": [{ "validator": "0x8a5d…", "name": "Hyperdash", "stakePct": 2.05, "firstSeen": 1784064279788 }, "… 14 in total"]
},
"settlementApplicable": true,
"settlementCaptured": true
}A verbatim snapshot of the live document (19 Aug 2026), trimmed where marked —
not a cleaned-up ideal. This market is complete: false on purpose: an archive
that claims completeness it does not have is worse than one that reports its
own holes, and dataQuality exists so you never have to guess.
The flow object
Every figure below is measured per fill from our raw archive, deduplicated per trade: the index serves one row per participant, two per trade.
{
"fills": 8697,
"traders": 1016,
"fee": 4.97,
"builderFee": 4.97,
"buyNotional": 1615840.34,
"sellNotional": 391210.73,
"splitNotional": 1366973,
"tailNotional": 1979720.84,
"tailFills": 1886,
"deduplicated": true,
"vwapYes": 0.66,
"vwapNo": 0.26,
"biggestFill": 99999.99,
"bestEntryPx": 0.299
}| Field | Meaning |
|---|---|
fills | Distinct trades across both legs, deduplicated by trade id — not raw participant rows |
traders | Distinct wallet addresses across both legs |
fee / builderFee | USD. Charged on-chain in outcome-token shares and valued at each fill’s own price; buying is free on outcome markets, so fees are sell-side by construction. builderFee is the part routed through builder codes — the two were identical until Hyperliquid’s August fee change introduced a protocol share |
buyNotional / sellNotional | Notional of taker-buy / taker-sell trades, USDC |
splitNotional | Everything that is not a taker buy or sell — protocol mechanics rather than order-book matching. Measured across all 1,012 markets: settlement 43.5%, merge outcome 28.1%, negate outcome 14.9%, minting 10.2%, merge question 3.3%. Despite the field name, minting is its smallest meaningful part and settlement its largest. The three notionals sum to the market’s totalVolume; subtract this one for an order-book-only figure |
tailNotional / tailFills | The post-settle tail: dollars moving after settlement. Already included in the totals above — subtract it to compare with trackers that cut at settlement. Note that 44% of it is the protocol settling positions rather than late trading, so it is not a “post-settle trading” figure |
deduplicated | true = per-trade figures with USD fees. false = an early sweep row not yet recomputed; treat its notional as inflated |
vwapYes / vwapNo | Volume-weighted average price per coin across its real trades, splits excluded. null until derived |
biggestFill | Largest single fill by notional, USD. null until derived |
bestEntryPx | Cheapest real buy price of the winning side — what the best entry actually paid per share. Fills under Hyperliquid’s $10 order minimum are ignored as dust. Only derivable once the winner is known |
markets/{id}/odds.json
The odds series on its own, because a long-running market carries tens of
thousands of points (~1 MB uncompressed) that most consumers do not need.
Fetch it only when oddsMeta.points > 0.
{
"generatedAt": 1787097654338,
"outcomeId": 813,
"points": 1095,
"odds": [ { "ts": 1783754570921, "px": 0.5 }, "…" ]
}Each point is the YES side’s mid price on the 0 to 1 probability scale. How
densely they were recorded, and by whom, is in oddsMeta.captureRegime and
oddsMeta.source — see
Resolution and provenance.
markets/{id}/trade-odds.json
The TRADE odds: every real transaction price of the YES coin, based on
the fills archive (buys and sells only, consecutive identical prices
collapsed). Same shape as odds.json plus one extra field: volumeBuckets,
~48 adaptive buckets of { t, yes, no } traded notional across the market’s
life, from the same deduplicated fills (absent on files derived before the
histogram shipped). Its own file and its own name: a
different instrument from the sampled mid, never blended with it. Fetch it
when tradeOddsMeta is non-null; it exists even for markets that settled
before the mid capture was born.
curl https://api.hypersight.xyz/v1/markets/141/trade-odds.jsonmarkets/{id}/settlement.json
Which validators voted the settlement, with the name and stake weight each carried at vote time.
{
"generatedAt": 1787356995910,
"outcomeId": 674,
"found": true,
"reason": "FIFA officially declared France the winner of the Game.",
"quorumReached": true,
"finalized": true,
"voters": [
{ "validator": "0x0000…acb8", "name": "ValiDAO", "stakePct": 1.5, "firstSeen": 1784160139953 }
]
}Fetch it when settlementUrl is non-null. The market document keeps the verdict
and a voterCount; only the roster lives here.
This is the only surviving copy. Hyperliquid serves votes while a settlement action is in flight and keeps nothing afterwards. One market settled before this capture existed and its roster is gone for good — no source anywhere can reconstruct it.
curl https://api.hypersight.xyz/v1/markets/674/settlement.jsonmarkets/{id}/price.json
What the underlying did over the window the market was live, at 5-minute resolution — Hyperliquid’s own price, the one the market settled against, not another venue’s. Frozen at settlement and never recomputed.
{
"generatedAt": 1787330633626,
"outcomeId": 3,
"interval": "5m",
"points": [ { "t": 1777960800000, "c": 1823.4 }, "…" ]
}Fetch it when priceUrl is non-null. It is null in two cases, and they are
different: event markets have no ticker at all, and a handful of price
markets closed before this capture existed.
curl https://api.hypersight.xyz/v1/markets/3/price.jsonAnything outside /v1 on this hostname returns a JSON 404.
A 403 applies to a caller, not to a resource: an address lands there after
abuse and every path answers the same way. There is nothing to retry, and it is
never about authentication — this surface needs no credentials.