Authentication
The WebSocket isn’t authenticated byapi-key (browsers can’t send
custom headers on WebSocket upgrades). Instead, mint a short-lived JWT
ticket through the API, then pass it as a ?token= query string.
Mint a ticket
Call
POST /auth/ws-token with On-Behalf-Of set to the sub-user
you want to subscribe as. Each ticket is bound to that one sub-user.Open the socket
The token can ride in either of two slots. The subprotocol form is
preferred — the token isn’t logged by proxies / browser history /
access logs the way query strings are:The server verifies the ticket on upgrade. Bad token → close code
4001 Invalid token.Protocol
- Read-only. Sending any frame to the server closes the socket with
4002 Read-only. The protocol carries server pushes only. - Heartbeats. The server sends WS pings; respond with pongs to keep the connection alive (most clients do this automatically).
- Frame shape. Every push is
{ event, data, ts }—eventis a string discriminator,tsis Unix epoch milliseconds.
Events
Discriminating deposits
Gateway-hosted deposits (Gate Pay, on-ramp) and self-hosted EVM crypto share event names but carry different keys:| Event | Gateway | Self-hosted crypto |
|---|---|---|
deposit.completed | has fundingId, payAmountToken, receiveAmountUsd | has depositId, chain, token, txHash, amountWei, amountUsdCents, confirmations |
deposit.failed | has fundingId, status, reason | has depositId, chain, token, txHash, reason, confirmations |
Trade events
Fired on every status transition. The full trade payload is included so you can update your UI without a follow-up GET.Close codes
| Code | Reason | Cause |
|---|---|---|
| 4001 | Missing token | No ?token= query string |
| 4001 | Invalid token | Bad signature, expired, or wrong purpose |
| 4002 | Read-only | Client sent any frame after upgrade |
Reconnection
The server doesn’t rotate tokens on disconnect; the same ticket is valid until it expires (~1h). On disconnect:One sub-user per socket
A token is bound to theOn-Behalf-Of sub-user it was minted with — the
socket only delivers events for that user. To watch multiple sub-users,
mint a token per sub-user and open one socket each. There’s no
multi-subscription pattern on a single connection.
For server-side aggregation across many sub-users, prefer
Webhooks.