About WebSocket API
The WebSocket API is in beta. The P&L and Portfolio streams work on paper and live today, but breaking improvements are in progress and are not finalized — connection handshake, subscription commands, message shapes, and field names will change.
Do not ship production integrations that cannot absorb breaking schema updates on short notice. Watch the Change Log for announcements; treat everything on these pages as subject to change before GA.
Overview
The TradeZero WebSocket API delivers real-time account data over persistent connections. Two separate streams are available, each at its own endpoint under the same base URL:
| Stream | Endpoint | What it delivers |
|---|---|---|
| P&L Stream | /stream/pnl | Account value, leverage, and per-position unrealized P&L - updated on every price tick |
| Portfolio Stream | /stream/portfolio | Order state changes and position updates driven by order fills and cancellations |
Base URL: wss://webapi.trade0.click/stream
Paper and live use the same WebSocket hosts as the REST API. Send the API key pair for the environment you want - paper keys stream paper account data; live keys stream live data. See Account Types and Authentication.
The two streams are independent connections. You open them in parallel and they each go through the same authentication handshake.
Connection and authentication
Every stream uses the same three-step handshake before data begins flowing.
Step 1 - Open the connection
Connect to the stream URL using a standard WebSocket client. No custom HTTP headers are needed.
wss://webapi.trade0.click/stream/pnl
wss://webapi.trade0.click/stream/portfolio
Immediately on connect the server sends a system message:
{
"@system": true,
"ts": 1700000000000,
"status": "PENDING_AUTH",
"message": "Send authenticate message"
}
The server re-sends PENDING_AUTH every 5 seconds until credentials are received. The connection is not closed for inactivity - it stays open indefinitely waiting for auth.
Step 2 - Send credentials
Respond with your API key and secret as a JSON object. The field names are key and secret:
{
"key": "YOUR_TZ-API-KEY-ID",
"secret": "YOUR_TZ-API-SECRET-KEY"
}
The auth payload uses key and secret. The field names are case-insensitive - Key/Secret (capitalized) is accepted the same as key/secret. Using any other name such as apiKey/apiSecret is treated as missing credentials and returns FAILED_AUTH.
Step 3 - Send your subscribe payload
Once the server responds with CONNECTED, immediately send the stream-specific subscribe payload. See the individual stream pages for the exact format.