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
    }
  }
}
FieldTypeDescription
methodstringMust be "post"
idintClient-assigned request ID for correlating responses
request.typestringMust be "exchange"
request.payloadObjectSame 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 TypeDescription
orderPlace one or more orders
cancelCancel orders by order ID
cancelByCloidCancel orders by client order ID
modifyModify an existing order
usdTransferTransfer USD between addresses
withdrawWithdraw from bridge
updateLeverageChange leverage for an asset
approveAgentAuthorize/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

  1. Use unique request IDs. Monotonically increasing integers work well. This allows you to correlate responses to requests.
  2. Implement timeouts. If no response arrives within 5 seconds, consider the request failed and retry or escalate.
  3. Combine with subscriptions. Subscribe to orderUpdates and userFills on the same connection to get immediate feedback on your orders.
  4. Fall back to REST. If the WebSocket connection drops, use the REST endpoint while reconnecting.