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
| Endpoint | Description |
|---|---|
GET /v1/markets | All venues → live state |
GET /v1/markets/{exchange} | One venue’s live state + staleness |
GET /v1/symbols | Per-venue symbol counts + capability flags |
GET /v1/symbols/{exchange} | Full symbol catalog (live + historical) for one venue |
GET /v1/symbols/{exchange}/live | Bare array of currently-subscribable symbols |
GET /v1/symbols/{exchange}/historical | Bare array of symbols with persisted history |
GET /v1/instruments | Cross-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 symbolshl_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 itfor 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
| HTTP | Meaning |
|---|---|
| 200 | OK (empty arrays are valid — the venue exists but has no symbols) |
| 404 | Unknown exchange or unknown instrument |
No authentication or rate-limit errors apply to these endpoints.