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

# V1.0.38

# Monaco Protocol SDK v1.0.38

This is an additive release — no breaking type changes. It brings the typed WebSocket surface up to par with the account APIs: dedicated `sdk.ws.positions` and `sdk.ws.liquidations` streams, and reconnect/resync callbacks you can now wire straight into the SDK config instead of dropping to the low-level factory. It also makes `postOnly` a durable, readable property of an order and gives single-order crossing rejections the same structured error code the batch endpoints already carried, adds an `order_id` filter to the gRPC user-trades history, and ships three PitPass React hooks. Two changes need a closer look before you upgrade: a set of **collateral withdrawal-gate corrections** that make `withdrawableCollateral` report a number a transfer-out will actually accept (expect a smaller figure than before for any account carrying PnL, funding, or an unrealized gain), and a **WebSocket order-event field-name correction** — read `tradingPair`, `filledQuantity`, and `fee` on order events, not the never-populated `symbol` / `executionQuantity` / `makerFee`.

## Added

### Typed positions and liquidations WebSocket streams

`sdk.ws.positions(handler, tradingPairId?)` and `sdk.ws.liquidations(handler, tradingPairId?)` (`@0xmonaco/core`) subscribe to the authenticated positions and liquidations channels, parse each raw server frame into a typed `PositionEvent` / `LiquidationEvent` (`@0xmonaco/types`), and return an unsubscribe function — mirroring the existing `orders` / `balances` / `movements` helpers instead of the generic `subscribe<T>`. Both require the signed session-key handshake. Positions use a **conflating** stream — a lagging subscriber is fast-forwarded to the latest state, so there is no gap signal; treat `updatedAt` as monotonic per `positionId`. Liquidations use a **sequential** stream and shed a slow subscriber with close code `1013` — treat a `1013` close as the gap signal and resync from a fresh snapshot. Parsing is lenient on the free-form / enum string fields (`side`, `status`, `reason`, `accountState`) so an unexpected server value never drops a risk-critical event. See [WebSockets](/sdk/typescript/websockets#positions-channel).

### WebSocket reconnect/resync configuration on the SDK config

`SDKConfig` gains an optional `ws` object (`ws?: MonacoWebSocketConfig`): the `onStatusChange` / `onResync` callbacks and the reconnect knobs (`autoReconnect`, `maxReconnectAttempts`, `reconnectBaseDelayMs`, `connectionTimeoutMs`) are now threaded into the WebSocket client the SDK builds internally. Previously these were reachable only through the low-level `createMonacoWebSocket` factory, so an app using the SDK could not observe connection status or drive snapshot resyncs. Pass them in the SDK config — `new MonacoSDK({ ..., ws: { onStatusChange, onResync } })` — and `onStatusChange` fires on connect/disconnect/reconnect while `onResync` fires after an automatic reconnect resumes the live stream (with `slowClient: true` for a `1013` slow-client shed). The session keypair is intentionally not part of this surface — it continues to flow from `login`. `@0xmonaco/types` adds `MonacoWebSocketConfig`, `StatusHandler`, `ResyncHandler`, and `WebSocketResyncInfo`.

### `postOnly` on order reads and a structured single-order crossing code

`GetOrderResponse` — order detail and every order-list item — gains an optional `postOnly` boolean (wire `post_only`; gRPC field tag 42) recording whether the order was placed post-only. Like `reduceOnly`, it is absent (not `false`) when the order was not placed post-only, including orders placed before the flag was persisted; `postOnly` is now a durable property of the order rather than an admission-time-only input. Exposed on `sdk.trading.getOrder` / `getOrders` (`@0xmonaco/core`), REST `GET /api/v1/orders` and `GET /api/v1/orders/{order_id}`, and gRPC `OrdersService.GetOrder` / `ListOrders`.

Single-order rejections that originate in the matching engine now carry the engine's stable code, so single-order callers get the same structured contract the batch endpoints always had. A post-only order or replacement that would cross the book is rejected with the code `POST_ONLY_WOULD_CROSS` — on REST it rides the error envelope's optional `code` field; on gRPC it is a `google.rpc.ErrorInfo` status detail with `reason` set to the code and `domain` set to `matching-engine.0xmonaco.com`. Match on the structured code; the `"post-only order would cross"` message substring still works but is now a legacy fallback. `error`, `message`, and the HTTP/gRPC statuses are unchanged, and `code` is omitted entirely when no engine code applies. The MCP `place_limit_order` and `replace_order` tool descriptions were updated to state this contract.

### `order_id` filter on gRPC user-trade history

`TradesService.ListUserTrades` (`/monaco.api.trades.TradesService/ListUserTrades`, authenticated, gRPC-only) adds an optional `order_id` string (an order UUID). When present, the response includes only trades where that order placed the caller's own side of the fill, across hot and archived history and in both pagination modes. `ListUserTradesResponse` is unchanged. Adding or changing `order_id` invalidates an existing page token — restart the cursor walk with an empty token.

### PitPass React hooks

`@0xmonaco/react` adds `useRewardsBalance` (`getRewardsBalance`), `useTraderCodeInfo` (`getTraderCodeInfo`), and `useTransferRewards` (`transferRewards`) — each a thin `useCallback` wrapper over the matching `sdk.pitpass.*` method that resolves the client from the `MonacoProvider` context. `useRewardsBalance` and `useTransferRewards` require authentication; `useTraderCodeInfo` is a public referral-code lookup. See [PitPass hooks](/sdk/react/hooks/use-pitpass).

## Fixed

### `withdrawableCollateral` now reports a number a transfer-out will accept

`withdrawableCollateral` (on margin account and risk bucket summaries — `GET /api/v1/margin/accounts`, `GET /api/v1/margin/accounts/{marginAccountId}`, `GET /api/v1/margin/parent-margin-account`), `newWithdrawableCollateral` (on every collateral transfer-in/transfer-out response under `/api/v1/margin/`), and `marginAvailableCollateral` (`GET /api/v1/margin/available-collateral`) previously reported `freeCollateral` — an equity figure that credits realized PnL, accrued funding, and unrealized mark-to-market gains that are not principal a transfer can move. The published number could far exceed anything a transfer-out would accept; a risk bucket holding realized PnL against roughly no allocated collateral advertised its whole balance as withdrawable while rejecting every transfer. All three now report the largest amount the exchange's withdrawal gate will actually accept — for a risk bucket, capped by its allocated collateral (net of its own resting-order and position margin and funding, plus realized PnL, counting an unrealized loss but never an unrealized gain) and by the parent account's own limit; for a parent margin account, capped by unearmarked deposited collateral and by `freeCollateral` less any unrealized gain. The field types, positions, and status codes are unchanged — only the value changed. **Size transfers and withdrawals from this field**; `freeCollateral` is unchanged and remains the equity/new-position headroom figure. Expect a smaller number than before for any account or bucket carrying realized PnL, accrued funding, or an unrealized gain.

The same correction closes several related withdrawal-gate gaps, all with unchanged types and status codes: an unrealized gain no longer funds a withdrawal from a parent margin account; a bucket-scoped transfer-out is no longer wrongly refused on a fully-allocated account (the release the request itself performs is now credited); and a partial withdrawal can no longer strip a losing risk bucket a piece at a time below the loss it has taken, which had let the containment step bill the difference to the insurance fund. Refusals in these cases carry a distinct, bucket-aware message so an automated client does not read them as a shortfall and top up collateral to no effect.

### WebSocket order-event field names corrected

Order events on `ws.events.orders` (`OrderFilled`, `OrderPartiallyFilled`, `OrderCancelled`, and the shared common fields) declared `symbol`, `executionQuantity`, and `makerFee`, but the matching engine has always sent `trading_pair`, `filled_quantity`, and `fee` (camelCased to `tradingPair`, `filledQuantity`, and `fee`). Consumers reading the old names received `undefined` — **use `tradingPair`, `filledQuantity`, and `fee`.** `filledQuantity` is the quantity filled in this event: the cumulative order fill for a taker, the current trade's quantity for a maker, keyed by `role`. The RAW (integer, base-unit) precision fields the wire already carried are now typed too — `quantityRaw`, `filledQuantityRaw`, `remainingQuantityRaw`, and `totalFilledRaw`. The `executedAt` runtime value is now RFC3339 with a `Z` suffix (e.g. `2026-01-02T03:04:05Z`) so `new Date(executedAt)` parses an unambiguous UTC instant; the TypeScript type is unchanged (`string`). `@0xmonaco/react`'s `useUserOrders` now reads its trading-pair fallback from `data.tradingPair` instead of the never-populated `data.symbol`.

### `applications/config` 401 description corrected

The documented `401` response on `GET /api/v1/applications/config` (`ApplicationsService.GetConfig`) was corrected from "Unauthorized - Invalid or missing JWT" to "Authentication required". The endpoint is session-authenticated (signed ed25519 session key, `monacoSignature`) and never used JWT/Bearer tokens. Description-only — no type shapes, status codes, or security requirements change.

## Upgrade

```bash theme={null}
npm install @0xmonaco/core@1.0.38 @0xmonaco/types@1.0.38 @0xmonaco/react@1.0.38 @0xmonaco/contracts@1.0.38
# or bun
bun add @0xmonaco/core@1.0.38 @0xmonaco/types@1.0.38 @0xmonaco/react@1.0.38 @0xmonaco/contracts@1.0.38
```

The MCP server ships at `1.0.38` too; it runs via `npx -y @0xmonaco/mcp-server`, so restarting your assistant picks up the new version and the updated post-only tool descriptions.

Nothing in this release is breaking. Four things worth acting on:

1. **Adopt the typed positions/liquidations streams.** Use `sdk.ws.positions` / `sdk.ws.liquidations` for live risk state, and handle a `1013` liquidations close as a gap signal — resync from a REST snapshot.
2. **Wire reconnect handling through the SDK config.** Pass `ws: { onStatusChange, onResync }` to `new MonacoSDK({ ... })` to observe status and resync after reconnects without the low-level factory.
3. **Match on `POST_ONLY_WOULD_CROSS` for single orders.** Read the structured `code` (REST envelope) / `ErrorInfo.reason` (gRPC) instead of the message substring, and read `postOnly` off order detail/list reads.
4. **Re-check withdrawal sizing.** Size transfer-outs and withdrawals from the corrected `withdrawableCollateral` / `marginAvailableCollateral`, and fix any WebSocket order-event consumer reading `symbol` / `executionQuantity` / `makerFee`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.