Connect & authenticate

Open the WebSocket, send an auth frame, and subscribe to channels.

Endpoints

Open a WebSocket to /ws on the same host as the REST API:

wss://api.drazill.com/ws # production (live)
wss://staging.drazill.com/ws # staging (paper) — use this with a drzl_test_ key

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:

1{ "type": "auth", "token": "<jwt-access-token>" }
1{ "type": "auth", "api_key": "<your-api-key>" }

An API key used on the WebSocket must carry the websocket scope. Both key classes authenticate the feed: a drzl_test_ key and a drzl_live_ key are accepted the same way — the key class governs paper-vs-live routing for REST trading writes, not the read/subscribe-oriented WebSocket feed. 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, your private user:{your_id} channel is auto-subscribed:

1{ "type": "connected", "session": "", "authenticated": true, "channels": ["user:018f…"] }

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.

1{ "type": "subscribe", "channels": ["prices:018f-outcome", "trades:018f-market"] }

The server acknowledges with the accepted channels, any rejects with a reason, and a replay summary per channel:

1{
2 "type": "subscribed",
3 "channels": ["prices:018f-outcome", "trades:018f-market"],
4 "rejected": [],
5 "errors": {},
6 "replayed": {}
7}

A rejected private channel comes back in errors with a structured reason (AUTH_REQUIRED, FORBIDDEN, UNKNOWN_CHANNEL, or TIER_NOT_ENTITLED).

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):

1import asyncio
2from drazill import DrazillWebSocket
3
4async def main():
5 # Defaults to wss://staging.drazill.com/ws — pass url=... for production.
6 ws = DrazillWebSocket(api_key="drzl_test_...") # key must have the websocket scope
7 await ws.subscribe("prices:018f-outcome")
8 async for message in ws.listen(): # auto-reconnects; replies to pings
9 print(message["type"], message.get("data"))
10
11asyncio.run(main())

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.