Pred WebSocket API
PRED uses [Ably](https://ably.com/) for real-time WebSocket data. Use Ably's token auth with `POST /api/v1/auth/ably` as your `authCallback`. ## Token auth Call `POST /api/v1/auth/ably` to get raw Ably `TokenDetails` JSON: ```json { "token": "ably-token-string", "keyName": "xxxxx.xxxxx", "clientId": "user-uuid", "capability": "{\"private:user:user-uuid\":[\"presence\",\"subscribe\"],\"market:*\":[\"subscribe\"]}", "expires": 1700000000000, "issued": 1699996400000 } ``` **Capabilities granted:** - Channel `private:user:`: `presence`, `subscribe` - Channel `market:*`: `subscribe` ## Private user channel: `private:user:{userID}` - **Authenticated**: you can only subscribe to your own `user_id` channel - **Must subscribe with Presence** (see below) — PRED only pushes events to clients that have entered presence on this channel - `user_id` comes from the login response ## How to subscribe with presence For the private user channel, you must **enter presence** before subscribing; otherwise PRED does not deliver order events. Use Ably's presence API in this order: 1. Obtain a token: call `POST /api/v1/auth/ably` with `Authorization: Bearer ` (and optionally `X-Wallet-Address`, `X-Proxy-Address`). Use the returned body as Ably's token (e.g. in `authCallback`). 2. Connect to Ably with that token (e.g. `ably.NewRealtime` with `authCallback` that returns the token). 3. Resolve the channel name for your user (e.g. `private:user:` from login; the token's capability may also indicate the channel). 4. Get the channel: `channel := realtime.Channels.Get(channelName)`. 5. **Enter presence** on the channel: call `channel.Presence.Enter(ctx, data)` with a small payload (e.g. `map[string]string{"source": "your-app"}`). This step is required; PRED only sends events to clients that have entered presence. 6. Subscribe to messages: call `channel.SubscribeAll(ctx, messageHandler)` (or `channel.Subscribe(ctx, eventName, handler)` for specific events). Handle `order-created`, `order-cancelled`, `order-updated` (and optionally `order-adjusted` if supported). If you subscribe without entering presence first, you will not receive order events on the private user channel. **Events:** ### `order-created` — New limit order placed ```json { "order_id": "string", "market_id": "string", "market_name": "string", "parent_market_id": "string", "parent_market_name": "string", "side": "long | short", "price": "string (cents)", "quantity": "string (shares)", "amount": "string (USD)", "remaining_quantity": "string", "reduce_only": false, "market_maker": false, "expiration": 1234567890 } ``` ### `order-cancelled` — Order cancelled by user or system ```json { "event_type": "order_cancelled", "order_id": "string", "timestamp": 1234567890 } ``` ### `order-updated` — Order matched on-chain (fully or partially filled) ```json { "event_type": "order_matched_on_chain", "order_id": "string", "remaining_quantity": "string", "filled_quantity": "string", "timestamp": 1234567890 } ``` Note: `matched_on_chain` may be `false` before confirmation; treat as a fill and react. Position from API may not reflect the impact yet. The SDK also handles alternate payload shapes: fields like `order_side`, `order_price`, `order_quantity`, or a nested `order` object with `side`, `price`, `quantity`. Additional fields that may appear: `market_id`, `parent_market_id`, `side`, `price`, `quantity`. ## Public market channels ### `market:orderbook:{marketID}` — Order book snapshot Event name: `orderbook` (throttled to 100ms) ```json { "market_id": "string", "last_updated_at": "2024-01-01T00:00:00Z", "sequence_number": 123, "last_update_id": 123, "bids": [ { "price": "50", "quantity": "100", "total": "50" } ], "asks": [ { "price": "51", "quantity": "100", "total": "51" } ] } ``` The SDK also reads `size` as an alias for `quantity`, and `metadata.cross_matching_enabled` (boolean). ### `market:ltp:{marketID}` — Last traded price Event name: `ltp` (throttled to 100ms) ```json { "price": "string (cents)", "volume": "string", "timestamp": 1234567890 } ``` ## Connection details - Use Ably token auth with `authCallback` calling `POST /api/v1/auth/ably` - Reconnect with exponential backoff: 1s min, 30s max - On the private user channel, enter presence before subscribing (see "How to subscribe with presence" above)