Connect & authenticate
Connect & authenticate
Endpoints
Open a WebSocket to /ws on the same host as the REST API:
Authenticate
Authentication is the first message you send, not a query parameter or header. The socket accepts either a first-party JWT or an API key:
An API key used on the WebSocket must carry the websocket scope. Both key classes
authenticate the feed and read the same real market data, but the key class does
govern what you can subscribe to: a drzl_test_ key is refused the private
user:{your_id} stream, because that channel carries live-money activity. See
Test keys on the WebSocket below. Use a drzl_test_ key
against staging for the Playground.
You have a few seconds to send the auth frame after the socket opens. An anonymous connection (no auth frame, or an auth frame with no credentials) is allowed — it can subscribe to the public market-data channels but not to your private stream.
On success the server sends a connected frame; if you authenticated with a JWT or a
drzl_live_ key, your private user:{your_id} channel is auto-subscribed:
Test keys on the WebSocket
Live and test credentials are separated on the realtime surface the same way they are on
REST. With a drzl_test_ key:
- Public market-data channels work unchanged —
prices:,market:,category:, and (subject to your feed tier)orderbook:andtrades:. The sandbox reads the same real market data as production. user:{your_id}is refused with the error reasonTEST_KEY_LIVE_CHANNELin thesubscribedframe’serrorsmap. That channel carries real fills, real cancels and real wallet movements; a sandbox credential does not observe live money.- There is no auto-subscribe on connect, so the
connectedframe carries an emptychannelsarray. That is the sandbox boundary, not a failed handshake.
If you re-authenticate an existing live-key session with a test key, any user: channel
that connection already held is dropped at that point — the downgrade takes effect
immediately rather than at the next subscribe.
Paper (sandbox) order activity is delivered by webhooks with
livemode: false, not over the WebSocket. For a paper order lifecycle, wire the webhook;
for market data, use this feed with your test key.
JWT sessions and drzl_live_ keys are unaffected by any of the above.
Subscribe
Send a subscribe frame with up to 50 channels. Public channels need no auth; private
channels are authorized on subscribe and rejected (never silently dropped) if you may not
read them.
The server acknowledges with the accepted channels, any rejects with a reason, and a replay summary per channel:
A rejected private channel comes back in errors with a structured reason
(AUTH_REQUIRED, FORBIDDEN, UNKNOWN_CHANNEL, TIER_NOT_ENTITLED, or
TEST_KEY_LIVE_CHANNEL).
A minimal client (Python)
The official Python SDK ships a tested async WebSocket client that defaults to staging
and handles the auth frame, ping/pong, and reconnects for you (from
sdks/python/drazill/_websocket.py,
exercised by sdks/python/tests/test_websocket.py):
The client replies to the server’s ping with a pong for you. If you write your own
client, you must do the same — a missed pong past two heartbeat intervals closes the
socket. See Limits & retention.
Never paste a drzl_live_ key into a browser or client-side app. Use a drzl_test_
key against staging for anything interactive, including the Playground.

