Skip to content

Guide

WebSockets

One path per kind of event, one JSON message per frame, delivered when the event happens. Streaming needs API Pro.
On this page

Connecting#

Upgrade request

wss://api.ordermap.si/v1/ws/options/trades?symbols=SPXW&min_premium=100000
Authorization: Bearer om_...
  • Send the key in the Authorization or X-API-Key header of the HTTP upgrade request. A key in the query string is rejected. The upgrade counts as one request against your rate limit.
  • The query string can carry an initial subscription: symbols (comma-separated) and the stream's filters. You can also subscribe after connecting.
  • One connection per account per stream. A second upgrade on a stream that already has a connection is refused with 409 stream_connection_limit before the upgrade, and the first connection is not disturbed. A client that crashed is noticed within about 20 seconds, after which you can reconnect.
  • Errors before the upgrade are ordinary JSON errors: 400 (bad symbols or filters), 401, 403 (streaming_not_in_plan, dataset_release_restricted, account_suspended), 409, 426 upgrade_required (not a WebSocket request), 429 (rate limit or cooldown) and 503 stream_unavailable (the stream is not running; retry after Retry-After).

Node.js, with the ws package: the key stays on the server

import WebSocket from "ws";

const ws = new WebSocket("wss://api.ordermap.si/v1/ws/options/trades?symbols=SPXW&min_premium=100000", {
  headers: { Authorization: `Bearer ${process.env.ORDERMAP_API_KEY}` },
});

ws.on("message", (raw) => {
  const message = JSON.parse(raw.toString());
  if (message.type === "event") console.log(message.seq, message.data.option_symbol, message.data.premium);
  if (message.type === "gap") console.warn("continuity lost: refetch through REST", message);
  if (message.type === "error") console.error(message.code, message.message);
});
ws.on("close", (code, reason) => console.log("closed", code, reason.toString()));

// Change the subscription while connected:
ws.on("open", () => {
  ws.send(JSON.stringify({ action: "subscribe", symbols: ["SPXW", "SPY"], filters: { side: ["above_ask", "at_ask"] } }));
});

From a browser#

A browser cannot set headers on a WebSocket object, so it sends the key as a subprotocol: new WebSocket(url, ["ordermap.v1", "ordermap.key.om_..."]). The server reads it only on an upgrade to a stream (a path under /v1/ws/) that has neither an Authorization nor an X-API-Key header and offers ordermap.v1. It answers with Sec-WebSocket-Protocol: ordermap.v1, never repeats or logs the key, and treats it exactly like a bearer key: the same rate limit, abuse checks and 30-second revalidation.

// A browser cannot set headers on a WebSocket: the key travels as a subprotocol.
const ws = new WebSocket("wss://api.ordermap.si/v1/ws/futures/trades?symbols=ES", ["ordermap.v1", "ordermap.key." + key]);

Messages#

The protocol is ordermap.v1. Every message is one JSON text frame.

DirectionMessageMeaning
server{"type":"hello","protocol":"ordermap.v1","event_type":...,"heartbeat_ms":10000,"max_symbols":100,"wildcard":true,"filters":{...}}First message. Describes the stream and its filters.
server{"type":"subscribed","event_type":...,"symbols":[...],"filters":{...}}The current subscription, sent after every change (* for a wildcard).
server{"type":"status","event_type":...,"symbol":...,"state":"live","reason":...}state is live, degraded or unavailable.
server{"type":"gap","event_type":...,"symbol":...,"reason":...}Continuity was lost. Refetch the missed range through REST.
server{"type":"error","code":...,"message":...,"symbol":...}A request message was refused.
server{"type":"event","event_type":...,"seq":N,"data":{...}}One event. seq counts the connection's events from 1.
client{"action":"subscribe","symbols":["SPXW"],"filters":{"min_premium":100000}}Adds symbols. filters, when present, replace the previous filters ({} clears them).
client{"action":"unsubscribe","symbols":["SPXW"]}Removes symbols. With no symbols, removes everything.

The first message

{"type":"hello","protocol":"ordermap.v1","event_type":"options.trades","heartbeat_ms":10000,"max_symbols":100,"wildcard":true,"filters":{}}
  • One event per message, delivered when it happens. There is no timed batching and no resend buffer. Value-style streams (index values, basis, forming bars) are limited to 60 events per second per symbol. The futures quote, depth and bar streams, the index value stream and the basis stream send the latest state right after you subscribe. Trade streams start with the next trade.
  • After a disconnect there is no replay. Reconnect, resubscribe and use the REST endpoints for anything you missed. A gap message tells you when continuity was lost while connected.
  • Cancelled option prints are not retracted on the stream. Reconcile through the REST trades endpoint, which leaves cancelled prints out.
  • Symbols are validated per stream. A family symbol (SPX, NDX, RUT, VIX) also selects its weekly root (SPXW, NDXP, RUTW, VIXW), and a futures product (ES) selects its front contract, so on one socket you cannot subscribe to both a family and one of its members (overlapping_symbols). Option-stream symbols are option roots.

