Connect
Open a WebSocket to the gateway. Nothing is required at the handshake — no headers, no query parameters, no subprotocol.
Once open, the socket is immediately usable for
market data. Authentication is only needed for
your own account’s activity.
Market data needs no credential. If all you want is trades, order books,
tickers or implied values, skip this page and go straight to
Subscriptions.
Authenticate
To receive your own fills, orders and positions, send anauthenticate frame carrying an API key.
success frame, and you are subscribed to
your own event stream. You do not subscribe to it explicitly — authenticating
is what enrolls you.
prediction-market-update frames. These are
independent of any subscribe you have sent; authenticating does not disturb
your market-data subscriptions, and subscribing does not disturb your private
stream.
A failed
authenticate leaves the socket open for anonymous market data.
You receive an error frame and stay
connected, unauthenticated — there is no need to reconnect before retrying
with a working credential.API keys
Issue an API key from your SOAR account settings. Keys are prefixedsoar_sk_
and are shown once at creation — store the value then, because it is not
retrievable afterwards.
Scopes do not nest. A
trade-only key is rejected on the WebSocket with
forbidden_scope, exactly as it is on the REST portfolio endpoints. A key
needs read specifically.
Replacing a credential
Re-authenticating resolves the new credential first, then replaces the old one — so your private stream stays up for the length of the lookup. If the new credential fails, you are left unauthenticated rather than silently kept on the old one. Treat a failed re-authentication as “log in again”, not as “still logged in as before”. Only oneauthenticate may be in flight at a time. A second frame sent while
one is still resolving is rejected with authenticate_in_progress; wait for the
pending response and retry.
Revocation
Revoking a key stops the private stream within 60 seconds, matching the REST promise. The server sends anerror frame and then closes the socket:
Because the socket closes, your market-data subscriptions end along with the
private stream. Reconnect and resubscribe. Market data itself still needs no
credential, so an anonymous socket is enough to keep prices flowing while you
sort out the key.
Connection limits
Concurrent authenticated connections are capped at 5 per API key, counted across all servers. Excessauthenticate attempts are refused with an error frame carrying code
connection_limit. The socket stays open and market data keeps flowing, so
you do not need to reconnect — close one of your other authenticated sockets
and try again.
The limit is enforced best-effort rather than transactionally, so sockets
opening simultaneously on one key may briefly exceed it. Treat it as
back-pressure, not a guarantee, and do not design around the exact number.
Replacing REST polling
The private stream is a drop-in replacement for pollingGET /v1/portfolio/fills
and GET /v1/orders/{order_id}.
Start buffering incoming socket events, authenticate, and wait for the success
frame before loading history and current state over REST. Reconcile that response
with the buffered events, deduplicating fills by tradeId, then keep applying live
updates.
There is no atomic boundary between the REST response and the stream, and missed
events are not replayed. Loading REST history before authenticating can leave a
gap. Reconcile against REST after every reconnect.