> ## 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.62

# Monaco Protocol SDK v1.0.62

This release covers the consumer-facing changes since v1.0.61. The `account` WebSocket channel now delivers a **subscribe-time snapshot** — one row per margin account you own in the authenticated application, flat accounts included — so an immediate baseline no longer needs a margin-accounts REST call; to describe those snapshot rows, `AccountEventData.sequence` is now optional, which is source-breaking for strict TypeScript. PitPass gains two self-scoped referral reads, `getMyReferralPosition` and `getMyReferralDownline`, with matching React hooks and gRPC RPCs, and the verify response now reports `isNewUser` and `referralApplied`. The `market_stats` channels pick up the same snapshot-on-subscribe treatment, and the server-key application order and movement listings now bound `total` / `totalPages` at the depth they can page to. If you consume the `account` channel under strict TypeScript, or read `total` on the application listings as a lifetime count, read the two upgrade notes before you bump.

## Breaking

### The `account` channel snapshot makes `AccountEventData.sequence` optional

`sdk.ws.account(handler, onSnapshot)` (authenticated session; raw channel `account`) now delivers a **subscribe-time snapshot** ahead of the live diffs: one `AccountEventData` row per margin account you own **in the application you authenticated under**, delivered as a single array through the `onSnapshot` callback. No SDK migration is needed — the `onSnapshot` parameter already existed on this subscription — but the baseline reaches only subscriptions that pass an `onSnapshot` handler, so add one if you don't already. Owning no margin account then delivers an empty array rather than a skipped call.

**FLAT accounts are included.** The live producer only emits for an account holding an open position or a resting order reserve, so a flat account was silent on the stream until it re-activated; the snapshot carries it with its current persisted health — a zero maintenance requirement and a zero margin ratio. A flat account that is also otherwise empty (no open risk bucket) reports its deposited collateral as both `equity` and `freeCollateral`; a flat account still holding an open risk bucket keeps that risk bucket's allocation and unsettled realized PnL, so its `equity` need not equal its `collateral`.

Because a snapshot row is the same payload as a live frame with `sequence` **omitted**, the parser reads the field optionally and **`AccountEventData.sequence` is now `number | undefined`**. This is SOURCE-BREAKING for strict TypeScript consumers: `event.data.sequence.toFixed()`, or passing it where a `number` is required, no longer compiles. Guard it (`event.data.sequence ?? fallback`, or narrow with a check) and treat absent as **unknown, never zero**, and never as a replay or ordering cursor — the counter is the matching engine producer's process-local per-account map, so a zero from any other emitter is indistinguishable from a restarted producer's first frame, and it resets on a producer restart. Runtime behaviour is unchanged: live frames still always carry a sequence, and a malformed value on a live frame is still rejected.

Merge the snapshot **per `marginAccountId`** rather than replacing your whole channel map, and let any live frame supersede a snapshot row for the same account whatever the timestamps say: a snapshot row's `updatedAt` is when its state was persisted (a database write), while a live frame's is when the engine sampled it, so the two clocks are not comparable under persistence lag. Rank `updatedAt` only between live frames — newest wins, with `sequence` breaking ties inside one producer run. Live delivery is also per user rather than per application, so a wallet trading through more than one application still receives live frames for its other accounts; each is full current health and baselines itself.

