spb/market-atlas
Public
TypeScript 96.7%
SQL 1.6%
CSS 0.8%
JavaScript 0.5%
1import type { Metadata } from "next";2import Link from "next/link";3import { Page, PageHeader } from "@/components/ui/section";4import { SITE_URL } from "@/lib/site";56export const metadata: Metadata = { title: "Developers", description: "Market Atlas API: REST endpoints, WebSocket and SSE streams, envelopes, errors and rate limits.", alternates: { canonical: "/developers" } };78const REST: Array<[string, string]> = [9 ["GET /v1/stats", "Live telemetry (instruments, connectors, observations today, events, freshness)."],10 ["GET /v1/markets", "Global overview: featured indices, crypto, FX, rates, commodities, equities, movers, exchanges with state, breadth."],11 ["GET /v1/instruments?asset_class=&exchange=&country=&q="ed=1&sort=&limit=&offset=", "Instrument master with canonical quotes. sort ∈ symbol | change | -change | volume | name."],12 ["GET /v1/instruments/{id|SYMBOL|VENUE:SYMBOL}", "Instrument detail: company, exchange + status, quote, aliases, observing sources, related instruments."],13 ["GET /v1/quotes/{id}", "One canonical quote."],14 ["GET /v1/quotes?ids=a,b,c", "Up to 200 canonical quotes."],15 ["GET /v1/quotes/{id}/provenance", "“Why this price?” — source coverage matrix: every contribution with observation_type, delta_bps vs consensus, weight, age, inclusion and reason; plus comparability, proxy/validator confirmations, coverage and shared_upstream_pairs."],16 ["GET /v1/coverage?asset_class=&tier=A|B|C|D&limit=", "Source Coverage Engine: summary (quoted, multiSource, byFamilies ≥5/≥3/≥2/1/0, weightedScore, tiers attainment, byAssetClass, proxiesConfirming, validatorsConfirming), targets, source-expansion queue, inferred shared upstreams (lineage)."],17 ["GET /v1/coverage/{id}", "Coverage of one instrument: tier, target, families, observations, proxies, validators, live/delayed/official counts, score, status, gap."],18 ["GET /v1/history/{id}?resolution=1m|5m|15m|1h|1d&from=&to=&limit=", "OHLCV bars (t, o, h, l, c, v, n sources, p producer)."],19 ["GET /v1/events?type=&instrument=&country=&asset_class=&severity=&since=&before=&limit=", "Canonical events; GET /v1/events/{id} for one."],20 ["GET /v1/filings?form=&cik=&q=&limit=&offset=", "Regulatory filings observed on EDGAR."],21 ["GET /v1/exchanges · GET /v1/exchanges/{id}", "Venues with session state, holidays, breadth, movers, events."],22 ["GET /v1/countries · GET /v1/countries/{code}", "Country atlas: exchanges, indices, rates, FX, equities, events."],23 ["GET /v1/search?q=", "Hybrid search grouped by asset class, exchange, country."],24 ["GET /v1/compare?ids=&resolution=", "Rebased series, return/volatility/drawdown, pairwise correlation."],25 ["GET /v1/changes?window=1m|5m|15m|1h|1d", "What changed: movers > 1 %, events, filings, by type."],26 ["GET /v1/breadth?scope=world|US|xnas", "Advancers/decliners/highs/lows for a scope."],27 ["GET /v1/sources · GET /v1/connectors · GET /v1/data-health · GET /v1/status · GET /v1/health · GET /v1/metrics", "Provenance directory, connector operations, health, public status, liveness, Prometheus metrics."],28];2930export default function DevelopersPage() {31 const base = SITE_URL;32 const ws = base.replace(/^http/, "ws");33 return (34 <Page>35 <PageHeader kicker="API v1" title="Developers" lead="Public, read-only API over the same canonical data the site shows. Every response carries provenance metadata; values whose data rights forbid redistribution are withheld rather than silently omitted." />36 <div className="prose-ma max-w-3xl">37 <h2>Base URL & envelope</h2>38 <pre>39 <code>{`${base}/v14041{ "data": …, "meta": { "request_id": "…", "timestamp": "2026-09-12T14:31:42.512Z", "data_status": "DELAYED" } }`}</code>42 </pre>43 <p>44 Errors are structured: <code>{`{ "error": { "code": "INSTRUMENT_NOT_FOUND", "message": "instrument not found" } }`}</code> with the matching HTTP status. No stack traces.45 </p>46 <h2>Rate limits</h2>47 <p>48 20 requests per second sustained per IP (burst 300) on <code>/v1</code> REST; <code>429</code> with <code>Retry-After</code> when exceeded. Streams and web pages are not counted. Higher limits and API keys will come with the developer accounts.49 </p>50 <h2>REST endpoints</h2>51 <table>52 <thead>53 <tr>54 <th>Endpoint</th>55 <th>Description</th>56 </tr>57 </thead>58 <tbody>59 {REST.map(([e, d]) => (60 <tr key={e}>61 <td>62 <code>{e}</code>63 </td>64 <td>{d}</td>65 </tr>66 ))}67 </tbody>68 </table>69 <h3>Example</h3>70 <pre>71 <code>{`curl ${base}/v1/quotes/BTC-USD7273{74 "data": {75 "instrument_id": "crypto_btc_usd", "symbol": "BTC-USD", "price": 77326.37, "change_percent": 0.0275,76 "bid": 77326.36, "ask": 77326.37, "currency": "USD",77 "source_count": 4, "observation_count": 7, "proxy_count": 0, "validator_count": 0, "comparability": "LIVE",78 "dispersion_bps": 2.13, "confidence": 0.958, "freshness_ms": 1552,79 "data_status": "REALTIME", "market_state": null, "rights_status": "PUBLIC_ATTRIBUTED", "withheld": false,80 "updated_at": "2026-09-12T08:42:34.479Z", "source_timestamp": "2026-09-12T08:42:34.358Z"81 },82 "meta": { "request_id": "…", "timestamp": "…", "data_status": "REALTIME" }83}`}</code>84 </pre>85 <h2>Quote fields</h2>86 <ul>87 <li>88 <code>data_status</code>: <code>REALTIME</code> · <code>DELAYED</code> · <code>AT_CLOSE</code> · <code>END_OF_DAY</code> · <code>STALE</code> · <code>WITHHELD</code>. Never treat anything but <code>REALTIME</code> as live.89 </li>90 <li>91 <code>source_count</code> = independent <em>voting</em> source families; <code>observation_count</code> = fresh observations of any role; <code>proxy_count</code> = stablecoin/derived proxies agreeing within 50 bp; <code>validator_count</code> = restricted-rights sources agreeing within 25 bp; <code>comparability</code> ∈ <code>LIVE</code> · <code>FIX</code> · <code>EOD</code> = class of the canonical value; <code>dispersion_bps</code> = spread between voting sources; <code>confidence</code> ∈ [0, 0.995].92 </li>93 <li>94 Provenance contributions: <code>observation_type</code> ∈ TRADE · MID · QUOTE · INDEX_VALUE · INDICATIVE · STABLECOIN_PROXY · DERIVED · OFFICIAL_FIX · REFERENCE_RATE · SETTLEMENT · EOD_CLOSE · NAV; <code>delta_bps</code> = distance to the canonical value; <code>reason</code> ∈ stale · not_comparable · temporal_mismatch · validation_only · validator_disagrees · outlier. Validator values are <code>null</code> (withheld).95 </li>96 <li>97 <code>freshness_ms</code> = age of the newest included observation at response time; <code>source_timestamp</code> is the source's own time when published.98 </li>99 </ul>100 <h2>WebSocket stream</h2>101 <pre>102 <code>{`${ws}/v1/stream103104→ { "action": "subscribe", "channels": ["quotes:BTC-USD", "quotes:AAPL", "events:*", "market:xnas"] }105← { "type": "hello", "version": 1, "server_seq": 1024, "ts": 1789202146812 }106← { "type": "subscriptions", "channels": ["quotes:crypto_btc_usd", "quotes:eq_us_xnas_aapl", "events:*", "market:xnas"] }107← { "type": "batch", "seq": 1, "ts": 1789202146921, "messages": [108 { "type": "quote", "instrument_id": "crypto_btc_usd", "symbol": "BTC-USD", "price": 77326.37, "change": 21.27, "change_pct": 0.0275,109 "bid": 77326.36, "ask": 77326.37, "volume": 6634.6, "currency": "USD", "timestamp": 1789202146563, "received": 1789202146819,110 "confidence": 0.906, "sources": 2, "status": "REALTIME" },111 { "type": "event", "event": { "id": "evt_…", "type": "TRADING_HALT", "title": "…", "severity": "WARNING", "confidence": 1, "source_count": 1, "sources": ["nasdaq-trader"], "instrument_ids": [], "data": { … } } },112 { "type": "market_state", "exchangeId": "xnas", "state": "OPEN", "at": 1789392600000 }113 ] }114← { "type": "heartbeat", "ts": …, "seq": 42 } (every 25 s)115→ { "action": "ping", "id": 1 } ← { "type": "pong", "id": 1, "ts": … }116→ { "action": "unsubscribe", "channels": ["quotes:AAPL"] }`}</code>117 </pre>118 <p>Channels:</p>119 <ul>120 <li>121 <code>quotes:<SYMBOL|id></code> one instrument · <code>quotes:*</code> everything (throttled to 2 updates/s per instrument) · <code>quotes:class:CRYPTO</code> one asset class · <code>tape</code> compact price changes.122 </li>123 <li>124 <code>events:*</code> · <code>events:<SYMBOL|id></code> · <code>events:US</code> (country) · <code>events:type:TRADING_HALT</code>.125 </li>126 <li>127 <code>market:<exchange></code> or <code>market:*</code> for session-state changes.128 </li>129 </ul>130 <p>131 Frames are batched (≈ 10 per second per client) and carry a per-client <code>seq</code>; a gap means messages were dropped under backpressure. Up to 500 channels per connection.132 </p>133 <h2>Server-Sent Events</h2>134 <pre>135 <code>{`curl -N "${base}/v1/sse?channels=quotes:BTC-USD,events:*"136137event: hello138data: {"version":1,"channels":["quotes:crypto_btc_usd","events:*"],"ts":…}139140event: batch141id: 58142data: {"type":"batch","seq":1,"ts":…,"messages":[{"type":"quote",…}]}`}</code>143 </pre>144 <h2>Identifiers</h2>145 <p>146 Stable public ids: <code>eq_us_xnas_aapl</code>, <code>etf_us_arcx_spy</code>, <code>index_us_spx</code>, <code>crypto_btc_usd</code>, <code>fx_eur_usd</code>, <code>rate_us_us10y</code>, <code>cmd_xcme_gc_f</code>. Endpoints accepting <code>{"{id}"}</code> also accept a bare symbol (<code>AAPL</code>, <code>BTC-USD</code>) or <code>VENUE:SYMBOL</code>.147 </p>148 <h2>Attribution & terms</h2>149 <p>150 Data carries the rights status of its sources; see <Link href="/licensing">data rights</Link>. Cboe values are 15-minute delayed and must be displayed as such; venue and official-source attributions must be preserved when redistributing. Market Atlas is an informational platform, not investment advice.151 </p>152 </div>153 </Page>154 );155}156