# Laevitas API V2 > Cryptocurrency derivatives, spot, prediction market, proprietary vol-surface, and Hyperliquid - HyperCore data API. Serves historical and real-time futures, perpetuals, options, spot, prediction markets, volatility surfaces, live portfolio risk, and Hyperliquid - HyperCore wallet/onchain data from major exchanges (Deribit, Binance, OKX, Bybit, CME, Polymarket, Hyperliquid, etc.). All REST endpoints are prefixed with `/api/v1`. Authentication via `X-API-Key` header or x402 USDC micropayments. An MCP server is available for AI agent access. Base URL: `https://apiv2.laevitas.ch` ## Authentication Two authentication methods: 1. **API Key** — pass `X-API-Key: ` header on every request 2. **x402 Micropayments** — pay per request with USDC on Base (no API key needed). First call returns HTTP 402 with payment instructions; after payment, a credit token is returned for subsequent calls via `X-Credit-Token` header ## Futures Endpoints Dated futures contracts (BTC, ETH, etc.) across major derivatives exchanges. - [Catalog](https://apiv2.laevitas.ch/swagger#/Futures/FuturesController_catalog): `GET /api/v1/futures/catalog` — list all available futures instruments, filterable by exchange and currency - [Metadata](https://apiv2.laevitas.ch/swagger#/Futures/FuturesController_metadata): `GET /api/v1/futures/metadata` — detailed instrument metadata (tick size, contract size, expiry, etc.) - [OHLCVT](https://apiv2.laevitas.ch/swagger#/Futures/FuturesController_ohlcvt): `GET /api/v1/futures/ohlcvt` — OHLC price candles with volume and trade count. Params: `instrument`, `exchange`, `currency`, `period` (1m to 1M), `start`, `end`, `limit`, `cursor` - [Level 1](https://apiv2.laevitas.ch/swagger#/Futures/FuturesController_level1): `GET /api/v1/futures/level1` — latest best bid/ask, mark price, index price for an instrument - [Orderbook](https://apiv2.laevitas.ch/swagger#/Futures/FuturesController_orderbook): `GET /api/v1/futures/orderbook` — aggregated L2 order book snapshots over time - [Orderbook Raw](https://apiv2.laevitas.ch/swagger#/Futures/FuturesController_orderbookRaw): `GET /api/v1/futures/orderbook-raw` — raw L2 order book (current depth) - [Volume](https://apiv2.laevitas.ch/swagger#/Futures/FuturesController_volume): `GET /api/v1/futures/volume` — historical volume with buy/sell breakdown and trade counts - [Trades](https://apiv2.laevitas.ch/swagger#/Futures/FuturesController_trades): `GET /api/v1/futures/trades` — individual trade records with price, size, and direction - [Open Interest](https://apiv2.laevitas.ch/swagger#/Futures/FuturesController_openInterest): `GET /api/v1/futures/open-interest` — historical open interest in contracts and USD - [Ticker History](https://apiv2.laevitas.ch/swagger#/Futures/FuturesController_tickerHistory): `GET /api/v1/futures/ticker-history` — historical ticker snapshots (bid, ask, mark, index, OI) - [Carry](https://apiv2.laevitas.ch/swagger#/Futures/FuturesController_carry): `GET /api/v1/futures/carry` — carry/basis data (mark price minus index price) - [Reference Price](https://apiv2.laevitas.ch/swagger#/Futures/FuturesController_referencePrice): `GET /api/v1/futures/reference-price` — mark price and index price history - [Snapshot](https://apiv2.laevitas.ch/swagger#/Futures/FuturesController_snapshot): `GET /api/v1/futures/snapshot` — current state of all futures for an exchange/currency ## Perpetuals Endpoints Perpetual swap contracts (same data structure as futures, with funding rate data). - [Catalog](https://apiv2.laevitas.ch/swagger#/Perpetuals/PerpetualsController_catalog): `GET /api/v1/perpetuals/catalog` — list all available perpetual instruments - [Metadata](https://apiv2.laevitas.ch/swagger#/Perpetuals/PerpetualsController_metadata): `GET /api/v1/perpetuals/metadata` — detailed instrument metadata - [OHLCVT](https://apiv2.laevitas.ch/swagger#/Perpetuals/PerpetualsController_ohlcvt): `GET /api/v1/perpetuals/ohlcvt` — OHLC price candles with volume and trade count - [Level 1](https://apiv2.laevitas.ch/swagger#/Perpetuals/PerpetualsController_level1): `GET /api/v1/perpetuals/level1` — latest best bid/ask, mark price, funding rate - [Orderbook](https://apiv2.laevitas.ch/swagger#/Perpetuals/PerpetualsController_orderbook): `GET /api/v1/perpetuals/orderbook` — aggregated L2 order book snapshots - [Orderbook Raw](https://apiv2.laevitas.ch/swagger#/Perpetuals/PerpetualsController_orderbookRaw): `GET /api/v1/perpetuals/orderbook-raw` — raw L2 order book (current depth) - [Volume](https://apiv2.laevitas.ch/swagger#/Perpetuals/PerpetualsController_volume): `GET /api/v1/perpetuals/volume` — historical volume with buy/sell breakdown - [Trades](https://apiv2.laevitas.ch/swagger#/Perpetuals/PerpetualsController_trades): `GET /api/v1/perpetuals/trades` — individual trade records - [Open Interest](https://apiv2.laevitas.ch/swagger#/Perpetuals/PerpetualsController_openInterest): `GET /api/v1/perpetuals/open-interest` — historical open interest - [Ticker History](https://apiv2.laevitas.ch/swagger#/Perpetuals/PerpetualsController_tickerHistory): `GET /api/v1/perpetuals/ticker-history` — historical ticker snapshots - [Carry](https://apiv2.laevitas.ch/swagger#/Perpetuals/PerpetualsController_carry): `GET /api/v1/perpetuals/carry` — carry/basis data for perpetuals - [Reference Price](https://apiv2.laevitas.ch/swagger#/Perpetuals/PerpetualsController_referencePrice): `GET /api/v1/perpetuals/reference-price` — mark and index price history - [Snapshot](https://apiv2.laevitas.ch/swagger#/Perpetuals/PerpetualsController_snapshot): `GET /api/v1/perpetuals/snapshot` — current state of all perpetuals for an exchange/currency ## Options Endpoints Options contracts with Greeks, implied volatility, and flow data. - [Catalog](https://apiv2.laevitas.ch/swagger#/Options/OptionsController_catalog): `GET /api/v1/options/catalog` — list all available options instruments - [Metadata](https://apiv2.laevitas.ch/swagger#/Options/OptionsController_metadata): `GET /api/v1/options/metadata` — detailed instrument metadata (strike, expiry, type) - [OHLCVT](https://apiv2.laevitas.ch/swagger#/Options/OptionsController_ohlcvt): `GET /api/v1/options/ohlcvt` — OHLC price candles with volume and trade count - [Volume](https://apiv2.laevitas.ch/swagger#/Options/OptionsController_volume): `GET /api/v1/options/volume` — historical volume with buy/sell breakdown - [Trades](https://apiv2.laevitas.ch/swagger#/Options/OptionsController_trades): `GET /api/v1/options/trades` — individual trade records with IV and Greeks - [Flow](https://apiv2.laevitas.ch/swagger#/Options/OptionsController_flow): `GET /api/v1/options/flow` — options flow data (large trades, unusual activity) - [Open Interest](https://apiv2.laevitas.ch/swagger#/Options/OptionsController_openInterest): `GET /api/v1/options/open-interest` — historical open interest - [Level 1](https://apiv2.laevitas.ch/swagger#/Options/OptionsController_level1): `GET /api/v1/options/level1` — latest best bid/ask with Greeks and IV - [Volatility](https://apiv2.laevitas.ch/swagger#/Options/OptionsController_volatility): `GET /api/v1/options/volatility` — historical implied volatility data - [Ticker History](https://apiv2.laevitas.ch/swagger#/Options/OptionsController_tickerHistory): `GET /api/v1/options/ticker-history` — historical ticker snapshots - [Reference Price](https://apiv2.laevitas.ch/swagger#/Options/OptionsController_referencePrice): `GET /api/v1/options/reference-price` — mark price and underlying price history - [Snapshot](https://apiv2.laevitas.ch/swagger#/Options/OptionsController_snapshot): `GET /api/v1/options/snapshot` — current state of all options for an exchange/currency - [GEX Catalog](https://apiv2.laevitas.ch/swagger#/Options/OptionsController_getGexCatalog): `GET /api/v1/options/gex/catalog` — available dealer-GEX currencies, history depth, and latest aggregate state - [GEX Latest](https://apiv2.laevitas.ch/swagger#/Options/OptionsController_getGexLatest): `GET /api/v1/options/gex/latest` — latest aggregate dealer gamma exposure snapshot from ClickHouse - [GEX History](https://apiv2.laevitas.ch/swagger#/Options/OptionsController_getGexHistory): `GET /api/v1/options/gex/history` — paginated aggregate dealer-GEX history for one currency - [GEX Regime Changes](https://apiv2.laevitas.ch/swagger#/Options/OptionsController_getGexRegimeChanges): `GET /api/v1/options/gex/regime-changes` — dealer regime transitions for one currency - [GEX Strikes](https://apiv2.laevitas.ch/swagger#/Options/OptionsController_getGexStrikes): `GET /api/v1/options/gex/strikes` — strike-level dealer-GEX contributions, aggregate all-expiries by default - [GEX Term Structure](https://apiv2.laevitas.ch/swagger#/Options/OptionsController_getGexTermStructure): `GET /api/v1/options/gex/term-structure` — per-expiry dealer-GEX term structure - [GEX Profile](https://apiv2.laevitas.ch/swagger#/Options/OptionsController_getGexProfile): `GET /api/v1/options/gex/profile` — interpolated dealer-GEX profile points ## Volatility Surface Endpoints 3D volatility surface and term structure data for options analytics. - [By Expiry](https://apiv2.laevitas.ch/swagger#/Options/VolSurfaceController_byExpiry): `GET /api/v1/options/vol-surface/by-expiry` — all real expiries at one time (ATM IV, skew, butterfly per maturity) - [By Tenor](https://apiv2.laevitas.ch/swagger#/Options/VolSurfaceController_byTenor): `GET /api/v1/options/vol-surface/by-tenor` — standardized constant-maturity tenors (1d–365d, interpolated) - [By Time](https://apiv2.laevitas.ch/swagger#/Options/VolSurfaceController_byTime): `GET /api/v1/options/vol-surface/by-time` — one expiry across time (historical vol surface) ## Proprietary Vol Surface Endpoints Calibrated vol-surface engine data from ClickHouse plus live portfolio risk. `margin` is required conceptually and defaults to `inverse`; pass `linear` for USDC-margined books. Slice endpoints default to `model=svi`. - `GET /api/v1/vol-surface/catalog` - available `(exchange, currency, margin, model)` tuples with latest calibration timestamp - `GET /api/v1/vol-surface/snapshots` - surface-level calibration metadata, index price, forward curve JSON, and calendar-arbitrage diagnostics - `GET /api/v1/vol-surface/slices` - per-expiry model parameters, ATM/wing metrics, fit diagnostics, spread model, quality tier, and fallback metadata - `GET /api/v1/vol-surface/term-structure` - constant-maturity ATM IV, total variance, skew, forward, term slope, forward vol, and source labels - `GET /api/v1/vol-surface/strikes` - per-strike IV diagnostics and greeks. Historical scans require `expiry` or `instrument` - `POST /api/v1/vol-surface/risk/decompose` - live portfolio risk decomposition. Requires `X-API-Key` authentication like GET endpoints - `POST /api/v1/vol-surface/risk/scenario` - full scenario repricing. Requires `X-API-Key` authentication like GET endpoints - `POST /api/v1/vol-surface/risk/ladder` - spot x vol ladder, capped at 400 cells. Requires `X-API-Key` authentication like GET endpoints Risk `decompose` includes portfolio greeks, value/PnL fields, vega buckets, and per-position model/market IV diagnostics. `scenario` includes base/shocked values, PnL, shocked greeks, and per-position shocked pricing. `ladder` includes `cells[]` plus `pnl_usd_matrix`, `pnl_coin_matrix`, and `pnl_pct_matrix`; matrix rows follow `spot_shifts_pct`, columns follow `vol_shifts`. Risk position notes: `expiry` accepts ISO 8601 (`2026-06-26T08:00:00Z` or `2026-06-26`) or any exchange-native date code — DDMMMYY (`26JUN26`), YYMMDD (`260626`), YYYYMMDD (`20260626`) — on any position regardless of `exchange`; date-only forms settle at 08:00 UTC. For options, `strike`/`expiry`/`option_type` may be omitted and are derived from the instrument name (all major venue formats); contradictions between explicit fields and the name are validation errors. Perpetual/future/spot legs without `entry_price` are valued at `mark_price` with zero PnL (`entry_price_source: "mark_fallback"`). ## Prediction Markets Endpoints Prediction market data from Polymarket and Hyperliquid HIP-4. Prices represent probabilities (0.0–1.0). Exchange defaults to `polymarket` for all prediction endpoints. - [Catalog](https://apiv2.laevitas.ch/swagger#/Predictions/PredictionsController_catalog): `GET /api/v1/predictions/catalog` — list available prediction instruments, filterable by exchange, category, event_slug, and keyword search - [Categories](https://apiv2.laevitas.ch/swagger#/Predictions/PredictionsController_categories): `GET /api/v1/predictions/categories` — list all prediction market categories with instrument counts - [Metadata](https://apiv2.laevitas.ch/swagger#/Predictions/PredictionsController_metadata): `GET /api/v1/predictions/metadata` — data availability metadata for a specific prediction instrument - [OHLCVT](https://apiv2.laevitas.ch/swagger#/Predictions/PredictionsController_ohlcvt): `GET /api/v1/predictions/ohlcvt` — OHLCVT candles with probability-based prices, buy/sell volume, trade counts. Params: `instrument_name`, `exchange` (default: polymarket), `resolution`, `start`, `end`, `limit`, `cursor` - [Ticker History](https://apiv2.laevitas.ch/swagger#/Predictions/PredictionsController_tickerHistory): `GET /api/v1/predictions/ticker-history` — historical ticker data with probability OHLC, bid/ask spread, liquidity metrics - [Trades](https://apiv2.laevitas.ch/swagger#/Predictions/PredictionsController_trades): `GET /api/v1/predictions/trades` — individual trades with price (probability), size, side, outcome, fee rate - [Orderbook Raw](https://apiv2.laevitas.ch/swagger#/Predictions/PredictionsController_orderbookRaw): `GET /api/v1/predictions/orderbook-raw` — raw L2 orderbook snapshots with bid/ask arrays, depth liquidity (10/20/50), imbalance, microprice - [Snapshot](https://apiv2.laevitas.ch/swagger#/Predictions/PredictionsController_snapshot): `GET /api/v1/predictions/snapshot` — cross-instrument snapshot at a single minute with ticker + OHLCVT data ## Hyperliquid - HyperCore Endpoints Hyperliquid L1 HyperCore wallet/onchain data from ClickHouse. These endpoints are separate from `/perpetuals/*`, `/spot/*`, and `/predictions/*` because they expose wallet attribution, raw HyperCore coin ids, fees, PnL, block/hash fields, TWAP state, resting L4 orders, and deep HyperCore-derived L2 books. - `GET /api/v1/hyperliquid/node/fills` - enriched wallet-attributed fills. Requires `wallet`; supports instrument, raw coin, currency, market_type, side, direction, min_notional, crossed, liquidation flag, time range, pagination - `GET /api/v1/hyperliquid/node/prediction-fills` - Hyperliquid HIP-4 prediction fills. Requires `condition_id`, `token_id`, or `instrument_name` - `GET /api/v1/hyperliquid/node/liquidations` - node liquidation fills with liquidated_user, liquidator, role, backstop flag, mark price, method, closed PnL, hash, block number; supports `dedupe=true` and `resolution=5m|15m|1h|1d` - `GET /api/v1/hyperliquid/node/wallet-flow` - 1-minute wallet flow rollups with buy/sell/net volume, buy/sell/net/total notional, realized PnL, and fees. Requires wallet, instrument, raw coin, or currency; supports `sort_by` and `min_notional` - `GET /api/v1/hyperliquid/node/wallet-positions` - latest wallet positions by instrument with labels, mark price, mark time, and position notional. Requires wallet, instrument, raw coin, or currency - `GET /api/v1/hyperliquid/node/funding-payments` - wallet-level funding payments. Requires `wallet` - `GET /api/v1/hyperliquid/node/twap-events` - TWAP lifecycle events with computed target notional; supports broad recent discovery with `min_target_notional` - `GET /api/v1/hyperliquid/node/resting-orders` - latest per-wallet resting orders from HyperCore-derived L4 state with mark price, `distance_from_mark_pct`, snapshot staleness meta, and `max_distance_from_mark` - `GET /api/v1/hyperliquid/node/instruments` - raw Hyperliquid coin mapping (`BTC`, `xyz:NVDA`, `@305`, `#40`) to normalized instrument, market type, currency, sizing, display name, deployer, and last-seen time - `GET /api/v1/hyperliquid/node/l2-orderbook` - latest deep HyperCore-derived L2 orderbook snapshot. Requires `instrument_name` ## Common Query Parameters Most endpoints accept these parameters: - `exchange` (required) — exchange name: `deribit`, `binance`, `okx`, `bybit`, `cme`, etc. - `currency` (required) — base currency: `BTC`, `ETH`, `SOL`, etc. - `instrument` — specific instrument name (e.g., `BTC-27JUN25`, `BTC-PERPETUAL`, `BTC-27JUN25-100000-C`) - `period` — candle resolution: `1m`, `3m`, `5m`, `15m`, `30m`, `1h`, `2h`, `4h`, `6h`, `12h`, `1d`, `1w`, `1M` - `start` — ISO 8601 datetime in UTC (e.g. `2025-01-15T00:00:00Z`) or Unix timestamp. Always use UTC with Z suffix - `end` — ISO 8601 datetime in UTC (e.g. `2025-02-01T00:00:00Z`) or Unix timestamp. Always use UTC with Z suffix - `limit` — max number of records to return (default varies by endpoint) - `cursor` — opaque pagination cursor from a previous response's `meta.next_cursor` field Vol Surface endpoints additionally use `margin`, `model`, `expiry`, `tenor_days`, `quality_tier`, `slice_source`, and portfolio `positions` depending on the endpoint. HyperCore endpoints additionally use `wallet`, `instrument_name_raw`, and `market_type` (`perp`, `perp_hip3`, `spot`, `prediction`) depending on the endpoint. For HyperCore node endpoints that accept `instrument_name`, unambiguous raw/currency aliases are resolved server-side where possible: `BTC` resolves to `BTC-USD`, casing is normalized (for example `btc-usd` to `BTC-USD`), and raw aliases should be sent as `instrument_name_raw` when you want exact raw-coin filtering. When the server rewrites an instrument filter, the response includes `meta.instrument_resolved: { "from": "...", "to": "..." }`. Ambiguous CEX-style names such as `BTC-USDT`, `BTCUSD`, or `BTC-PERPETUAL` are not rewritten; they return an empty `data` array with a structured `UNRESOLVED_INSTRUMENT` warning and a suggested HyperCore instrument when one is available. HyperCore endpoints that expose freshness metadata include `meta.freshness_basis` so clients can interpret `meta.staleness_ms` correctly. Resting-order snapshots are emitted every 60 seconds and use `freshness_basis: "snapshot"` with `snapshot_time`, `snapshot_time_iso`, `snapshot_interval_ms`, and `staleness_ms`; latest resting-order requests without `start`/`end` are pruned to the most recent 15 minutes. Wallet positions are event-sourced latest-state and use `freshness_basis: "ingestion_watermark"` with `watermark_time`, `watermark_time_iso`, and `staleness_ms`; per-row `updated_at` and `last_fill_time` describe wallet activity recency, not pipeline freshness. **Important**: All datetime parameters and response timestamps are in UTC. Always pass dates with the `Z` suffix (e.g. `2025-01-15T00:00:00Z`). ## Pagination All list endpoints use cursor-based pagination. Responses include: ```json { "success": true, "metadata": { "endpoint": "...", "timestamp": "..." }, "data": [...], "meta": { "next_cursor": "eyJtaW51dGUiOi4uLn0=" } } ``` Pass `meta.next_cursor` as the `cursor` parameter to fetch the next page. When `meta.next_cursor` is `null`, there are no more results. ## Response Warnings Responses may include `meta.warnings`, an array of `{ "code": string, "message": string }`. Omitted means no warnings. - `STALE_SNAPSHOT` — freshness lag exceeded the endpoint threshold. For `freshness_basis: "snapshot"`, this means the latest snapshot is older than three times its advertised `snapshot_interval_ms`. For `freshness_basis: "ingestion_watermark"`, this means no new events were ingested beyond the endpoint threshold; the warning message includes elapsed seconds and threshold seconds. - `UNRESOLVED_INSTRUMENT` — an `instrument_name` filter did not match or resolve. The message includes the input and, when available, a "did you mean" suggestion. Options GEX latest/detail endpoints are snapshot-emitted every 60 seconds and expose `meta.snapshot_time`, `meta.snapshot_time_iso`, `meta.snapshot_interval_ms`, `meta.freshness_basis: "snapshot"`, and `meta.staleness_ms`. Aggregate GEX history lives in `gex_index`; strike, term-structure, and interpolated profile endpoints read durable ClickHouse detail tables. Detail endpoints expose legacy raw/unweighted fields plus `weighted_*` fields. Use weighted fields when reconciling strike or expiry detail with aggregate `total_gex`; raw fields preserve the underlying decomposition before moneyness and expiry weighting. ## MCP Server An MCP (Model Context Protocol) server is available for AI agents at `POST /api/v1/mcp` using Streamable HTTP transport. It exposes 80+ tools mirroring the REST API (futures, perpetuals, options, spot, volatility surfaces, proprietary vol-surface risk, prediction markets, macro/analytics, and Hyperliquid - HyperCore data). Supports OAuth 2.1 Bearer tokens and x402 micropayments. - [MCP Documentation](https://apiv2.laevitas.ch/mcp): Interactive MCP documentation and tool reference ## WebSocket Streaming Real-time data streaming via two transports: - **Native WebSocket**: `wss://apiv2.laevitas.ch/ws` (preferred — Deribit/Binance-style JSON-RPC) - **Socket.IO**: `wss://apiv2.laevitas.ch/stream` (legacy compatibility) Authentication uses the same credentials as REST: pass `apikey: ` as a handshake header, OR `X-Credit-Token: ` for x402 wallet customers with an active ws-pass. ### Channel patterns ``` trades.{market}.{exchange}.{instrument} ohlc.{ticker|vt}.{market}.{exchange}.{instrument}.{timeframe} liquidations.{market}.{exchange}.{instrument} book.{market}.{exchange}.{instrument} ``` `{market}` is one of `perpetuals`, `futures`, `options`, `spot`, `predictions`. Wildcards (`*`) are allowed in the `market`, `exchange`, or `instrument` segments — e.g. `trades.*` (everything), `liquidations.perpetuals.*` (every perp liquidation), `book.perpetuals.*.BTCUSDT` (BTCUSDT perp book across all exchanges). Wildcards are NOT allowed in OHLC `dataType` or `timeframe`. Trailing `*` auto-pads — `trades.*` is equivalent to `trades.*.*.*`. ### Subscribe protocol (native /ws) ```json { "id": 1, "method": "subscribe", "params": { "channels": ["trades.spot.binance.BTCUSDT", "liquidations.perpetuals.*"] } } ``` Server responds with `{ "id": 1, "result": { "subscriptionIds": [...], "channels": [...] } }`. Data events arrive as `{ "channel": "", "data": { ... } }` — note that wildcard subscribers receive events tagged with the **resolved concrete channel path**, not the wildcard pattern. Client dispatch logic that keys off `msg.channel` works unchanged. ### Limits (per connection) - 200 subscriptions - 20 inbound messages/second - 24h max lifetime (server force-closes with code 4004 — reconnect and resubscribe) - 2 MB outbound buffer (slow-consumer threshold) - 5 concurrent connections per API key, 20 per IP ### Close codes — reconnect dispatch | Code | Meaning | Action | |------|---------|--------| | 1001 | Server graceful shutdown (deploy) | Reconnect after 1–5s, no backoff | | 1006 / 1011 | Network hiccup, abnormal close | Exponential backoff with jitter (1s → 30s cap) | | 4001 | Auth failed (bad key, revoked, invalid credit token) | **DO NOT auto-retry.** Surface to user. | | 4002 | Idle timeout (missed pong) | Reconnect immediately; check for blocked event loop | | 4003 | Slow consumer (couldn't drain >2 MB) | **Fix the underlying issue first** (reduce subs, faster handler), then reconnect | | 4004 | 24h lifetime cap reached | Reconnect immediately and resubscribe — expected ~daily | | 4005 | Too many concurrent connections | **DO NOT reconnect.** Close another connection or raise cap | | 4006 | x402 ws-pass expired or absent | Buy a new pass via `POST /api/v1/x402/ws-pass/{hour\|day}`, then reconnect | | 4008 | Inbound rate limit (>20 msg/sec) | Pause, throttle subscribe calls, then reconnect | ### Best practices - **Persist your subscription list locally.** The server has no memory across reconnects — resubscribe to everything on every connect. - **Always implement exponential backoff with jitter** for transient closes (1006, 1011). Without jitter, a fleet of clients reconnects in lockstep after every server restart. - **Plan for the 24h disconnect (4004)** — it's expected hygiene, not an error. Build it into your client. - **Pong promptly.** Server pings every 25s, expects pong within 75s. Standard `ws`/`socket.io` clients handle this automatically. - **Bundle subscribes** — one `subscribe` call with N channels, not N calls with one channel each. - **Log the close code on every disconnect** — without it you can't distinguish a 4003 from a 4004 from a network blip. - **Don't open one connection per channel.** One connection holds 200 subs; cap is 5 connections per key. - **Don't subscribe to firehoses you can't drain.** `book.*` or `trades.*` deliver thousands of events per second; a blocked handler hits 4003 in under a minute. - **Don't pass the API key in the URL query string.** It ends up in access logs. Use the `apikey` header. ### Reference reconnect loop (Node.js) ```js import WebSocket from 'ws'; const URL = 'wss://apiv2.laevitas.ch/ws'; const FATAL = new Set([4001, 4003, 4005]); // surface, don't retry let attempt = 0; function connect() { const ws = new WebSocket(URL, { headers: { apikey: process.env.LAEVITAS_API_KEY } }); ws.on('open', () => { attempt = 0; ws.send(JSON.stringify({ id: 1, method: 'subscribe', params: { channels: ['trades.spot.binance.BTCUSDT'] } })); }); ws.on('message', (raw) => { /* handle msg.channel + msg.data */ }); ws.on('close', (code) => { if (FATAL.has(code)) return console.error('Fatal close', code); const delay = Math.min(1000 * 2 ** attempt++, 30_000) * (0.8 + Math.random() * 0.4); setTimeout(connect, delay); }); } connect(); ``` For x402 ws-pass clients: on close code 4006, buy a new pass via REST first, then reconnect with the new `x-credit-token`. Don't add 4006 to your fatal set — treat it as a "refill required" signal. - [WebSocket Documentation](https://apiv2.laevitas.ch/websocket): Interactive WebSocket documentation and playground ## Optional - [OpenAPI Specification](https://apiv2.laevitas.ch/api-json): Full Swagger/OpenAPI 3.0 JSON specification - [Swagger UI](https://apiv2.laevitas.ch/swagger): Interactive API explorer with try-it-out - [ReDoc](https://apiv2.laevitas.ch/redoc): Read-only API reference documentation - [Changelog](https://apiv2.laevitas.ch/changelog.html): Version history and release notes - [Historical data corrections](https://apiv2.laevitas.ch/api/v1/changelog/data-corrections): Machine-readable affected endpoints, windows, deployment versions, and re-collection guidance - [Data status and coverage](https://apiv2.laevitas.ch/api/v1/changelog/data-status): Machine-readable live incidents, maintenance, series terminations, and coverage-universe changes - [Historical field semantics](https://apiv2.laevitas.ch/historical-data.html): Canonical bar, carry, options-model, and cross-currency field definitions