WebSocket Post Requests
In addition to receiving data, you can submit exchange actions (orders, cancels, etc.) directly through the WebSocket connection. This can provide lower latency than REST for order management since the connection is already established.
Request Format
{
"method": "post",
"id": 1,
"request": {
"type": "exchange",
"payload": {
"action": { ... },
"nonce": 1700000000123,
"signature": { "r": "0x...", "s": "0x...", "v": 27 },
"vaultAddress": null
}
}
}| Field | Type | Description |
|---|---|---|
method | string | Must be "post" |
id | int | Client-assigned request ID for correlating responses |
request.type | string | Must be "exchange" |
request.payload | Object | Same payload format as the REST POST /exchange endpoint |
Response Format
The server responds with a message containing the matching id:
{
"channel": "post",
"data": {
"id": 1,
"response": {
"status": "ok",
"response": {
"type": "order",
"data": { "statuses": [{ "resting": { "oid": 12345 } }] }
}
}
}
}Error responses:
{
"channel": "post",
"data": {
"id": 1,
"response": {
"status": "err",
"response": "Insufficient margin"
}
}
}Supported Actions
All actions supported by the REST POST /exchange endpoint are also available via WebSocket post:
| Action Type | Description |
|---|---|
order | Place one or more orders |
cancel | Cancel orders by order ID |
cancelByCloid | Cancel orders by client order ID |
modify | Modify an existing order |
usdTransfer | Transfer USD between addresses |
withdraw | Withdraw from bridge |
updateLeverage | Change leverage for an asset |
approveAgent | Authorize/revoke an API wallet |
Example: Place Order via WebSocket
TypeScript
const ws = new WebSocket("wss://api.gx.exchange/ws");
let requestId = 0;
const pendingRequests = new Map<number, (response: any) => void>();
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.channel === "post") {
const { id, response } = msg.data;
const resolve = pendingRequests.get(id);
if (resolve) {
resolve(response);
pendingRequests.delete(id);
}
}
};
function postExchange(action: any, nonce: number, signature: any): Promise<any> {
return new Promise((resolve) => {
const id = ++requestId;
pendingRequests.set(id, resolve);
ws.send(JSON.stringify({
method: "post",
id,
request: {
type: "exchange",
payload: { action, nonce, signature, vaultAddress: null }
}
}));
});
}
// Usage (after signing)
const response = await postExchange(
{
type: "order",
orders: [{
a: 0,
b: true,
p: "67000.0",
s: "0.01",
r: false,
t: { limit: { tif: "Gtc" } }
}],
grouping: "na"
},
Date.now(),
signature // EIP-712 signature object
);Python
import asyncio
import json
import websockets
async def post_order(ws, action, nonce, signature, request_id):
message = {
"method": "post",
"id": request_id,
"request": {
"type": "exchange",
"payload": {
"action": action,
"nonce": nonce,
"signature": signature,
"vaultAddress": None,
}
}
}
await ws.send(json.dumps(message))
# Wait for matching response
async for msg in ws:
data = json.loads(msg)
if data.get("channel") == "post" and data["data"]["id"] == request_id:
return data["data"]["response"]Info Requests via WebSocket
You can also submit info queries through the WebSocket:
{
"method": "post",
"id": 2,
"request": {
"type": "info",
"payload": { "type": "allMids" }
}
}Response:
{
"channel": "post",
"data": {
"id": 2,
"response": { "BTC": "67432.5", "ETH": "3521.2" }
}
}Best Practices
- Use unique request IDs. Monotonically increasing integers work well. This allows you to correlate responses to requests.
- Implement timeouts. If no response arrives within 5 seconds, consider the request failed and retry or escalate.
- Combine with subscriptions. Subscribe to
orderUpdatesanduserFillson the same connection to get immediate feedback on your orders. - Fall back to REST. If the WebSocket connection drops, use the REST endpoint while reconnecting.