See [Subscribe-time snapshots](/sdk/typescript/websockets#subscribe-time-snapshots) and the [raw `account` channel reference](/reference/websockets#account).

## Added

### PitPass self-scoped referral reads

`sdk.pitpass.getMyReferralPosition()` (`GET /api/v1/pitpass/referrals/me`) and `sdk.pitpass.getMyReferralDownline()` (`GET /api/v1/pitpass/referrals/me/downline`) — with the gRPC equivalents `TraderCodeService.GetMyReferralPosition` and `TraderCodeService.GetMyReferralDownline` — return the caller's own referral chain. Both need an authenticated session and are **self-scoped**: identity is derived from the session, there is no id path parameter, so a request cannot read another user's chain. Every other user is exposed only as a **public wallet address** plus a custom-handle-or-wallet `display`, never an internal id.

`getMyReferralPosition` returns `GetMyReferralPositionResponse`: your direct (L1) `referrer` and `referrerDisplay` (both empty when you were not referred — only the direct referrer is exposed), the all-time `totalEarned` across every level and token, and `rewards`, your most recent `ReferralRewardEntry` rows newest-first (up to the 100 newest — `totalEarned` stays the complete aggregate — each carrying the reward's `source`, `level` 1/2/3, `amount`, `token`, `rateApplied` and `createdAt`).

`getMyReferralDownline` returns `GetMyReferralDownlineResponse`: `earningsBySource`, one `ReferralEarningsSource` row per (source trader, level, token) you earn from across L1/L2/L3; `directReferees`, your L1 roster as `ReferralDirectReferee` rows **including referees who have not traded yet** (their `totalEarned` reads `"0"`), showing up to the 500 most recent effective referees (after per-wallet dedupe and the winning-edge filter), drawn from a bounded scan of recent relationships — so a referrer with a very large history may get an incomplete roster — while the `earningsBySource` and `summary` earnings views stay unbounded and count every level, so a caller past that roster cap still reads their full earnings; and `summary`, a `ReferralEarningsSummary` carrying `totalEarned` and the per-level `level1Earned` / `level2Earned` / `level3Earned` — always populated, so a brand-new user reads a zeroed summary rather than an absent field. All amounts are RAW atomic units of the token.

`@0xmonaco/react` wraps both as the `useMyReferralPosition` and `useMyReferralDownline` hooks.

See [PitPass](/sdk/typescript/pitpass) and [the React PitPass hooks](/sdk/react/hooks/use-pitpass).

### The verify response reports `isNewUser` and `referralApplied`

`AuthState` — returned by `sdk.auth.authenticate` and `sdk.auth.verifySignature` (`POST /api/v1/auth/verify`) — now carries two optional flags read from the verify response. `isNewUser` is `true` when this verify created the user (the wallet's first sign-in to this application); `referralApplied` is `true` when a PitPass referral relationship was recorded on this verify (a valid TraderCode was applied). Gate first-time UX on `isNewUser`, and confirm a referral landed with `referralApplied`. Both are optional, so read them behind a presence check.

See [Authentication](/sdk/typescript/auth).

## Changed

### The `market_stats` channels deliver a subscribe-time snapshot

`sdk.ws.marketStats(pairId, handler, onSnapshot)` and `sdk.ws.marketStatsAll(handler, onSnapshot)` (public, no auth) now receive a subscribe-time snapshot ahead of the live frames. The per-market form delivers a one-element `MarketStatsData[]` carrying that pair's latest complete stats frame; the all-markets form delivers a `MarketStatsSummary[]` with one summary per active market with retained data, ordered by trading-pair id. Each per-market row is the same shape as the live per-market payload, and each all-markets summary is the same shape as an element of the live all-markets frame's `markets` list — so apply it as a terminal-state baseline and let the live frames move it forward. No SDK migration is needed — the `onSnapshot` parameters already existed — but the baseline reaches only subscriptions that pass an `onSnapshot` handler, so add one if you don't already.

A per-market subscription whose market has not yet produced a frame — or on a transient matching-engine read failure — receives a `SNAPSHOT_UNAVAILABLE` signal rather than a fabricated one; the subscription stays active and a later published live frame seeds it once the market produces one (a market that never publishes, e.g. a perp with no open-interest frame, stays unseeded). The all-markets channel returns `SNAPSHOT_UNAVAILABLE` the same way for a brief window during initial startup or after a server restart (until the producer commits its first full generation), and on any transient snapshot read failure against the matching engine — treat it as a resync signal and take the next periodic push as the baseline. Where a deployment does not run the market-stats snapshot service, neither channel sends a snapshot at all and the first live push seeds the baseline, so do not block on `onSnapshot` firing.

See [Subscribe-time snapshots](/sdk/typescript/websockets#subscribe-time-snapshots).

### Application listings bound `total` and `totalPages` to their pagination reach

`client.applications.listApplicationOrders()` and `client.applications.listApplicationMovements()` (`GET /api/v1/applications/orders` and `/api/v1/applications/movements`, server-key auth; gRPC `ApplicationsService.ListAppOrders` / `ListAppMovements`) now bound their `total` and `totalPages` by the listing's pagination reach. Both stay **exact** up to 10,000 pages of the requested `pageSize` (`pageSize` × 10,000 matching rows) and saturate there, so an application with more matching orders or movements than the listing can page through reads the cap — `totalPages` becomes `10000`, the last page it can reach — instead of its lifetime total. Applications under that reach see the same numbers as before.

The bound lets the server stop counting at the cap rather than walking the whole application's history on every page render. Loops that stop at `page >= totalPages` keep terminating; only code that read `total` as the application's lifetime count needs to treat exactly `pageSize` × 10,000 as "at least this many". On the same two endpoints, a `page` above 10,000 is now rejected as invalid input — HTTP `400` (error `BAD_REQUEST`) on REST, `INVALID_ARGUMENT` on gRPC — instead of fetching rows past the reported last page.

See [Application Backend Endpoints](/api-reference).

## Upgrade

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

Two things to check before upgrading. If you **consume the `account` channel under strict TypeScript**, `AccountEventData.sequence` is now `number | undefined`: guard every read (`event.data.sequence ?? fallback`) and treat absent as unknown rather than zero — snapshot rows omit it, live frames always carry it. And if you **read `total` on the application listings** as a lifetime count, it is now capped at `pageSize` × 10,000; treat exactly that value as "at least this many", and expect a `page` above 10,000 to be rejected.

The rest is additive. The `account` and `market_stats` subscribe-time snapshots arrive through the optional `onSnapshot` callback, so a subscription that already passes one starts receiving a baseline with no code change — add the callback if you don't already; merge the `account` snapshot per `marginAccountId` and let live frames supersede it. The PitPass referral reads and the new `isNewUser` / `referralApplied` flags are additive surfaces — read the flags behind a presence check.
