Documentation Index
Fetch the complete documentation index at: https://docs.mobula.io/llms.txt
Use this file to discover all available pages before exploring further.
Endpoint
- URL:
wss://stream-perps-prod-eu.mobula.io/ - Event type:
stream(in the subscribe envelope)
Subscribe
Parameters
type(required) — must be"stream".authorization(required) — your Mobula server-side API key.payload.name(required) — client-provided subscription name. Echoed back on the ack frame and useful for log correlation.payload.chainIds(required) — array of chain ids to subscribe to. See Chain coverage below.payload.events(required) — array of event categories."order"covers all perp trade-lifecycle events listed in Event types below.payload.subscriptionTracking(optional) — string"true"(not a boolean). When set, the ack frame includes asubscriptionIdyou can use to demux multiple subscriptions on a single socket.
Subscribe acknowledgement
Server push
Each event is one frame. The top-level envelope wraps the event-specificdata:
data.traderAddressis lowercased on the wire — match accordingly when filtering by wallet.duplicateCountis informational; identical frames may still be delivered on reconnect or for Gains’TRADE_STORED+MARKET_BUYpair on the same transaction. Deduplicate on the client with a key like(transactionHash, type, traderAddress, tradeId).
Event types
| Type | Emitted by | Description |
|---|---|---|
MARKET_BUY / MARKET_SELL | Gains, Lighter | Market order fill |
LIMIT_BUY / LIMIT_SELL | Gains | Limit order fill |
LIQUIDATION_LONG / LIQUIDATION_SHORT | Gains, Lighter | Position liquidated |
TAKE_PROFIT / STOP_LOSS | Gains, Lighter | TP / SL trigger fired |
TRADE_STORED | Gains | Emitted in addition to MARKET_* when a Gains trade is committed to the Diamond — clients see two frames per tx |
UPDATE_TP / UPDATE_SL | Gains | TP/SL edited. Carries newPriceQuote and quantityPercentage. |
POSITION_SIZE_INCREASE_EXECUTED / POSITION_SIZE_DECREASE_EXECUTED | Gains | Margin added / removed on an open position |
LEVERAGE_UPDATE_EXECUTED | Gains | Leverage changed on an open position |
MARKET_OPEN_CANCELED / MARKET_CLOSE_CANCELED | Gains | Market order rejected by the Diamond. extra.cancelReason is a numeric Gains enum — see the Gains Trading docs for the canonical mapping. |
PerpOrderExecuted, PerpTpSlUpdate, PerpUncategorizedEvent) including extra-field shapes, see the Perpetuals data model.
Gains “two frames per trade” caveat
For every Gains market action, you will receive two events back-to-back with overlapping but different field sets — these are not duplicates:TRADE_STORED—{ market, exchange, chainId, traderAddress, type, tradeId, transactionHash, extra: { tradeType, leverage, long, collateralAmount, index, openPrice, tp, sl }, date, ... }MARKET_BUY(orMARKET_SELL) —{ market, exchange, chainId, type, priceQuote, priceUSD, blockNumber, baseAmountRaw, tradeId, collateralAmountRaw, collateralAsset, leverage, traderAddress, takeProfitUSD, stopLossUSD, extra: { open, amountSentToTrader, trade: { long, index, tradeType, openPrice, collateralIndex } }, transactionHash, date, ... }
(transactionHash, type, traderAddress, tradeId) — distinguishes the two without dropping one of them.
Chain coverage
| Chain id | Used for |
|---|---|
evm:42161 | Gains on Arbitrum (mainnet) |
evm:421614 | Gains on Arbitrum Sepolia (testnet) |
evm:8453 | Gains on Base |
lighter:304 | Lighter — used by this stream |
Lighter on this stream is
lighter:304. The sibling Perp Positions WSS uses lighter:301. Subscribing to events with lighter:301 returns no Lighter frames at all — it is silently dropped.Envelope shape — events vs positions
The perp events stream and the perp positions WSS use different envelope shapes:| Perp Events (this page) | Perp Positions | |
|---|---|---|
| Host | stream-perps-prod-eu.mobula.io | hawk-api-prod-eu.mobula.io |
| Subscribe top-level | { type: "stream", authorization, payload } | { event: "perp-positions-open" | "...-unfilled", data, authorization } |
subscriptionTracking type | string "true" | boolean true |
| Lighter chain id | lighter:304 | lighter:301 |
| Push semantics | one event per frame | full snapshot per frame |
Heartbeat & idle timeout
The server expectsping frames to keep the socket alive:
{ "event": "pong" }. The idle timeout is short (~10 s) before a subscription is sent — make sure your first frame after open is a subscribe, not silence. Once subscribed, 30 s+ between pings has been observed to work.
Lighter “hawk” subscribers
LighterMARKET_* / liquidation / TP / SL frames may include an activePosition / historicalPosition block embedded on the event with the full position state at the time of the event. Raw (non-hawk) subscribers receive a smaller payload without this block.
Implementation example
Related
Perp Positions Stream
Live snapshot of open positions + unfilled orders.
Perpetuals Data Model
Per-event field reference (executed / TP-SL / uncategorized).
Execution Cookbook
Pair with this stream to learn that your order filled.
Funding Stream
Real-time funding rates across CeFi + DeFi exchanges.