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://hawk-api-prod-eu.mobula.io/ - Channels (subscribe once per channel):
perp-positions-open— currently filled / open perp positionsperp-positions-unfilled— pending limit / stop / TP / SL orders that haven’t filled yet
(wallet, channel).
Subscribe
Parameters
event(required) —"perp-positions-open"or"perp-positions-unfilled".data.wallet(required) — wallet address. Lowercased on the wire — match accordingly.data.subscriptionTracking(optional, boolean) — whentrue, the server tags pushed frames with thesubscriptionIdso multiple subscriptions can be muxed on one socket. Default:false.data.subscriptionId(optional) — client-generated id echoed back on every push for that subscription. Auto-generated if omitted.authorization(required) — your Mobula server-side API key.
Server push
Each frame contains the full position set for the channel — there is no diff/patch protocol. Replace your local state withdata on every push.
Field reference
Thedata[] items mirror the REST response of GET /2/wallet/positions/perp/open (for perp-positions-open) and GET /2/wallet/positions/perp/unfilled (for perp-positions-unfilled). The unfilled channel additionally carries type: "STOP" | "LIMIT".
The collateral field (numeric, the USD value of the margin actually posted on the position) is present on WSS frames; it is also documented on the REST response.
Composite id format
pos-gains-inj-usd-usdc-0xaa0055ef84ef93138c7c11be1d19dac5dcd08741-0.
When closing a Gains position via /2/perp/payloads/close-position, do not pass the full composite id — extract the trailing trade-index segment and send it as a string (e.g. "0", "919").
Snapshot semantics
- The first frame after a successful subscribe is the current snapshot of the channel. You can subscribe without a REST seed.
- Every subsequent frame is also a full snapshot (not a diff). Replace state wholesale on receive.
- An empty
data: []push means the channel is currently empty (no open positions / no pending orders).
Heartbeat & idle timeout
The server expects a periodicping to keep the socket alive:
{ "event": "pong" }. A 30-second interval is safe in practice. The idle timeout is short (~10 s) before a subscription is sent — make sure your first frame after open is a subscribe, not silence.
Chain coverage
| Chain id | Notes |
|---|---|
evm:42161 | Gains on Arbitrum |
lighter:301 | Lighter — used by this channel |
Lighter is exposed as
lighter:301 on this channel. The sibling Perp Events Stream emits Lighter events under lighter:304. Subscribe with the right chain id depending on which stream you are wiring.Implementation example
Related
Perp Events Stream
Trade-lifecycle events (fills, liquidations, TP/SL, cancels).
Get Perp Positions
REST endpoint — useful as a synchronous seed.
Get Perp Unfilled Orders
REST endpoint for pending orders.
Execution Cookbook
Full build → execute flow.