Skip to main content
This guide walks you through verifying the service, listing markets, submitting your first order, and connecting to the WebSocket for live market data.
You need an API key to place orders and view account state. An operator must provision your trader account. If you don’t have a key yet, ask your exchange operator.

Prerequisites

  • An assigned API key (format: exch_<32-hex-chars>, e.g. exch_1d4208be6fa84b8cb0a2e5cfa9508d5f)
  • curl or any HTTP client
  • For WebSocket: a browser console, websocat, or any WebSocket client

1

Check service health

Verify the exchange is live before trading.
curl https://exchange.jamesxu.dev/health
Expected response when healthy:
{
  "status": "ok",
  "service": "exchange",
  "now": "2026-03-18T15:00:00Z",
  "persistence": {
    "mode": "postgres",
    "status": "ok"
  }
}
If status is "degraded", the persistence backend is unhealthy (retrying, backpressured, or stopped). Trading continues in memory, but data may not be fully persisted.
2

List available markets

Discover which markets are configured and their trading parameters.
curl https://exchange.jamesxu.dev/api/v1/markets
Example response:
[
  {
    "market_id": "BTC-USD",
    "display_name": "Bitcoin",
    "base_asset": "BTC",
    "quote_asset": "USD",
    "tick_size": 1,
    "min_order_quantity": 1,
    "reference_price": 100,
    "enabled": true,
    "settled": false
  }
]
Note the tick_size and min_order_quantity for each market — your order price must be a multiple of tick_size and quantity must be at least min_order_quantity.
3

Submit your first order

Place a limit buy order for 2 units of BTC-USD at price 100.
curl -X POST \
  -H "x-api-key: YOUR_API_KEY" \
  -H "content-type: application/json" \
  https://exchange.jamesxu.dev/api/v1/orders \
  -d '{"market":"BTC-USD","side":"BUY","price":100,"quantity":2}'
Example response (order rested, no immediate fill):
{
  "order": {
    "id": "66377526-7b98-485a-8c40-7024e68fa3c5",
    "trader_id": "9d64e278-8b56-46e9-9cab-18c5b22f2fb9",
    "market": "BTC-USD",
    "side": "BUY",
    "price": 100,
    "quantity": 2,
    "remaining": 2,
    "created_at": "2026-03-18T15:28:01.342510Z"
  },
  "fills": [],
  "resting": true
}
If the order crosses with a resting sell order, fills will be non-empty and resting may be false (fully filled) or true (partially filled).
Orders are rate-limited to 100 per second per user. Exceeding this returns a 429 status.
4

View your open orders and fills

Check your current resting orders and executed trades.
curl -H "x-api-key: YOUR_API_KEY" \
  'https://exchange.jamesxu.dev/api/v1/open-orders?market=BTC-USD'
The ?market=BTC-USD query parameter is optional — omit it to see all markets.
5

Connect to WebSocket and subscribe to market data

Subscribe to live L3 orderbook updates.
const socket = new WebSocket("wss://exchange.jamesxu.dev/ws");

socket.addEventListener("open", () => {
  // Subscribe to L3 orderbook for BTC-USD
  socket.send(JSON.stringify({
    op: "subscribe",
    channel: "l3",
    market: "BTC-USD",
    last_sequence: null,
  }));
});

socket.addEventListener("message", (event) => {
  const msg = JSON.parse(event.data);

  switch (msg.type) {
    case "snapshot":
      // Full orderbook state — initialize your local book
      console.log("Snapshot:", msg.sequence, msg.bids, msg.asks);
      break;
    case "delta":
      // Incremental update — apply to local book
      console.log("Delta:", msg.sequence, msg.events);
      break;
    case "resync_required":
      // Gap detected — resubscribe for a fresh snapshot
      console.warn("Resync required:", msg.reason);
      socket.send(JSON.stringify({
        op: "subscribe",
        channel: "l3",
        market: "BTC-USD",
        last_sequence: null,
      }));
      break;
    case "heartbeat":
      // Keep-alive — no action needed
      break;
  }
});
You receive one snapshot message immediately after subscribing, followed by delta messages for every subsequent change. Always track the sequence number and resubscribe if you receive resync_required.
6

Authenticate on WebSocket and receive order events

Authenticate your WebSocket session to enable trading and receive user-scoped events.
const socket = new WebSocket("wss://exchange.jamesxu.dev/ws");

socket.addEventListener("open", () => {
  // Authenticate first
  socket.send(JSON.stringify({
    op: "authenticate",
    api_key: process.env.EXCHANGE_API_KEY,
  }));

  // Market data subscription (can be sent before or after auth)
  socket.send(JSON.stringify({
    op: "subscribe",
    channel: "l3",
    market: "BTC-USD",
    last_sequence: null,
  }));
});

socket.addEventListener("message", (event) => {
  const msg = JSON.parse(event.data);

  switch (msg.type) {
    case "authenticated":
      console.log("Authenticated as", msg.username);
      // Now submit an order via WebSocket
      socket.send(JSON.stringify({
        op: "submit_order",
        request_id: "req-1",
        market: "BTC-USD",
        side: "BUY",
        price: 100,
        quantity: 2,
      }));
      break;
    case "ack":
      console.log("Order acknowledged:", msg.request_id);
      break;
    case "reject":
      console.error("Order rejected:", msg.code, msg.message);
      break;
    case "fill":
      console.log("Fill received:", msg.fill);
      break;
    case "order_state":
      console.log("Order state update:", msg.order, msg.status);
      break;
    case "admin_message":
      console.log("[Admin]", msg.message.title, msg.message.body);
      break;
  }
});
Using WebSocket for order entry gives you real-time fill and order_state events pushed directly to your client without polling.

What’s next

REST API reference

Full documentation for every REST endpoint, request/response schema, and auth requirements.

WebSocket API

Complete message reference for all client and server WebSocket message types.

Error codes

HTTP status codes and WebSocket reject/error code reference.

Examples

More concrete curl, JavaScript, and Python examples.

Build docs developers (and LLMs) love