Requires Quant Subscription
⚠️ Data is only published during New York Stock Exchange cash hours (9:30 AM–4:00 PM ET).
Provides real-time, low-latency market data via WebSocket.
- Make a
GET /negotiaterequest (with required headers) to receive connection URLs and the groupPREFIX. - Connect to a hub (e.g.,
classic,state) and join groups (e.g.,blue_SPX_state_gamma_zero) to subscribe.
{
"websocket_urls": {
"classic": "wss://ws.gex.bot:443/client/hubs/classic?access_token=<access_token>",
"state_gex": "wss://ws.gex.bot:443/client/hubs/state_gex?access_token=<access_token>",
"state_greeks_zero": "wss://ws.gex.bot:443/client/hubs/state_greeks_zero?access_token=<access_token>",
"state_greeks_one": "wss://ws.gex.bot:443/client/hubs/state_greeks_one?access_token=<access_token>",
"orderflow": "wss://ws.gex.bot:443/client/hubs/orderflow?access_token=<access_token>"
},
"prefix": "blue"
}Messages are Zstandard-compressed Protobufs.
- Each Quant subscriber is allowed 1 active connection per hub. Additional requests to
/negotiatewill kick all existing connections. - To maintain multiple hub connections simultaneously, use the authorized hub endpoints from a single negotiate request and connect to each hub within 15 minutes.
- If a hub connection is dropped more than 15 minutes after negotiating, you must re-negotiate and re-connect to each hub.
wscat is a command-line WebSocket client useful for verifying connectivity, join/leave group flow, and raw message delivery without writing any application code.
npm install -g wscatUse the full URL from the /negotiate response and specify the Azure Web PubSub subprotocol:
wscat -c "wss://ws.gex.bot:443/client/hubs/orderflow?access_token=<access_token>" \
--subprotocol json.webpubsub.azure.v1Replace <access_token> with the token from the corresponding websocket_urls entry in the negotiate response. Swap orderflow for any other hub name as needed.
Once connected, send a joinGroup message. The group name must use the prefix returned by /negotiate:
{"type":"joinGroup","group":"blue_SPX_orderflow_orderflow","ackId":1}A successful join returns an ack:
{"type":"ack","ackId":1,"success":true}If success is false, double-check the hub/group pairing and that the prefix matches the negotiate response.
| Symptom | Likely cause |
|---|---|
| Connection closes immediately | Token expired or /negotiate was called again after connecting |
Ack returns success: false |
Wrong hub for the group, or malformed group name |
| Connection succeeds but no messages arrive | Outside NYSE cash hours, or group name prefix is wrong/hardcoded |
| Binary messages received | Expected — messages are Zstandard-compressed Protobufs and won't be human-readable in wscat |
Cause: Calling /negotiate more than once before all hub connections are established.
Each call to /negotiate invalidates all previously issued access tokens and kicks any existing connections. If you negotiate a second time while still connecting to hubs from the first response, those connections will be dropped.
Fix: Call /negotiate exactly once, store the full response, then open all desired hub connections using the URLs from that single response. Only re-negotiate when a connection expires (beyond 15 minutes) or is lost.
Cause: Subscribing to groups on the wrong hub, or using a hardcoded prefix instead of the one returned by /negotiate.
Each hub only routes messages for its own groups:
| Hub | Group prefix pattern | Example group |
|---|---|---|
classic |
{prefix}_{ticker}_classic_{category} |
blue_SPX_classic_gex_full |
state_gex |
{prefix}_{ticker}_state_gex_{category} |
blue_SPX_state_gex_gamma |
state_greeks_zero |
{prefix}_{ticker}_state_greeks_zero_{category} |
blue_SPX_state_greeks_zero_delta |
state_greeks_one |
{prefix}_{ticker}_state_greeks_one_{category} |
blue_SPX_state_greeks_one_delta |
orderflow |
{prefix}_{ticker}_orderflow_{category} |
blue_SPX_orderflow_orderflow |
Joining a state_gex group on the classic hub (or vice versa) will silently succeed but never deliver messages.
Fix: Always connect to the hub that matches the group you want, and always construct group names dynamically using the prefix field from the /negotiate response — do not hardcode it. The prefix can change between negotiate calls.
Yes. You are allowed 1 active connection per hub, so you can hold connections to all hubs at the same time from a single subscription.
No. The only limit is 1 connection per hub. There is no additional cap on the number of hubs you connect to concurrently.
No, with one important exception: calling /negotiate again.
- Connecting to a different hub (e.g., connecting to
state_gexwhile already connected toclassic) using the same original/negotiateresponse will not affect your existing connection. - Connecting to the same hub again using the same URL from the
/negotiateresponse will disconnect your previous connection to that specific hub, because you are only allowed one active connection per hub. - Calling
/negotiatea second time to get new credentials will immediately invalidate all access tokens from the first response and kick all active connections.