Error messages#

The code of an error message is one of: invalid_message, unknown_action, invalid_symbol, too_many_symbols, wildcard_not_allowed, overlapping_symbols, invalid_filter, symbol_unavailable (the symbol cannot be served on this stream), capacity and account_capacity (too many subscriptions in the service, or held by your account alone), and inbound_rate_limited.

Keepalive and limits#

  • The server pings every 10 seconds and closes a connection that has not answered (or sent any frame) within 20 seconds. Standard WebSocket libraries answer pings automatically.
  • Client messages are limited to 4 KiB and 10 per second. More closes the connection with 1008.
  • At most 100 symbols per connection, fewer on some streams (see the table below). A stream that accepts * takes it only as the sole subscription.
  • Each connection has an outbound queue of 4,096 messages or 4 MiB. A client that cannot keep up is closed with 4008 slow_consumer instead of silently losing events.
  • Your key, project, account and plan are re-checked every 30 seconds.

Close codes#

CodeReasonMeaning
1000, 1001server_shutdownNormal close, or the service is restarting. Reconnect.
1008inbound_rate_limitedYou sent more than 10 messages a second.
1009message_too_bigA client message was larger than 4 KiB.
1013cooldown retry_after_ms=N, state_unavailableTry again later. For a cooldown the reason says when.
4008slow_consumerThe connection fell too far behind.
4401unauthorizedThe key was revoked or the account became unavailable.
4403forbidden, plan_changed, account_suspendedYour plan, a dataset release or your standing no longer allows the stream.

Streams#

Each stream has a page in the reference with its filters, the event schema and an example event. The symbol limit is per stream.

StreamEvent typeDeliversSymbolsFilters
/v1/ws/options/flowoptions.flowConsolidated sweeps, splits and blocks.up to 100contract_typesidemin_sizemin_premiummax_premiumtrade_typesentimentmin_dtemax_dte
/v1/ws/options/tradesoptions.tradesEvery classified option print.up to 100 or *contract_typesidemin_sizemin_premiummax_premium
/v1/ws/options/unusualoptions.unusualUnusual option activity.up to 100contract_typesidemin_sizemin_premiummax_premiumtrade_typesentimentmin_dtemax_dte
/v1/ws/futures/barsfutures.barsFutures one-minute bars.up to 25none
/v1/ws/futures/depthfutures.depthFutures market depth.up to 10none
/v1/ws/futures/quotesfutures.quotesFutures best bid and offer.up to 25none
/v1/ws/futures/tradesfutures.tradesFutures trades.up to 25min_sizeside
/v1/ws/indices/basisindices.basisIndex versus futures-implied value.up to 10none
/v1/ws/indices/valuesindices.valuesCash index values.up to 100none
/v1/ws/stocks/barsstocks.barsStock second and minute bars.up to 100interval
/v1/ws/stocks/blocksstocks.blocksLarge stock trades.up to 100min_sizemin_notional
/v1/ws/stocks/dark-poolstocks.dark_poolOff-exchange stock trades.up to 100min_sizemin_notional
/v1/ws/stocks/imbalancesstocks.imbalancesExchange auction imbalances.up to 100 or *none
/v1/ws/stocks/luldstocks.luldLimit up-limit down bands and halts.up to 100none
/v1/ws/stocks/quotesstocks.quotesStock national best bid and offer.up to 50none
/v1/ws/stocks/tradesstocks.tradesStock trades.up to 50min_sizemin_notional
/v1/ws/analyticsanalyticsSnapshots of streamable endpoints.20 subscriptionsnone

Analytics snapshots#

/v1/ws/analytics pushes the complete response of any REST endpoint marked streamable whenever its data changes. Each subscription names an endpoint and its ordinary query parameters:

Subscribe

{"action":"subscribe","id":"levels","route":"/v1/options/levels","params":{"underlying_symbol":"SPX"},"interval_ms":5000}

The hello message lists the streamable endpoints with their minimum refresh interval (routes[].min_interval_ms, from half a second to five seconds) and max_subscriptions (20). The server answers with subscribed (the subscriptions with the interval applied), then sends events:

Event

