Asset analytics
/api/asset/[asset]/riskFREEcache 30s
Realized vol + max drawdown + sharpe from the store
Log-return risk metrics computed inline from the sovereign history store. Falls back to an empty result when the store has fewer than `minBars` observations.
Query parameters
| Name | Type | Required | Description |
|---|
minBars | integer | no | Drop threshold for store→fallback switch. Default 30, cap 5000. |
Response shape
{ ok, asset, kind, venue, storeKey, source: 'store' | 'fallback', periodsPerYear, minBars, metrics: {bars, returns, meanLogReturn, realizedVol, annualizedVol, annualizedReturn, sharpe, sharpeAdjAC, ulcerIndex, painIndex, modifiedVar95, martinRatio, cdar95, gainToPain, sterlingRatio, omega, rollSpreadBps, maxDrawdown, peakPrice, troughPrice, drawdownBars} }Sample curl
curl 'https://hypo.markets/api/asset/hl-BTC/risk?minBars=30'
/api/asset/[asset]/slippageFREEcache 10s
Order-book walking simulator — avg fill, slippage in bp, tier breakdown
Walks the live order book (HL L2 or PM CLOB) and reports the volume-weighted average execution price, signed slippage versus mid, per-bp tier breakdown, and worst-fill level for the requested size.
Query parameters
| Name | Type | Required | Description |
|---|
size | number | yes | Quote (USD) or base (contracts), per sizeUnit. > 0, ≤ 1B. |
side | enum | yes | "buy" or "sell". |
sizeUnit | enum | no | "quote" (default, USD notional) or "base" (contracts). |
Response shape
{ ok, asset, kind, venue, generatedAt, mode: 'live', params, result: {side, midPrice, topPrice, baseFilled, quoteFilled, remaining, fullyFilled, avgPrice, slippageBps, worstFillPrice, worstFillBps, levelsConsumed, tiers: [{bpsFrom, bpsTo, baseFilled, quoteFilled}]} }Sample curl
curl 'https://hypo.markets/api/asset/hl-BTC/slippage?size=10000&side=buy'
/api/asset/[asset]/cascadesFREEcache 15s
Liquidation-cascade detector (price-only proxy)
Walks records and flags clusters where price falls (or rises with direction=up) by >= minDrawdownPct off a trailing windowMs peak/trough. Useful for spotting candidate forced-unwind events. CAVEAT: no exchange liquidation feed wired — purely a price-based proxy.
Query parameters
| Name | Type | Required | Description |
|---|
windowMs | integer | no | Trailing window ms. Default 60000, cap 86400000. |
minDrawdownPct | number | no | Threshold drawdown fraction, in (0, 1). Default 0.01. |
direction | enum | no | "down" (default) or "up". |
fromMs | integer | no | Inclusive lower bound (epoch ms). |
toMs | integer | no | Inclusive upper bound (epoch ms). |
limit | integer | no | Max records read, default 5000, cap 50000. |
Response shape
{ ok, asset, kind, venue, storeKey, params, summary: {clustersFound, deepestDrawdownFrac, totalCascadeBars, direction}, cascades: [{tStart, tEnd, bars, peakPrice, troughPrice, drawdownFrac}] }Sample curl
curl 'https://hypo.markets/api/asset/hl-BTC/cascades?windowMs=60000&minDrawdownPct=0.005'
/api/asset/[asset]/streamPROcache 0s
SSE live data push for an asset (replaces client polling)
Server-Sent Events stream emitting one event per asset-pulse update — the live price/snapshot fanned out from a single upstream fetch to all subscribers. Premium realtime tier; charged per stream-connect when prepaid billing is enabled.
Response shape
text/event-stream: one JSON data: frame per pulse; ': connected' initial comment; ': heartbeat' every 25s
Sample curl
curl -N 'https://hypo.markets/api/asset/hl-BTC/stream'
/api/asset/[asset]/stream-flowPROcache 0s
SSE live order-flow delta (tick-rule classified)
Server-Sent Events stream emitting one event per asset-pulse update. Each event carries the new price, prev price, side (buy/sell/unclassified), signed weight, and per-connection cumulative. Per-client state — comparing cumulatives across clients is meaningless.
Response shape
text/event-stream: { t, p, prevP, v, weight, side, signed, cumulative } per event; ': connected' initial comment; ': heartbeat' every 25sSample curl
curl -N 'https://hypo.markets/api/asset/hl-BTC/stream-flow'
/api/asset/[asset]/flowFREEcache 15s
Order-flow imbalance via the tick rule (Lee-Ready 1991)
Classifies each recorded tick as buy- or sell-initiated using the price tick vs the previous record; zero ticks inherit the prior direction. Reports buy/sell volume, imbalance ratio, a VPIN-lite order-flow toxicity score in [0,1] (mean absolute imbalance across non-overlapping rollingWindow buckets — persistent one-sided pressure does not wash out the way it does in the net imbalance), full per-record series with cumulative delta, and a trailing rollingDelta array for charting.
Query parameters
| Name | Type | Required | Description |
|---|
fromMs | integer | no | Inclusive lower bound (epoch ms). |
toMs | integer | no | Inclusive upper bound (epoch ms). |
limit | integer | no | Max records read, default 5000, cap 50000. |
rollingWindow | integer | no | Window size for rolling delta, default 60, max 5000. |
Response shape
{ ok, asset, kind, venue, storeKey, params, summary: {bars, buyBars, sellBars, unclassifiedBars, buyVolume, sellVolume, netDelta, imbalance, vpin, hasRealVolume, impactLambda:number|null, impactLambdaBps:number|null, impactFromRealVolume}, series: [{t, side, weight, signed, cumulative}], rollingDelta, rollingWindow }Sample curl
curl 'https://hypo.markets/api/asset/hl-BTC/flow?rollingWindow=120'
/api/asset/[asset]/volprofileFREEcache 30s
Volume profile + POC from the sovereign store
Builds a price-volume histogram from the recorded observations. For each price bin: bar count + cumulative volume (or count-weighted when records carry no volume). POC (point of control) is the highest-volume bin and gets isPoc:true.
Query parameters
| Name | Type | Required | Description |
|---|
priceStep | number | yes | Bin width in price units; must be > 0. |
fromMs | integer | no | Inclusive lower bound (epoch ms). |
toMs | integer | no | Inclusive upper bound (epoch ms). |
limit | integer | no | Max records read, default 5000, cap 50000. |
Response shape
{ ok, asset, kind, venue, storeKey, params, recordsUsed, hasRealVolume, pocIdx, buckets: [{priceLow, priceHigh, count, volume, isPoc}] }Sample curl
curl 'https://hypo.markets/api/asset/hl-BTC/volprofile?priceStep=100'
/api/asset/[asset]/carryFREEcache 60s
HL funding-rate carry — hourly + annualized + side breakdown
Per-hour funding rate, annualised rate, and per-side carry view (long + short) with days-to-1% and days-to-10% horizons. HL perps only; other kinds 404 with an explanatory message.
Response shape
{ ok, asset, kind: 'hl-perp', venue, coin, markPx, generatedAt, snapshotAgeMs, carry: {fundingHourly, fundingAnnualizedFrac, longSide, shortSide, flat} }Sample curl
curl 'https://hypo.markets/api/asset/hl-BTC/carry'
/api/statsPROcache 15s
Tier-1 statistical metrics for the curated cross-venue asset set
Per-asset return/risk statistics over a 30d window. returnMode is LOG for HL perps (price levels, $) and DIFF for bounded probability series (PM/Kalshi/HL-pred) — Sharpe/Sortino/Calmar are SUPPRESSED on binary venues (√periodsPerYear annualisation is dimensionless; a `horizon` block with daysToResolve/perDayMove/terminalVariance is emitted instead). periodsPerYear is fixed at 8760. Results are cached ~20s in-process; `cached` + `resultsAgeMs` disclose staleness. `coverage`/`perVenue` describe which venues this engine actually has (a sovereign engine narrows). Each result carries `type` (the venue/kind discriminant, e.g. hl-perp) — there is no separate `venue` field and `stats` is FLAT (no nested `returns`). Shares the returnMode convention with the m2m bundle, but NOTE the window/cadence differ: this endpoint uses 30d of 1h candles (periodsPerYear 8760), while the bundle's risk block uses its own 24h history window annualised by a CADENCE-DERIVED periodsPerYear — so realizedVol is comparable in magnitude but not identical; don't cross-map the two as the same number.
Query parameters
| Name | Type | Required | Description |
|---|
venue | string | no | Restrict to one of hl/hl-pred/pm/kalshi. |
max | integer | no | Cap the curated asset count. |
Response shape
{ now, elapsedMs, cached, resultsAgeMs, requested, returned, venue, coverage, perVenue, snapshot, results: [{asset, type, name, markPx, changePct, stats: {n, returnMode, framing, annualisedVol, sharpe|null, sharpeSuppressedReason, sortino, var95, es95, maxDrawdown, hurst, autocorr1, halfLifeMR, verdict, horizon?}}] }Sample curl
curl 'https://hypo.markets/api/stats?venue=kalshi&max=5'
/api/m2m/indexFREEcache 60s
M2M discovery — every asset a bot can query, grouped by venue
Returns the full asset universe a bot can pass to /api/m2m/[asset]/bundle or /api/m2m/batch. Each entry carries the asset id, venue, kind, lastPrice and isStale hint so a bot can pre-filter (e.g. 'only fresh hyperliquid perps') before committing to per-asset round-trips. Cached 60s — the universe changes slowly.
Response shape
{ ok, generatedAt, apiVersion, scope, summary:{total, byVenue, freshCount, staleCount}, generatedAtMs, filters:{kind:string[], fresh:boolean, minBasisBps:number|null, limit:number|null, offset}, returned, truncated, entries:[{asset, venue, kind, lastPrice, name:string|null, isStale, fairPrice:number|null, basisBps:number|null}] · params: ?kind=perp|binary|pred (CSV) ?fresh=true ?minBasisBps=N (cross-venue mispricing screen: perp mark-vs-oracle basis + binary cross-venue consensus edge) ?limit=N ?offset=N, bundleEndpoint, batchEndpoint }Sample curl
curl 'https://hypo.markets/api/m2m/index'
/api/m2m/batchFREEcache 0s
M2M batch — many bundles in one round-trip (portfolio scan)
POST {assets:[id, id, ...]} (max 50 per request) and get back an array of bundles. Server-side composition lets the snapshot fan-out and assetIndex cache reuse across all assets in the batch, saving disk reads vs N independent /bundle calls. Per-asset errors don't fail the batch: each item is either a successful bundle or {ok:false, asset, error}. CORS preflight (OPTIONS) supported for browser-based bots.
Response shape
{ ok, generatedAt, apiVersion, requestedCount, bundles:[ ...bundle | {ok:false, asset, error} ] } — each successful bundle has the same shape as /api/m2m/[asset]/bundle (freshness.historyLastEverMs included; series?:{...} when body.series=true)Sample curl
curl -X POST -H 'Content-Type: application/json' -d '{"assets":["hl-BTC","hl-ETH"]}' 'https://hypo.markets/api/m2m/batch' # add ,"series":true to bundle sparkline data on every item/api/m2m/[asset]/stream-signalPROcache 0s
M2M SSE — push signal updates as the asset pulse refreshes
Server-Sent Events stream of freshly-composed M2M bundles. Bots subscribe once, get signal updates pushed every time the asset's pulse refreshes (cadence floor 1500ms, idle bump every 15s during quiet periods). Same bundle shape as the REST /bundle endpoint — bots can pipe both through the same parser. Per-connection state tracked server-side. Heartbeat comment every 25s for proxy keepalive.
Response shape
text/event-stream — each data: line is a JSON M2MBundle with an added `cause` field ("init"|"pulse"|"idle")Sample curl
curl -N 'https://hypo.markets/api/m2m/[asset]/stream-signal'
/api/m2m/[asset]/bundlePROcache 15s
M2M unified bundle — one round-trip, every signal a bot needs
Machine-to-machine endpoint for AI agents and trading bots. Composes price, freshness, risk metrics, flow lean, carry hint, synthesized direction + confidence, and a venue-native URL with suggested side. HYPO is data-only — bots execute on the venue's native API via tradeHint.venueNativeUrl. Versioned: response always carries apiVersion. Sub-15s polling cached at the CDN; faster cadence consumers should use the per-asset SSE streams.
Response shape
{ ok, generatedAt, generatedAtMs, apiVersion, schema:{version, optionalBlocks[]}, asset, venue, storeKey, freshness:{feedAgeMs, historyLastMs, historyLastEverMs, isStale}, name:string|null, price:{last, bid, ask, spreadBps, change24hPct, unit:'usd'|'probability', change24hSource:'snapshot'|'store-delta'|null, fairValue:number|null, basisBps:number|null}, fairValue:{value:number|null, unit:'usd'|'probability', basisBps:number|null, source:'hl-oracle'|'consensus'|'none', confidence:number|null, dispersionBps:number|null, nVenues:number|null, isStale}, liquidity:{liquidityUsd, openInterestUsd, volume24hUsd, volumeTotalUsd, source:'snapshot'|null}, horizon:{endDate, daysToResolve, resolvedFrom:'closeTime'|'endDate'|null, terminalVariance}|null, risk:{realizedVolAnnualizedPct, maxDrawdownPct, sharpe, ulcerIndexPct, painIndexPct, modifiedVar95Pct, martinRatio, cdar95Pct, gainToPain, sterlingRatio, omega, rollSpreadBps, barsUsed, source:'store'|'fallback'|'insufficient', returnBasis:'log'|'diff'|null, windowMs, periodsPerYear}, flow:{imbalance, lean:'BID'|'ASK'|null}, carry:{fundingAprPct, side:'longs_pay'|'shorts_pay'|'flat'}, signals:{direction:'LONG'|'SHORT'|'NEUTRAL', confidence, reasons[]}, tradeHint:{venueNativeUrl, suggestedSide:'BUY'|'SELL'|null, notes[]}, series?:{prices[], points, windowMs} (opt-in via ?series=true) }Sample curl
curl 'https://hypo.markets/api/m2m/[asset]/bundle' # try hl-BTC, pm-trump-2024, or any other asset id
/api/feedFREEcache 4s
Apex feed: the full HL + PM + Kalshi snapshot with ages and stale flags
The same FeedSnapshot every server-side page reads via readFeed(). Includes per-venue snapshots, ages in ms, stale booleans (gated by STALE_THRESHOLD_MS = 120s), and the last error per venue. Force-dynamic; consumers should respect the cache-control header.
Response shape
{ ok, hyperliquid, polymarket, kalshi, limitless, ages:{hyperliquid, polymarket, kalshi, limitless}, stale:{hyperliquid, polymarket, kalshi, limitless}, errors:{hyperliquid, polymarket, kalshi, limitless}, bodyAgeMs } // bodyAgeMs: age of this (≤1s micro-cached) body. Kalshi markets also carry volume24hUsd (price-weighted $) + volume24hContracts (raw count).Sample curl
curl 'https://hypo.markets/api/feed'
/api/asset/[asset]FREEcache 10s
Per-asset dashboard payload — candles + book/history + snapshot
The composite payload powering /feed/[asset]'s server-rendered dashboard. Includes raw quote/market/prediction object, candles or price-history series, and the live order book (HL perps only). The shape varies by asset kind (hl-perp / hl-pred / pm / kalshi) — discriminate on the `type` field.
Query parameters
| Name | Type | Required | Description |
|---|
asset | string | yes | Path parameter — asset id (hl-BTC, pm-{slug}, kalshi-{ticker}, hl-pred-{slug-or-outcomeId}). |
Response shape
{ ok, asset, type: 'hl-perp'|'hl-pred'|'pm'|'kalshi', now, snapshot:{fetchedAt, ageMs, stale}, ...kindSpecificFields }Sample curl
curl 'https://hypo.markets/api/asset/hl-BTC'
/api/asset/[asset]/statsPROcache 15s
Pre-computed analytical statistics — Sharpe, Sortino, Calmar, Hurst, VaR, ES
Heavier statistical pack than /api/asset/[asset]/risk: includes Sharpe + Sortino + Calmar + AC-adjusted Sharpe (Lo 2002) + Omega + Hurst + ACF + ADF + KPSS + variance ratio + Jarque-Bera + Ljung-Box (+ a lag [1,2,3,5,10] LB profile) + Roll (1984) implied spread (bps) + Ulcer Index + multi-tail Expected Shortfall (es90/es95/es99 + tail-concentration) + Brier-on-self-history + drawdown summary. Computed from upstream candles (no store dependency). NOTE: for binary venues (PM, Kalshi, HL-pred) the response is HORIZON-FRAMED — annualised Sharpe/Sortino/Calmar/AC-Sharpe are suppressed (null, with returns.framing='horizon' + sharpeSuppressedReason) because √periodsPerYear scaling is dimensionless on a bounded [0,1] probability; a `horizon` block (daysToResolve, perDayMove, perHorizonMove, terminalVariance=p(1−p), resolvedFrom, available) keyed to time-to-resolution is returned instead. HL perps remain annualised (framing='annualised', horizon=null). Omega/Ulcer/Roll-spread/multi-tail-ES/LB-profile are emitted for BOTH framings (not √T-annualised).
Query parameters
| Name | Type | Required | Description |
|---|
asset | string | yes | Path parameter — asset id. |
Response shape
{ ok, asset, type, now, snapshot, stats:{...analyticalMetrics, returns:{sharpe:number|null, sortino:number|null, calmar:number|null, sharpeAdjAC:number|null, omega:number|null, gainToPain:number|null, annualisedVol, returnMode:'log'|'diff', framing:'annualised'|'horizon', sharpeSuppressedReason:string|null}, risk:{var95, var99, es95, es90, es99, esTailConcentration:number|null, ulcerIndex, cdar95, drawdownAtRisk95, sterling:number|null, tailIndex:number|null, tailIndexWide:number|null, maxDrawdown, ...}, structure:{hurst, autocorr1, autocorr2, trendT, halfLifeMR:number|null, permEntropy, permEntropyTieFrac, rollSpreadBps}, tests:{ljungBox, ljungBoxProfile:[{lag, stat, p, reject}], adf, kpss, runs, varianceRatio, jarqueBera}, horizon:{daysToResolve, barsPerDay, perDayMove, perHorizonMove, terminalVariance, resolvedFrom:'closeTime'|'endDate'|null, available}|null}, benchmark?:{benchmarkAsset, up:number|null, down:number|null, captureSpread:number|null, alignedBars}|null (HL perps only) }Sample curl
curl 'https://hypo.markets/api/asset/hl-BTC/stats'
/api/book/[asset]FREEcache 4s
Live order book for an HL perp or PM market
Bid + ask ladders from the venue's depth API. HL perps return L2 levels; PM returns the CLOB's yes-side book. Use /api/asset/[asset]/slippage for size-aware execution simulation.
Query parameters
| Name | Type | Required | Description |
|---|
asset | string | yes | Path parameter — asset id. |
Response shape
{ ok, asset, kind, bids:[{price, size}], asks:[{price, size}], fetchedAt }Sample curl
curl 'https://hypo.markets/api/book/hl-BTC'
/api/m2m/[asset]/quoteFREEcache 2s
Ultra-low-latency price tick — current price + freshness only
Micro-endpoint companion to /api/m2m/[asset]/bundle. Returns ONLY price (last/bid/ask/spreadBps/change24hPct) + freshness (feedAgeMs/isStale). No risk metrics, no signal synthesis, no history-store read by default. Warm latency ~1-2ms vs ~50ms for /bundle. Use for latency-sensitive bot scans across many assets. IMPORTANT for movement scanners: `change24hPct` is populated only for HL perps (snapshot-native); for Polymarket/Kalshi/Limitless it is ALWAYS null here (`change24hSource` is null) because the binary-venue 24h delta is a history-store computation done only in /bundle — to scan binary-venue movement use /movers or /bundle, not /quote. Optional ?activity=true adds historyLastEverMs (costs ~1-2ms of tail-read disk IO) for callers that want the 'last seen' signal alongside the live tick. Versioned: apiVersion='v1' (new optional fields are backwards-compatible).
Query parameters
| Name | Type | Required | Description |
|---|
asset | string | yes | Path parameter — asset id (hl-BTC, pm-{slug}, kalshi-{ticker}, hl-pred-{slug-or-outcomeId}). |
activity | boolean | no | Query — set to 'true' to include freshness.historyLastEverMs (last write on disk). Costs ~1-2ms. |
venueNativeUrl | boolean | no | Query — set to 'false' to drop venueNativeUrl (~50-100 bytes) for byte-saving scans. Default true. |
Response shape
{ ok, generatedAt, apiVersion, asset, venue, storeKey, price:{last, bid, ask, spreadBps, change24hPct (null on PM/Kalshi/Limitless — use /movers|/bundle), change24hSource:'snapshot'|null, fairValue:number|null, basisBps:number|null (perp HL-oracle, snapshot-local)}, freshness:{feedAgeMs, isStale, historyLastEverMs?} (opt-in ?activity=true), venueNativeUrl }Sample curl
curl 'https://hypo.markets/api/m2m/[asset]/quote' # try hl-BTC, pm-{slug}, or any other asset idHealth probes
/api/health/endpointsFREEcache 30s
In-process probe aggregator for the 9 night-build endpoints
Invokes each route handler in-process (no HTTP loopback) and reports status code, latency, and last-checked ISO timestamp per probe. Cached for 30s globally.
Response shape
{ ok, generatedAt, summary: {healthy, degraded, errored, total, avgLatencyMs, maxLatencyMs, verdict}, probes: [{endpoint, sampleUrl, status, statusCode, sampleLatencyMs, lastChecked, error}] }Sample curl
curl 'https://hypo.markets/api/health/endpoints'
/apiFREEcache 3600s
Endpoint index — minimal JSON list of every public route
Lightweight catalog endpoint. Returns `{ ok, count, catalog, endpoints }` where each endpoint carries path + method + summary + group + cacheSeconds. Useful for tooling that just needs the URL list without the full OpenAPI spec.
Response shape
{ ok, count, catalog: {docs, spec}, endpoints: [{path, method, summary, group, cacheSeconds}] }Sample curl
curl 'https://hypo.markets/api'
/api/openapi.jsonFREEcache 3600s
OpenAPI 3.1 spec for every public read endpoint
Machine-readable schema describing every endpoint in this catalog. Generated from lib/api-catalog at request time so adding a new route auto-propagates to OpenAPI consumers. Static-cacheable; the spec only changes when the catalog does.
Response shape
OpenAPI 3.1.0 document: { openapi, info, servers, tags, paths, components }Sample curl
curl 'https://hypo.markets/api/openapi.json'
/api/alerts/staleFREEcache 60s
JSON mirror of /alerts staleness dashboard
Returns the same data as /alerts in JSON so external monitors can poll without scraping HTML. Default threshold 5 minutes; configurable via ?thresholdMin=.
Query parameters
| Name | Type | Required | Description |
|---|
thresholdMin | number | no | Staleness threshold in minutes. Default 5, max 1440. |
limit | integer | no | Cap on stale[] and neverRecorded[] arrays. Default 1000, max 10000. Summary tally reflects the full count regardless. |
sortBy | string | no | Sort key for the visible window: staleness | asset | venue. Defaults: staleness for stale[], asset for neverRecorded[]. Applied AFTER the limit slice. |
venue | string | no | Restrict to a single venue id (e.g. hyperliquid, polymarket, kalshi). 400 on unknown. Applied BEFORE detection — summary tally and limit cap reflect the filtered subset. |
Response shape
{ ok, generatedAt, params: {thresholdMin, thresholdMs, limit, sortBy, venue}, summary: {totalAssets, staleCount, neverRecordedCount, byVenue}, truncated: {stale, neverRecorded}, stale: [...], neverRecorded: [...] }Sample curl
curl 'https://hypo.markets/api/alerts/stale?venue=hyperliquid&thresholdMin=15&limit=100'
/api/alerts/stale.csvFREEcache 60s
RFC 4180 CSV mirror of /api/alerts/stale
Same query surface and validation envelope as the JSON endpoint, but emits text/csv with a download attachment. Columns: kind (stale|never_recorded), venue, asset, lastIso, staleForMs, count, bytes. Stale rows precede never-recorded rows. Summary tally is dropped; consumers wanting that should call /api/alerts/stale.
Query parameters
| Name | Type | Required | Description |
|---|
thresholdMin | number | no | Staleness threshold in minutes. Default 5, max 1440. |
limit | integer | no | Cap per-block (stale and neverRecorded each capped). Default 1000, max 10000. |
sortBy | string | no | Sort key: staleness | asset | venue. Applied AFTER the per-block limit slice. |
venue | string | no | Restrict to a single venue id. 400 on unknown. Filter applied BEFORE detection; the filename also embeds the venue. |
Response shape
text/csv with header row: kind,venue,asset,lastIso,staleForMs,count,bytes
Sample curl
curl -O 'https://hypo.markets/api/alerts/stale.csv?venue=hyperliquid&thresholdMin=15'
/api/alerts/stale/historyFREEcache 60s
Rolling-snapshot of the staleness verdict over the past N hours
Single-snapshot foundation today; future expansion will read a sovereign JSONL window so a dashboard can chart verdict drift over the last 6/12/24h. ?hours= is validated up-front so consumers can wire against the response shape now.
Query parameters
| Name | Type | Required | Description |
|---|
hours | number | no | Window in hours. Default 6, max 48. Validated today; reserved for the future historical snapshotter. |
thresholdMin | number | no | Staleness threshold in minutes. Default 5, max 1440. |
Response shape
{ ok, generatedAt, params: {hours, thresholdMin, thresholdMs}, snapshots: [{ts, verdict, summary}], note }Sample curl
curl 'https://hypo.markets/api/alerts/stale/history?hours=12'
/api/alerts/stale/snapshotFREEcache 0s
Cron trigger that persists one staleness snapshot
Computes the current verdict + summary and appends one record to the sovereign stale-snapshots JSONL store. Rate-limited to one write per 60s (returns 200 with skipped:true if called sooner). When the HYPO_SNAPSHOT_TOKEN env is set, requests must carry a matching X-Snapshot-Token header (401 otherwise); when unset, the endpoint is open (intended for fully-local dev).
Response shape
{ ok, skipped, written?: {ts, verdict, summary}, reason?, lastSnapshotAgeMs? }Sample curl
curl -X POST -H 'X-Snapshot-Token: $TOKEN' 'https://hypo.markets/api/alerts/stale/snapshot'
/api/feed/healthFREEcache 5s
Feed-cache poller diagnostics (per-upstream counters + last error)
Surfaces the state of the in-process feed-cache poller: per-upstream ok/fail counters, last error message, snapshot age, pollersRunning boolean. Verdict OK when all three upstreams have snapshots, WARN when partial, DOWN when no poller is running OR every poll has failed since start (HTTP 503 on DOWN). Also a per-venue `venues` freshness map and a `degraded` map (+`anyDegraded`): a degraded venue is one actively erroring (failCount>0, lastError set) while its last snapshot is still fresh — a LEADING indicator (the pre-120s-stale-cliff window) that does NOT change the verdict, so transient 429s don't flap OK.
Response shape
{ ok, generatedAt, verdict, venues:{hyperliquid, polymarket, kalshi, limitless}, degraded:{hyperliquid, polymarket, kalshi, limitless}, anyDegraded, health:{ startedAt, uptimeMs, pollersRunning, hyperliquid:{lastFetchedAt, ageMs, okCount, failCount, lastError, pollIntervalMs, hasSnapshot}, polymarket:{...}, kalshi:{...}, limitless:{...} } }Sample curl
curl 'https://hypo.markets/api/feed/health'
/api/health/anomaliesFREEcache 5s
Live data-integrity invariant checker (alertable verdict)
Runs detectAnomalies() over the current in-memory snapshot and surfaces invariant violations for an external alerting cron: stale/missing/empty venues, probabilities outside [0,1], non-positive HL prices, the Kalshi empty-no-book noProb=0.50 artifact, gross overround, and money-path health (billing write failures, low disk, held over-cap deposits). verdict is ok | degraded (a warning present) | critical. Sovereign-aware: an engine is only faulted for the venue(s) it serves (apex=all three). PAGE ON `alertable === true`, NOT `verdict !== 'ok'` — `verdict` flaps to degraded/critical during the ~90s post-restart warm-up grace while the first poll lands, but `alertable` is false during that grace (and true only on a real problem).
Response shape
{ ok, verdict, warming, alertable, scope, counts:{ total, critical, warning }, anomalies:[{ severity, code, venue, message, count? }], generatedAt }Sample curl
curl 'https://hypo.markets/api/health/anomalies'
/api/health/snapshotterFREEcache 30s
Liveness check on the sovereign stale-snapshotter file
Returns the same stats /status renders plus a coarse verdict (OK / WARN / DOWN) classified by the age of the most recent snapshot. Returns HTTP 503 on DOWN so naive monitors (`curl --fail`, uptime-kuma's HTTP status mode) get the right signal without parsing the body. Thresholds: OK <= 10 min, WARN <= 30 min, DOWN beyond that or file absent.
Response shape
{ ok, generatedAt, verdict, reason, thresholds: {warnAfterMs, downAfterMs}, stats: {exists, sizeBytes, lastTs, lastTsMs, ageMs, count24h} }Sample curl
curl --fail 'https://hypo.markets/api/health/snapshotter'
/api/health/upstreamFREEcache 30s
Network probe over HL, PM, Kalshi data sources
Goes over the wire to each upstream with a 5s AbortController timeout per probe. Surfaces network errors, rate-limit codes, and round-trip latency. Independent from /api/health/endpoints.
Response shape
{ ok, generatedAt, scope, summary: {healthy, degraded, errored, total, avgLatencyMs, maxLatencyMs, verdict}, probes: [{upstream, probedUrl, method, status, statusCode, latencyMs, lastChecked, error}] }Sample curl
curl 'https://hypo.markets/api/health/upstream'
/api/healthFREEcache 0s
Apex liveness — quick yes/no whether the process is up + SSE fan-out telemetry
Minimal endpoint for liveness checks: returns ok + uptime + asset-pulse subscriber counts. Lighter than /api/feed/health (which goes deeper into per-upstream state). Use this for top-level uptime monitoring; /api/feed/health for the data-pipeline verdict.
Response shape
{ ok, uptimeMs, pulse:{assetsPolling, totalSubscribers, perAsset} }Sample curl
curl 'https://hypo.markets/api/health'
Account & billing
/api/account/usageKEYcache 0s
Your API key's usage, quota, tier, and per-venue breakdown (this UTC month)
Self-service usage report for the caller's own API key. Authenticate with the key being reported on (Authorization: Bearer <key> or X-API-Key). Returns the tier, its limits (monthly quota, per-key rate, features, venue entitlement), and the current-month usage including the per-venue split that underpins per-venue billing.
Response shape
{ ok, tier, owner, venues, month, limits:{monthlyQuota, ratePerMin, maxConcurrentStreams, features, venues}, usage:{total, quotaRemaining, byVenue, byEndpoint, firstAt, lastAt}, key:{hash, createdAt, expiresAt} }Sample curl
curl -H 'X-API-Key: k_live_…' 'https://hypo.markets/api/account/usage'
/api/account/keysADMINcache 0s
Admin key management — issue (POST), list (GET), revoke (DELETE)
Admin-only API-key lifecycle, gated by the HYPO_ADMIN_TOKEN bearer (fail-closed in production). POST {tier, owner, label?, venues?, expiresAt?} issues a key and returns the raw key ONCE (only its SHA-256 hash is stored). GET lists key metadata (hashes only). DELETE {keyHash} revokes.
Query parameters
| Name | Type | Required | Description |
|---|
tier | enum | yes | free | pro | enterprise (POST body). |
owner | string | yes | Account id / email (POST body). |
venues | csv | no | Per-key venue allow-list, or "all" (POST body). |
expiresAt | integer | no | Expiry epoch-ms, or null (POST body). |
keyHash | string | no | Key hash to revoke (DELETE body). |
Response shape
POST → { ok, rawKey, record }; GET → { ok, keys:[record] }; DELETE → { ok, revoked }Sample curl
curl -XPOST -H 'Authorization: Bearer $HYPO_ADMIN_TOKEN' -H 'Content-Type: application/json' -d '{"tier":"pro","owner":"acme@x.com"}' 'https://hypo.markets/api/account/keys'/api/account/balanceKEYcache 0s
Your prepaid USDC/USDT balance, recent ledger, and the price list
Self-service prepaid balance for the caller's API key (µUSD + USD). Includes the recent credit/debit ledger and the per-call price list. Top up by depositing USDC/USDT (see /api/account/wallets).
Response shape
{ ok, owner, balance:{microUsd, usd}, prepaidEnabled, priceListMicroUsd, ledger:[{ts, type, microUsd, balanceAfter, ref}] }Sample curl
curl -H 'X-API-Key: k_live_…' 'https://hypo.markets/api/account/balance'
/api/account/walletsKEYcache 0s
Register the wallet(s) you pay FROM + discover deposit addresses
GET returns your registered pay-from wallets, the per-chain deposit addresses (USDC/USDT across the top-10 chains), and the price list. POST {address} registers an EVM/Tron/Solana wallet — a deposit from it credits your prepaid balance automatically.
Query parameters
| Name | Type | Required | Description |
|---|
address | string | no | Pay-from wallet (0x… EVM / T… Tron / base58 Solana) — POST body. |
Response shape
GET → { ok, registeredWallets, depositTargets:[{chain, asset, depositAddress}], priceListMicroUsd }; POST → { ok, registeredWallets }Sample curl
curl -XPOST -H 'X-API-Key: k_live_…' -H 'Content-Type: application/json' -d '{"address":"0xYourWallet"}' 'https://hypo.markets/api/account/wallets'/api/account/deposit-addressKEYcache 0s
Your unique per-chain deposit address (CREATE2 forwarders)
Returns a deposit address UNIQUE to your account on each configured chain, derived deterministically (CREATE2) so it is byte-identical to where funds are swept. Send USDC/USDT on the matching chain to your address; confirmed deposits credit your prepaid balance automatically — no pay-from registration needed. Dormant (503) until per-customer deposits are configured.
Query parameters
| Name | Type | Required | Description |
|---|
chain | string | no | Limit to one chain (e.g. 'base'); default returns every configured chain. |
Response shape
{ ok, owner, addresses:[{chain, address, assets}] }Sample curl
curl -H 'X-API-Key: k_live_…' 'https://hypo.markets/api/account/deposit-address?chain=base'
/api/account/creditADMINcache 0s
Admin manual credit (fiat/Stripe bridge, adjustments)
Admin-only off-chain top-up gated by HYPO_ADMIN_TOKEN, idempotent by `ref`. On-chain USDC/USDT deposits are credited automatically by the watcher; this is the manual/fiat path.
Query parameters
| Name | Type | Required | Description |
|---|
owner | string | yes | Account owner to credit (POST body). |
usd | number | no | Amount in USD (or microUsd) — POST body. |
ref | string | yes | Idempotency key, e.g. stripe_pi_… (POST body). |
Response shape
{ ok, owner, applied, microUsd, balanceMicroUsd }Sample curl
curl -XPOST -H 'Authorization: Bearer $HYPO_ADMIN_TOKEN' -H 'Content-Type: application/json' -d '{"owner":"acme@x.com","usd":50,"ref":"stripe_pi_1"}' 'https://hypo.markets/api/account/credit'/api/account/webhook/[provider]WEBHOOKcache 0s
PSP deposit webhook (Coinbase Commerce / Stripe / generic HMAC)
Signed deposit webhook sink. provider ∈ coinbase | stripe | hmac. The signature is verified over the RAW body (fail-closed if the provider secret is unset), then the deposit is credited to the account in metadata.hypo_owner — idempotent by the PSP event id. This is the no-custody path (the PSP attributes the payment + handles per-customer addresses + fiat); the on-chain watcher is the self-custody path. Both credit the same ledger.
Query parameters
| Name | Type | Required | Description |
|---|
provider | enum | yes | Path param: coinbase | stripe | hmac. |
Response shape
{ ok, provider, owner, applied, microUsd, balanceMicroUsd } (200); ignored events → { ok, ignored }; bad signature → 401; secret unset → 503Sample curl
# configured in the PSP dashboard, not called by hand:
# Coinbase Commerce → https://hypo.markets/api/account/webhook/coinbase
# Stripe → https://hypo.markets/api/account/webhook/stripe
/api/account/vouchersADMINcache 0s
Admin — issue prepaid voucher codes (one of the parallel funding paths)
Issue redeemable voucher codes worth a fixed amount, gated by HYPO_ADMIN_TOKEN. POST {usd|microUsd, count?, expiresAt?, label?} returns the raw codes ONCE (only SHA-256 hashes are stored). GET lists voucher metadata. Customers redeem at /api/account/redeem; the credit lands in the same prepaid balance as on-chain / PSP / admin top-ups.
Query parameters
| Name | Type | Required | Description |
|---|
usd | number | no | Voucher value in USD (or microUsd) — POST body. |
count | integer | no | How many to issue (default 1, max 1000) — POST body. |
expiresAt | integer | no | Expiry epoch-ms, or null — POST body. |
Response shape
POST → { ok, count, microUsd, codes:["HYPO-…"] }; GET → { ok, vouchers:[record] }Sample curl
curl -XPOST -H 'Authorization: Bearer $HYPO_ADMIN_TOKEN' -H 'Content-Type: application/json' -d '{"usd":25,"count":10}' 'https://hypo.markets/api/account/vouchers'/api/account/redeemKEYcache 0s
Redeem a prepaid voucher code into your balance
Redeem a voucher (POST {code}) — single-use + idempotent — crediting the caller's prepaid balance. Authenticated by your API key. Works alongside on-chain deposits, PSP webhooks, and admin credits: all converge on one balance per account.
Query parameters
| Name | Type | Required | Description |
|---|
code | string | yes | The voucher code, e.g. HYPO-ABCDE-FGHJK-LMNPQ (POST body). |
Response shape
{ ok, owner, microUsd, balanceMicroUsd } (200); invalid OR already-redeemed → 404 invalid_code (indistinguishable, anti-enumeration); expired → 410Sample curl
curl -XPOST -H 'X-API-Key: k_live_…' -H 'Content-Type: application/json' -d '{"code":"HYPO-ABCDE-FGHJK-LMNPQ"}' 'https://hypo.markets/api/account/redeem'/api/account/treasuryADMINcache 0s
Admin — prepaid float/treasury report (yield visibility)
Total prepaid liability held across all customers — the float you custody until usage consumes it, available for yield (T-bills / on-chain). Gated by HYPO_ADMIN_TOKEN.
Response shape
{ ok, float:{ totalMicroUsd, totalUsd, accounts, nonZeroAccounts } }Sample curl
curl -H 'Authorization: Bearer $HYPO_ADMIN_TOKEN' 'https://hypo.markets/api/account/treasury'
/api/admin/flagsADMINcache 0s
Admin — live operational flag state + global kill toggle
The operator control surface (powers the /ops console). GET returns the LIVE state of every operational flag across bot (execMode, engineLoop, vaultEnabled, globalKill, tradeFee), monetization (paidGating, prepaidBilling), deposits (EVM, Solana), and security (trustProxy). POST {globalKill:true|false} toggles the runtime bot kill-switch (no restart). Env-driven flags are read-only (flip in the engine's env file + restart). Gated by HYPO_ADMIN_TOKEN (Bearer).
Response shape
{ ok, flags:{ bot:{execMode,engineLoop,vaultEnabled,globalKill,tradeFeeMicroUsd}, monetization:{paidGating,prepaidBilling}, deposits:{evm,solana}, security:{trustProxy}, dataVenues:[{venue,shipped,tier}], process:{venue,nodeEnv} }, engines:[{venue,port,verdict}] }Sample curl
curl -H 'Authorization: Bearer $HYPO_ADMIN_TOKEN' 'https://hypo.markets/api/admin/flags'
Trading bot
/api/bot/statusKEYcache 0s
HYPO Bot — system + per-account status (free)
Status for the autonomous trading bot (bot.hypo.markets). Unauthenticated → public system status (execMode mock|live, global kill, engine-loop flag). Authenticated (API key) → adds the caller's config, kill state, prepaid balance, recent orders, and access-fee totals. NON-CUSTODIAL: the bot trades on the USER's OWN venue account; HYPO never holds trading funds — only the per-trade access fee billed from prepaid credit. Execution is DORMANT (execMode='mock') until live adapters + the credential vault ship.
Response shape
{ ok, authenticated, system:{execMode:'mock'|'live', globalKill, engineLoop, vaultEnabled}, killed?, balanceMicroUsd?, config?:{enabled, venues[], assets[], minConfidence, tradeSizeUsd, feeMicroUsd, maxStaleMs}, connectedVenues?:[{venue, kind, addedAt}], activity?:{orderRecords, filled, fills, accessFeesMicroUsd}, recentOrders?:[{t, clientOrderId, venue, venueAsset, side, sizeUsd, status, feeAccessMicroUsd}] }Sample curl
curl -H 'X-API-Key: $HYPO_KEY' 'https://bot.hypo.markets/api/bot/status'
/api/bot/controlKEYcache 0s
HYPO Bot — configure the caller's bot + kill-switch
Update the caller's single bot. Body (all optional): enabled, venues (subset of hyperliquid|polymarket|kalshi|limitless), assets[], minConfidence (0..1 signal floor), tradeSizeUsd (per-trade notional — NO cap), maxStaleMs (stale-signal guard), kill (boolean — instant halt override that wins over enabled). feeMicroUsd is NOT user-settable (operator revenue). 1 bot per key; open more by provisioning more keys.
Response shape
{ ok, config:{enabled, venues[], assets[], minConfidence, tradeSizeUsd, feeMicroUsd, maxStaleMs, updatedAt}, killed }Sample curl
curl -X POST -H 'X-API-Key: $HYPO_KEY' -H 'Content-Type: application/json' -d '{"enabled":true,"venues":["hyperliquid"],"assets":["hl-BTC"],"minConfidence":0.65}' 'https://bot.hypo.markets/api/bot/control'/api/bot/tradeKEYcache 0s
HYPO Bot — place one order on the caller's own venue account (billed per trade)
Place ONE explicit order non-custodially on the caller's OWN venue account, billing the flat per-trade access fee from prepaid credit ONLY on a real fill. Body: { venue (hyperliquid|polymarket|kalshi|limitless), asset, side (buy|sell), sizeUsd>0, markPrice>0 (execution reference), clientOrderId? (idempotency) }. Idempotent on clientOrderId — a replay never double-places or double-bills. Live execution is double-gated (HYPO_BOT_EXEC_MODE=live AND the per-user credential vault); until then it returns 503 in live mode and executes against the deterministic MockVenue in mock mode. 402 on insufficient prepaid credit; 423 when the kill-switch is set.
Response shape
{ ok, execMode:'mock'|'live', outcome:{status:'filled'|'resting'|'rejected'|'duplicate'|'killed'|'insufficient_balance', clientOrderId, chargedMicroUsd, order?, reason?} }Sample curl
curl -X POST -H 'X-API-Key: $HYPO_KEY' -H 'Content-Type: application/json' -d '{"venue":"hyperliquid","asset":"hl-BTC","side":"buy","sizeUsd":100,"markPrice":65000}' 'https://bot.hypo.markets/api/bot/trade'/api/bot/credentialsKEYcache 0s
HYPO Bot — connect/list/disconnect your OWN venue credential (non-custodial)
Manage the credential the bot uses to place orders on YOUR OWN venue account — the non-custodial key. Secrets are AES-256-GCM encrypted at rest and NEVER returned or logged. POST {venue, kind:'apiKey'|'wallet'|'oauth', secret:{...}} to connect; DELETE {venue} to disconnect; GET to list connected venues (metadata only). 503 when the vault is not configured (HYPO_BOT_VAULT_KEY unset). STRONGLY recommend supplying trade-only / withdraw-disabled keys — even a vault breach can then only trade, never withdraw (HYPO never holds funds or withdrawal authority).
Response shape
{ ok, vaultEnabled?, connected:[{venue, kind, addedAt}] } (secrets never returned)Sample curl
curl -X POST -H 'X-API-Key: $HYPO_KEY' -H 'Content-Type: application/json' -d '{"venue":"hyperliquid","kind":"wallet","secret":{"privateKey":"0x..."}}' 'https://bot.hypo.markets/api/bot/credentials'/api/bot/leaderboardFREEcache 0s
HYPO Bot — public anonymous leaderboard (realized P&L)
Public ranking of all bots by realized P&L (descending). FREE, no auth, no PII — each bot is a stable pseudonymous handle derived from its hashed ledger id; no owner, balance, or credential is ever exposed. The traction surface. ?limit (1-200, default 50).
Query parameters
| Name | Type | Required | Description |
|---|
limit | integer | no | Max rows, 1-200, default 50. |
Response shape
{ ok, leaderboard:[{handle, realizedPnlUsd, winRate, tradeCount, totalVolumeUsd, openPositions}] }Sample curl
curl 'https://bot.hypo.markets/api/bot/leaderboard?limit=20'
/api/bot/tapeFREEcache 0s
HYPO Bot — public live-tape SSE (anonymous fills)
Server-Sent Events stream of recent fills across ALL bots, anonymised (pseudonymous handle, no PII). A 'snapshot' frame on connect, then 'fills' frames as new trades land (polls the durable ledger). ': heartbeat' every 25s. FREE, no auth. The live 'show parade'.
Response shape
text/event-stream: data:{type:'snapshot'|'fills', fills:[{t, handle, venue, venueAsset, side, filledUsd, avgPrice}]}; ': connected' + ': heartbeat' commentsSample curl
curl -N 'https://bot.hypo.markets/api/bot/tape'