Skip to content

Discovery REST

Eight public endpoints let a client probe what venues and symbols the platform currently exposes, without hard-coding lists. All are public (no auth required) and cached server-side for 60 seconds. Use these at startup to validate symbol names, discover new listings, and build dynamic subscription sets.


Endpoint summary

EndpointDescription
GET /v1/marketsAll venues → live state
GET /v1/markets/{exchange}One venue’s live state + staleness
GET /v1/symbolsPer-venue symbol counts + capability flags
GET /v1/symbols/{exchange}Full symbol catalog (live + historical) for one venue
GET /v1/symbols/{exchange}/liveBare array of currently-subscribable symbols
GET /v1/symbols/{exchange}/historicalBare array of symbols with persisted history
GET /v1/instrumentsCross-venue catalog of canonical underlyings
GET /v1/instruments/{symbol}Which venues quote one underlying

GET /v1/markets

Map of every venue to its current live state.

{
"hl": { "symbols": ["ETH", "BTC", "SOL", ...], "connected": true },
"uni": { "symbols": ["WETH/USDC", ...], "connected": true },
"spectra": { "symbols": [...], "connected": true }
}

connected reflects whether the upstream feed is currently healthy (not stale beyond its venue-specific threshold).


GET /v1/markets/{exchange}

One venue’s live state plus current staleness.

{
"exchange": "hl",
"symbols": ["ETH", "BTC", "SOL", ...],
"connected": true,
"staleSec": 0.4
}

staleSec is -1 when the venue has never emitted a message.


GET /v1/symbols

Per-venue summary with symbol counts and capability flags.

{
"exchanges": [
{
"id": "hl",
"live_count": 152,
"historical_count": 50,
"connected": true,
"extensible": false,
"capabilities": {
"live_quotes": true,
"live_prints": true,
"live_funding": true,
"hist_quotes": true,
"hist_prints": true,
"hist_funding": true
}
}
]
}

extensible: true means the venue accepts symbols outside the published list. All AMM venues are extensible — any pool resolvable via the on-chain registry is subscribable.


GET /v1/symbols/{exchange}

Full catalog for one venue: live symbols, historical symbols, capabilities.

{
"exchange": "hl",
"connected": true,
"capabilities": { "live_quotes": true, "live_prints": true, ... },
"live": {
"count": 152,
"symbols": ["ETH", "BTC", ...],
"extensible": false
},
"historical": {
"count": 50,
"symbols": ["ETH", "BTC", "SOL", ...],
"note": "Historical retention is best-effort; subset of live."
}
}

For extensible AMM venues: live.count is null and live.symbols is the curated bootstrap list — clients can subscribe to symbols outside it.


GET /v1/symbols/{exchange}/live

Bare array of currently-subscribable symbols. Use this when you only need the symbol list.

["ETH", "BTC", "SOL", "ARB", "OP", "AVAX", ...]

GET /v1/symbols/{exchange}/historical

Bare array of symbols that have persisted history.

["ETH", "BTC", "SOL", "DOGE", ...]

GET /v1/instruments

Cross-venue catalog of canonical underlyings. Each key is an uppercase asset name; each value is the venues that quote it in exchange:symbol form.

{
"ETH": ["hl:ETH", "dydx:ETH-USD", "ostium:ETH/USD", "gmx:ETH", "uni:WETH/USDC"],
"BTC": ["hl:BTC", "dydx:BTC-USD", "ostium:BTC/USD", "gmx:BTC"],
"XAU": ["ostium:XAU/USD"],
"SPX": ["ostium:SPX/USD"],
"WTI": ["ostium:WTI/USD"]
}

This is a curated catalog covering common cross-venue underlyings. For an exhaustive list, walk /v1/symbols/{exchange} for each venue.


GET /v1/instruments/{symbol}

Venues quoting one underlying. Path parameter is case-insensitive; pass uppercase.

GET /v1/instruments/ETH
{
"symbol": "ETH",
"venues": [
{ "exchange": "hl", "symbol": "ETH" },
{ "exchange": "dydx", "symbol": "ETH-USD" },
{ "exchange": "ostium", "symbol": "ETH/USD" },
{ "exchange": "gmx", "symbol": "ETH" },
{ "exchange": "uni", "symbol": "WETH/USDC" }
]
}

Python discovery pattern

import httpx
base = "https://api.mackinac.io"
# Which venues are currently connected?
markets = httpx.get(f"{base}/v1/markets").json()
live_venues = [v for v, s in markets.items() if s["connected"]]
# All live HL symbols
hl_symbols = httpx.get(f"{base}/v1/symbols/hl/live").json()
# Which venues quote ETH?
eth = httpx.get(f"{base}/v1/instruments/ETH").json()
# → {"symbol":"ETH","venues":[{"exchange":"hl","symbol":"ETH"},{"exchange":"dydx","symbol":"ETH-USD"},{"exchange":"gmx","symbol":"ETH"},…]}
# Subscribe to ETH across all venues that carry it
for venue in eth["venues"]:
ws.send(json.dumps({"action": "subscribe",
"exchange": venue["exchange"],
"symbol": venue["symbol"]}))

Caching

All discovery endpoints return Cache-Control: public, max-age=60. Expect new pool discoveries and symbol additions to surface within ~60 seconds.


Errors

HTTPMeaning
200OK (empty arrays are valid — the venue exists but has no symbols)
404Unknown exchange or unknown instrument

No authentication or rate-limit errors apply to these endpoints.