{"type":"event","event_type":"analytics","seq":1,"data":{"id":"levels","route":"/v1/options/levels","revision":"1","resync":true,"response":{"data":{},"meta":{}}}}
  • response is the endpoint's usual {data, meta} envelope, always the full snapshot, never a delta. revision increases with each change of the data, and resync is true on the first snapshot after subscribing. Send {"action":"unsubscribe","id":"levels"} to stop one subscription (no id stops all).
  • id is yours: up to 64 letters, digits, _, -, ., :. Re-subscribing with the same id replaces the subscription. interval_ms can only slow a subscription down (up to one hour), never below the endpoint's minimum.
  • An account's subscriptions together may refresh at most 10 times a second (the sum of 1/interval). Beyond that the subscribe is refused with poll_budget_exceeded: choose longer intervals. Subscriptions with the same endpoint and parameters share one refresh.
  • A paginated endpoint streams its first page: has_more is reported and next_cursor_id and next_url are null. Results larger than 4 MiB are not streamed (response_too_large).
  • Under heavy load a refresh can be skipped and retried about one interval later, so a snapshot may arrive late. After several skipped refreshes in a row the server sends a status message with state: degraded and reason: refresh_delayed, and state: live when refreshes resume. Load never produces an error message.
  • Other analytics errors: invalid_route (not streamable; see /v1/catalog), too_many_subscriptions and invalid_filter (bad params).

Streamable endpoints#

EndpointReturns
/v1/options/contractsContracts of an underlying: those listed now, or those quoted on a past date.
/v1/options/chainThe option chain: quotes, day statistics, open interest and Greeks of every contract.
/v1/options/flow/by-expirationCall and put premium, volume and net flow for each expiration.
/v1/options/flow/by-strikeCall and put premium and volume at every strike, by aggressor class.
/v1/options/flow/exchangesMarket share of option premium, volume and trades by exchange.
/v1/options/flow/leadersUnderlyings or contracts leading option flow: top premium, bullish, bearish and movers.
/v1/options/flow/net-driftNet call and put premium per bucket and cumulatively over the session.
/v1/options/flow/net-flowNet premium or net volume per bucket for calls, puts and overall.
/v1/options/flow/overnightOvernight (global trading hours) option prints.
/v1/options/flow/premium-driftCumulative signed premium of calls, puts and net sentiment over the session.
/v1/options/flow/put-call-ratioPut/call volume and premium ratios per bucket and cumulatively.
/v1/options/flow/statsPremium, volume and trades of a filtered option print set, by contract type and aggressor side.
/v1/options/flow/strike-activityExecuted premium and trade counts per strike (SPX and SPXW).
/v1/options/exposure/by-expirationModeled dealer gamma, delta, vanna or charm exposure by expiration.
/v1/options/exposure/by-strikeModeled dealer gamma, delta, vanna or charm exposure by strike.
/v1/options/exposure/forecastModeled levels repriced at intraday horizons with a statistical cone.
/v1/options/exposure/heatmapStrike by expiration grid of modeled exposure, open interest or flow.
/v1/options/exposure/intervalsModeled exposure by strike at every interval of a session.
/v1/options/exposure/profileModeled exposure repriced over a sweep of underlying prices, with zero crossings.
/v1/options/exposure/surfaceDense strike by expiration surface of net modeled exposure for 3D views.
/v1/options/levelsKey levels of the modeled dealer exposure: walls, gamma flip, largest cell, max pain, expected move.
/v1/options/market-mapModeled exposure and executed flow by strike for SPX and SPXW.
/v1/options/open-interestOpen interest by strike or by expiration.
/v1/options/volatility/driftIntraday implied volatility against adjusted realized volatility.
/v1/options/volatility/skewImplied volatility smile by strike and delta, with risk reversals and butterflies.
/v1/options/volatility/surfaceImplied volatility surface by strike and expiration.
/v1/options/volatility/surface-sliceOne strike across expirations, or one expiration across strikes, of the volatility surface.
/v1/options/volatility/term-structureAt-the-money implied volatility by expiration, constant-maturity points and forward volatilities.
/v1/futures/bookThe current displayed depth of a futures contract.
/v1/futures/liquiditySpread and displayed liquidity of a futures contract.
/v1/futures/snapshotLast trade, top of book and session OHLCV of a futures contract.
/v1/futures/cvdCumulative volume delta of a futures session.
/v1/futures/delta-barsBuy, sell and net volume per bar.
/v1/futures/footprintFootprint bars: volume by price inside each bar, with imbalances.
/v1/futures/order-flowAggregated futures prints (order-flow bubbles) for a window.
/v1/futures/session-profileVolume profile of the whole current trading session (POC, VAH, VAL).
/v1/futures/volume-profileVolume by price for a window, with point of control and value area.
/v1/indices/snapshotCurrent value and session range of up to 50 indices.
/v1/indices/basis/snapshotLive basis, fair value and premium of up to 10 indices.
/v1/stocks/moversTop 20 gainers or losers of the day.
/v1/stocks/snapshotCurrent-day snapshot of up to 50 stocks.
/v1/market/overviewOne-call picture of the market: indexes, futures, volatility and breadth.
/v1/market/statusTrading state of the US equity market and health of the data areas.