Skip to main content
Connect to wss://api.testnet.arcus.xyz/v1/ws (mainnet: wss://api.arcus.xyz/v1/ws). The connection multiplexes channel subscriptions and request/response (RPC) calls.

Message envelopes

Subscribe / unsubscribe:
{ "type": "subscribe",   "channel": "<channel_name>", "id": "<subscription_id>" }
{ "type": "unsubscribe", "channel": "<channel_name>", "id": "<subscription_id>" }
The server replies with { "type": "subscribed", ... } and then streams { "type": "channel_data", ... } updates carrying a publishTimestampMs and a contents payload. Request / response: every post and get message must include a numeric id chosen by the client. The server echoes the same id in its response. IDs do not need to increase — uniqueness among in-flight calls on the connection is sufficient.
{
  "type": "get",
  "id": 2,
  "request": {
    "type": "l2orderbook",
    "payload": { "market": "BTC-PERP" }
  }
}
See Authentication for the signing rules that apply to order methods.

Placing orders

Order methods are asynchronous. The server returns 202 with status: "ACK" (or CANCEL_ACKNOWLEDGED); subscribe to the orders or userFills channels to observe the lifecycle.
{
  "type": "post",
  "id": 1,
  "request": {
    "type": "placeOrder",
    "payload": {
      "address": "0x...",
      "accountIndex": 0,
      "marketId": 0,
      "orderSide": "BUY",
      "orderType": "LIMIT",
      "timeInForce": "GTT",
      "goodTilTime": "4102444800000000",
      "quantity": "0.01",
      "price": "50000"
    },
    "apiKey": "<64-hex-public-key>",
    "timestamp": "1712345678000",
    "signature": "<128-hex-signature>"
  }
}
Server response:
{
  "method": "placeOrder",
  "id": 42,
  "status": 202,
  "result": { "orderId": "...", "status": "ACK" }
}
batchModifyOrders is not yet implemented and returns 501.

Channels

See the Channels reference for the full list and per-channel payload schemas.

Sequence numbers

Streamed messages carry sequence numbers so you can order events, detect dropped messages, and resync after a reconnect. Three scopes exist:
  • Global — one monotonic counter across the whole exchange, incremented for every event the matching engine processes. Use it to order events across markets and to tell whether you’ve missed anything.
  • Per-market — a counter local to a single market.
  • Per-account — a counter local to a single account.
Which field carries the sequence depends on the message:
ScopeFieldAppears on
GlobalglobalSequenceIdl2Orderbook, l2OrderbookUpdates
GlobalsequenceNumbertrades
Per-market (order book)lastSequenceIdl2Orderbook, l2OrderbookUpdates
Per-market (market attributes)marketSequenceNumMarketAttributesUpdate
Per-accountsequenceNumAccountUpdate (REST schemas expose the same value as accountSequenceNum)

Resyncing the order book

For l2Orderbook, the snapshot’s lastSequenceId is the per-market sequence of the last update it reflects. Apply only l2OrderbookUpdates deltas whose lastSequenceId is greater than the snapshot’s — they’re monotonic and continuous, so a gap means you missed a delta and should re-subscribe for a fresh snapshot. Use globalSequenceId to order order-book events against other markets.
The trades message — including its sequenceNumber — is expected to change when counterparty information is added, so treat that field as provisional.

Errors

Responses include an HTTP-like status and either a result or an error object with type, message, and optional field details.