> ## Documentation Index
> Fetch the complete documentation index at: https://docs.arcus.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# WebSocket

> Real-time market data and order routing

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:**

```json theme={null}
{ "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.

```json theme={null}
{
  "type": "get",
  "id": 2,
  "request": {
    "type": "l2orderbook",
    "payload": { "market": "BTC-PERP" }
  }
}
```

See [Authentication](/api-reference/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`](/api-reference/channels#orders) or [`userFills`](/api-reference/channels#userfills) channels to observe the lifecycle.

```json theme={null}
{
  "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:

```json theme={null}
{
  "method": "placeOrder",
  "id": 42,
  "status": 202,
  "result": { "orderId": "...", "status": "ACK" }
}
```

`batchModifyOrders` is not yet implemented and returns `501`.

## Channels

See the [Channels](/api-reference/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:

| Scope                          | Field               | Appears on                                                                   |
| ------------------------------ | ------------------- | ---------------------------------------------------------------------------- |
| Global                         | `globalSequenceId`  | `l2Orderbook`, `l2OrderbookUpdates`                                          |
| Global                         | `sequenceNumber`    | `trades`                                                                     |
| Per-market (order book)        | `lastSequenceId`    | `l2Orderbook`, `l2OrderbookUpdates`                                          |
| Per-market (market attributes) | `marketSequenceNum` | `MarketAttributesUpdate`                                                     |
| Per-account                    | `sequenceNum`       | `AccountUpdate` (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.

<Note>
  The `trades` message — including its `sequenceNumber` — is expected to change when counterparty information is added, so treat that field as provisional.
</Note>

## Errors

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