Market Atlas API v1
Base: https://www.market-atlas.co/v1 (same origin as the web app; in development http://127.0.0.1:8391/v1).
Envelope: { "data": …, "meta": { "request_id", "timestamp", … } }; errors: { "error": { "code", "message" } }.
Public rate limit on /v1 only: 20 requests/s per IP (burst 300), 429 + retry-after. Admin routes need x-ma-admin-token.
Quote object (publicQuote): instrument_id, symbol, name, asset_class, exchange_id, country, price, open, high, low, previous_close, change, change_percent, volume, bid, ask, currency, source_count, dispersion_bps, confidence, freshness_ms, data_status, market_state, rights_status, withheld, updated_at, source_timestamp, session_high, session_low.
data_status ∈ REALTIME | DELAYED | END_OF_DAY | AT_CLOSE | STALE | WITHHELD — never present STALE/AT_CLOSE as live.
Quotes also carry observation_count, proxy_count, validator_count, comparability (LIVE/FIX/EOD); provenance contributions carry
observation_type, delta_bps, reason ∈ stale | not_comparable | temporal_mismatch | validation_only | validator_disagrees | outlier.
| Method & path | Purpose |
|---|---|
GET /health |
liveness (db, connectors healthy, quotes cached) |
GET /status |
public status components (website, api, stream, ingestion, source groups) |
GET /stats |
homepage telemetry — real counters only |
GET /metrics |
Prometheus exposition |
GET /instruments?asset_class&exchange&country&q"ed=1&sort&limit&offset |
instrument list with quotes |
GET /instruments/:idOrSymbol |
instrument + company + exchange status + quote + aliases + sources + related (NASDAQ:AAPL form accepted) |
GET /quotes/:idOrSymbol · GET /quotes?ids=a,b |
canonical quotes |
GET /quotes/:id/provenance |
Why this price? — contributions, weights, inclusion reasons, method, versions |
| `GET /history/:id?resolution=1m | 5m |
GET /events?type&instrument&country&asset_class&severity&since&before&limit · GET /events/:id |
canonical market events |
GET /filings?form&cik&q&limit&offset |
regulatory filings |
GET /search?q |
hybrid search (exact/prefix/alias/name), grouped by asset class / exchange / country |
GET /markets |
global overview: indices, crypto, forex, rates, commodities, equities, gainers/losers, exchanges with status, breadth |
| `GET /breadth?scope=world | US |
| `GET /changes?window=1m | 5m |
GET /exchanges · GET /exchanges/:id |
venues, status/next transition, holidays, breadth, movers, events |
GET /countries · GET /countries/:code |
country atlas page data |
GET /compare?ids=a,b,c&resolution=1d&limit |
normalized series, return/vol/drawdown, correlations |
GET /sources · GET /connectors · GET /data-health |
source directory (with role contributor/validator and likely_shared_upstream_with), public connector table, data-health dashboard |
GET /coverage?asset_class&tier&limit · GET /coverage/:id |
Source Coverage Engine: redundancy histogram (≥5/≥3/≥2/1 families), weighted score, tier attainment, expansion queue, inferred shared upstreams; per-instrument coverage |
GET /admin/lineage |
all statistically compared source pairs with similarity |
GET /stream (WebSocket) · GET /sse?channels= |
live stream — see below |
| `GET /admin/overview | connectors |
Stream protocol
Client → server: {"action":"subscribe","channels":["quotes:AAPL","quotes:crypto_btc_usd","quotes:*","quotes:class:CRYPTO","events:*","events:US","events:type:TRADING_HALT","market:xnas","tape"]},
{"action":"unsubscribe",…}, {"action":"ping","id":1}.
Server → client: hello, subscriptions, heartbeat (25 s), pong, error, and batches at ≤ 10 Hz per client:
{"type":"batch","seq":12,"ts":…,"messages":[{"type":"quote","instrument_id","symbol","price","change","change_pct","bid","ask","volume","currency","timestamp","received","confidence","sources","status"}, {"type":"event","event":{…}}, {"type":"market_state","exchangeId","state","at"}]}.
quotes:* is throttled to one quote per instrument per 500 ms; explicit quotes:<id> subscriptions receive every recomputation.
seq is per client; a gap means the client missed batches (backpressure drops oldest). Withheld (non-redistributable) values are never streamed.