Stratos API
Generated by pnpm stratos api-doc from a paper service on 2026-11-07: every answer below is
real. Use @stratos/client from an interface: it signs actions, retries
failovers and reconnects the stream.
- Base URL: the gateway (
pnpm gateway), which sends reads to any caught-up node and writes to the leader. - Units: USD as numbers (6-decimal precision), prices in USD, times in ms since the epoch.
- Money stays in the vault on Elysium. A deposit is a vault transaction (approve USDC, then
deposit(amount)). The engine credits it once the deposit has its confirmations. A withdrawal is a signed action that answers with an authorization. The user submits that authorization tovault.withdraw. - Writes are EIP-712 signed actions to
POST /v1/exchange: domain{ name: "Stratos", version: "1", chainId }(chainId from/v1/info, 99801 on Elysium testnet), typeAction(string action, string payload, uint256 nonce, uint256 expiry).payloadis the JSON of the parameters, exactly as signed.expiryis at most 5 minutes out. The nonce is the command id, so re-sending the same body is safe and returns the first answer. - Errors are
{ ok: false, code, message }with a stablecode(packages/core/src/errors.ts). A 503not_leadermeans a failover is in progress or the cluster hasn't confirmed the write yet. Retry with the same body (the client does this).
Reads
Service info
Mode, chain, coins, fees, roll schedule, leverage tiers, vault address.
GET /v1/info
{
"mode": "paper",
"chainId": 99801,
"coins": [
"ETH",
"HYPE"
],
"faucet": true,
"fees": {
"standard": 0.0005,
"degen": 0.0002,
"degenProfitShare": 0.05,
"liquidation": 0.01,
"insuranceShare": 0.1
},
"roll": {
"weekday": 5,
"hourUtc": 8,
"windowMs": 3600000
},
"tiers": [
{
"poolUsd": 0,
"maxLeverage": 5,
"degenMaxLeverage": 50
},
{
"poolUsd": 250000,
"maxLeverage": 10,
"degenMaxLeverage": 75
},
"… 1 more"
],
"vault": null,
"stage": "ask"
}
Markets
Eight markets: X², X³ and their straddles on ETH and HYPE. maxLeverage is what a new position can take now. It slides down as the book's gap risk fills its budget (docs/PRICING_AND_LIQUIDATION.md). reduceOnly is set for 15 min after a fast move.
GET /v1/markets
[
{
"id": "ETH2",
"coin": "ETH",
"kind": "power",
"power": 2,
"name": "ETH²",
"indexPrice": 3000,
"markPrice": 3000,
"ref": 3000,
"nf": 1,
"fundingRateYear": 0.417,
"fundingRateHour": 0.0000476027,
"openInterest": {
"long": 0,
"short": 0
},
"maxLeverage": 10,
"degenMaxLeverage": 75,
"degenMinLeverage": 1,
"halted": false,
"reduceOnlyUntil": null,
"priceAgeMs": 73,
"nextRoll": 1794556800000
},
{
"id": "ETH2S",
"coin": "ETH",
"kind": "straddle",
"power": 2,
"name": "ETH² straddle",
"indexPrice": 3000,
"markPrice": null,
"ref": 3000,
"nf": 1,
"fundingRateYear": 0.317,
"fundingRateHour": 0.0000361872,
"openInterest": {
"long": 0,
"short": 0
},
"maxLeverage": 10,
"degenMaxLeverage": 75,
"degenMinLeverage": 1,
"halted": false,
"reduceOnlyUntil": null,
"priceAgeMs": 73,
"nextRoll": 1794556800000
},
{
"id": "ETH3",
"coin": "ETH",
"kind": "power",
"power": 3,
"name": "ETH³",
"indexPrice": 3000,
"markPrice": 3000,
"ref": 3000,
"nf": 1,
"fundingRateYear": 1.101,
"fundingRateHour": 0.000125685,
"openInterest": {
"long": 0,
"short": 0
},
"maxLeverage": 6.66667,
"degenMaxLeverage": 50,
"degenMinLeverage": 1,
"halted": false,
"reduceOnlyUntil": null,
"priceAgeMs": 73,
"nextRoll": 1794556800000
},
{
"id": "ETH3S",
"coin": "ETH",
"kind": "straddle",
"power": 3,
"name": "ETH³ straddle",
"indexPrice": 3000,
"markPrice": null,
"ref": 3000,
"nf": 1,
"fundingRateYear": 0.951,
"fundingRateHour": 0.000108562,
"openInterest": {
"long": 0,
"short": 0
},
"maxLeverage": 6.66667,
"degenMaxLeverage": 50,
"degenMinLeverage": 1,
"halted": false,
"reduceOnlyUntil": null,
"priceAgeMs": 73,
"nextRoll": 1794556800000
},
{
"id": "HYPE2",
"coin": "HYPE",
"kind": "power",
"power": 2,
"name": "HYPE²",
"indexPrice": 40,
"markPrice": 40,
"ref": 40,
"nf": 1,
"fundingRateYear": 0.8225,
"fundingRateHour": 0.0000938927,
"openInterest": {
"long": 0,
"short": 0
},
"maxLeverage": 5,
"degenMaxLeverage": 37.5,
"degenMinLeverage": 1,
"halted": false,
"reduceOnlyUntil": null,
"priceAgeMs": 64,
"nextRoll": 1794556800000
},
{
"id": "HYPE2S",
"coin": "HYPE",
"kind": "straddle",
"power": 2,
"name": "HYPE² straddle",
"indexPrice": 40,
"markPrice": null,
"ref": 40,
"nf": 1,
"fundingRateYear": 0.6225,
"fundingRateHour": 0.0000710616,
"openInterest": {
"long": 0,
"short": 0
},
"maxLeverage": 5,
"degenMaxLeverage": 37.5,
"degenMinLeverage": 1,
"halted": false,
"reduceOnlyUntil": null,
"priceAgeMs": 65,
"nextRoll": 1794556800000
},
{
"id": "HYPE3",
"coin": "HYPE",
"kind": "power",
"power": 3,
"name": "HYPE³",
"indexPrice": 40,
"markPrice": 40,
"ref": 40,
"nf": 1,
"fundingRateYear": 2.1675,
"fundingRateHour": 0.000247432,
"openInterest": {
"long": 0,
"short": 0
},
"maxLeverage": 3.33333,
"degenMaxLeverage": 25,
"degenMinLeverage": 1,
"halted": false,
"reduceOnlyUntil": null,
"priceAgeMs": 65,
"nextRoll": 1794556800000
},
{
"id": "HYPE3S",
"coin": "HYPE",
"kind": "straddle",
"power": 3,
"name": "HYPE³ straddle",
"indexPrice": 40,
"markPrice": null,
"ref": 40,
"nf": 1,
"fundingRateYear": 1.8675,
"fundingRateHour": 0.000213185,
"openInterest": {
"long": 0,
"short": 0
},
"maxLeverage": 3.33333,
"degenMaxLeverage": 25,
"degenMinLeverage": 1,
"halted": false,
"reduceOnlyUntil": null,
"priceAgeMs": 65,
"nextRoll": 1794556800000
}
]
One market
GET /v1/markets/ETH2
{
"id": "ETH2",
"coin": "ETH",
"kind": "power",
"power": 2,
"name": "ETH²",
"indexPrice": 3000,
"markPrice": 3000,
"ref": 3000,
"nf": 1,
"fundingRateYear": 0.417,
"fundingRateHour": 0.0000476027,
"openInterest": {
"long": 0,
"short": 0
},
"maxLeverage": 10,
"degenMaxLeverage": 75,
"degenMinLeverage": 1,
"halted": false,
"reduceOnlyUntil": null,
"priceAgeMs": 76,
"nextRoll": 1794556800000
}
Quote
What an open would cost, its leverage and liquidation prices, and whether the engine would take it now (ok, or a reason). Pass account to check the user's own caps.
GET /v1/quote?market=ETH2&side=long&size=1000&collateral=200
{
"ok": true,
"reasons": [],
"market": "ETH2",
"side": "long",
"size": 1000,
"collateral": 200,
"leverage": 5,
"fee": 0.5,
"fundingRateYear": 0.417,
"fundingPerDay": 1.14247,
"liquidationPrice": {
"low": 2752.99,
"high": null
},
"entryPrice": 3000,
"maxLeverage": 10
}
Writes
Faucet (paper and testnet)
Test dollars once a day per account. Not on mainnet.
POST /v1/faucet {"account":"0xf77dbb8941bafb73767e13b0d91e80d7e47f8238"}
{
"ok": true,
"seq": 51,
"events": [
"Deposited"
]
}
The signed body
Every write looks like this (client.sign):
{
"action": "open",
"payload": "{\"market\":\"ETH2\",\"side\":\"long\",\"size\":1000,\"collateral\":200}",
"nonce": "1794040341934000",
"expiry": 1794040401934,
"account": "0xf77dbB8941baFB73767E13b0d91E80d7E47F8238",
"signature": "0xa2163dc821a70930a7e7e8e55df667460b6b90…"
}
Open
size is notional USD and collateral is USD taken from free cash. degen: true gives fixed knock-out leverage. The position id is account:nonce.
POST /v1/exchange {action:"open", payload:{"market":"ETH2","side":"long","size":1000,"collateral":200}}
{
"ok": true,
"seq": 52,
"events": [
"Opened"
]
}
Re-sending the same body
The same nonce is the same command: same answer, nothing done twice.
POST /v1/exchange (same body)
{
"ok": true,
"seq": 52,
"events": [
"Opened"
]
}
Positions
Live P&L, equity, leverage and liquidation prices.
GET /v1/accounts/0xf77dbb8941bafb73767e13b0d91e80d7e47f8238/positions
[
{
"id": "0xf77dbb8941bafb73767e13b0d91e80d7e47f8238:1794040341934000",
"market": "ETH2",
"kind": "power",
"power": 2,
"side": "long",
"degen": false,
"size": 1060.9,
"entryNotional": 1000,
"collateral": 200,
"pnl": 60.9,
"funding": -0.000001,
"equity": 260.9,
"leverage": 4.06631,
"marginRatio": 4.91847,
"liquidationPrice": {
"low": 2752.99,
"high": null
},
"entryPrice": 3000,
"indexPrice": 3090,
"fundingRateYear": 0.417,
"openedAt": 1794040341949
}
]
Add margin
POST /v1/exchange {action:"addMargin", payload:{"position":"…","amount":50}}
{
"ok": true,
"seq": 61,
"events": [
"MarginAdded"
]
}
Close (part)
fraction closes part of the position; leave it out to close all of it.
POST /v1/exchange {action:"close", payload:{"position":"…","fraction":0.5}}
{
"ok": true,
"seq": 62,
"events": [
"Settled"
]
}
LP deposit
Mints pool shares at NAV.
POST /v1/exchange {action:"poolDeposit", payload:{"amount":500}}
{
"ok": true,
"seq": 63,
"events": [
"PoolDeposited"
]
}
Withdraw
Takes free cash out of the engine. In testnet and mainnet the answer carries withdrawal: pass it to vault.withdraw(amount, nonce, deadline, signature) (vaultWithdrawArgs). Paper mode has no vault, so its signature is null.
POST /v1/exchange {action:"withdraw", payload:{"amount":100}}
{
"ok": true,
"seq": 64,
"events": [
"Withdrew"
],
"withdrawal": {
"account": "0xf77dbb8941bafb73767e13b0d91e80d7e47f8238",
"amount": 100000000,
"nonce": "1794040341984000",
"deadline": 1794126741,
"signature": null,
"vault": null,
"chainId": null
}
}
Linked devices (agent keys)
An account can let another key sign for it, as Hyperliquid's agent wallets do: a phone linked from the desktop. The
account's own wallet signs approveAgent; after that a body with account set to the account and signed by the agent's
key is accepted. An agent can trade, manage positions and orders, and use the pool; it can't withdraw or
approveAgent, and it can revokeAgent only itself. At most 5 at a time, each for up to 180 days.
GET /v1/info says whether the service has it on (agents: true); GET /v1/accounts/{account} lists them under agents.
POST /v1/exchange {action:"approveAgent", payload:{"agent":"0x…","name":"Phone","expiresAt":1797000000000}}
POST /v1/exchange {action:"revokeAgent", payload:{"agent":"0x…"}}
With @stratos/client: client.approveAgent({ agent, name, expiresAt }), and an agent's client is
new StratosClient({ baseUrl, signer: { address: agentAddress, account: ownerAccount, signTypedData } }).
A rejection
HTTP 422 with a stable code.
POST /v1/exchange {action:"open", payload:{"size":1000000,"collateral":10,…}}
{
"ok": false,
"code": "leverage_too_high",
"message": "leverage 100000.00x is over 10x (rises w…"
}
Account, pool and transparency
Account
Free cash, positions, P&L and pool shares.
GET /v1/accounts/0xf77dbb8941bafb73767e13b0d91e80d7e47f8238
{
"account": "0xf77dbb8941bafb73767e13b0d91e80d7e47f8238",
"cash": 9304.68,
"accountValue": 9460.13,
"collateral": 125,
"notional": 530.45,
"pnl": {
"realized": 30.45,
"unrealized": 30.45,
"fees": 0.765225,
"funding": -0.000001,
"total": 60.1348
},
"volume": 1530.45,
"trades": 2,
"liquidations": 0,
"knockouts": 0,
"deposited": 10000,
"withdrawn": 100,
"pool": {
"shares": 500000000,
"value": 500,
"queued": 0
},
"positions": [
{
"id": "0xf77dbb8941bafb73767e13b0d91e80d7e47f8238:1794040341934000",
"market": "ETH2",
"kind": "power",
"power": 2,
"side": "long",
"degen": false,
"size": 530.45,
"entryNotional": 500,
"collateral": 125,
"pnl": 30.45,
"funding": -0.000001,
"equity": 155.45,
"leverage": 3.41235,
"marginRatio": 5.86106,
"liquidationPrice": {
"low": 2665.57,
"high": null
},
"entryPrice": 3000,
"indexPrice": 3090,
"fundingRateYear": 0.417,
"openedAt": 1794040341949
}
]
}
Trades
Newest first. Page with before (a time) and limit (at most 500).
GET /v1/accounts/0xf77dbb8941bafb73767e13b0d91e80d7e47f8238/trades
[
{
"seq": 62,
"t": 1794040341975,
"kind": "close",
"account": "0xf77dbb8941bafb73767e13b0d91e80d7e47f8238",
"position": "0xf77dbb8941bafb73767e13b0d91e80d7e47f8238:1794040341934000",
"market": "ETH2",
"side": "long",
"notional": 530.45,
"spot": 3090,
"pnl": 30.45,
"funding": 0,
"fee": 0.265225
},
{
"seq": 52,
"t": 1794040341949,
"kind": "open",
"account": "0xf77dbb8941bafb73767e13b0d91e80d7e47f8238",
"position": "0xf77dbb8941bafb73767e13b0d91e80d7e47f8238:1794040341934000",
"market": "ETH2",
"side": "long",
"notional": 1000,
"spot": 3000,
"pnl": 0,
"funding": 0,
"fee": 0.5
}
]
Candles
Index candles per coin, oldest first: interval 1m, 5m, 15m, 1h, 4h or 1d; limit up to 5,000 (default
500); end (ms, exclusive) pages backwards. The engine's own candles start when the node did; before that
the node serves Hyperliquid's public candles for the coin (daily back to August 2020 for ETH and December 2024
for HYPE, 4h about two years, 1h about seven months, 1m a few days), synced every minute. The two are
spliced at the first live candle, so a chart is continuous and its recent part is exactly what the engine
priced on.
GET /v1/candles?coin=ETH&interval=1m&limit=2
[
{
"t": 1794040320000,
"o": 3000,
"h": 3090,
"l": 3000,
"c": 3090
}
]
Pool
LP pool NAV, shares, the next roll (withdrawals settle there).
GET /v1/pool
{
"nav": 300500,
"cash": 300500,
"sharePrice": 1,
"shares": 300500000000,
"queuedShares": 0,
"navMarkedAt": 0,
"nextRoll": 1794556800000,
"insuranceFund": 0.026523,
"tier": {
"poolUsd": 250000,
"maxLeverage": 10,
"degenMaxLeverage": 75
},
"revenue": {
"tradingFees": 0.738702,
"liquidationFees": 0,
"insuranceIn": 0.026523
}
}
Stats
Volume, fees, liquidations, revenue.
GET /v1/stats
{
"openInterest": 530.45,
"volume": 1530.45,
"positions": 1,
"accounts": 2,
"insuranceFund": 0.026523,
"protocolRevenue": 0.738702,
"seq": 64
}
Risk
Each coin's gap risk against its budget: what's driving leverage limits right now.
GET /v1/risk
[
{
"coin": "ETH",
"designGap": {
"down": 0.15,
"up": 0.2
},
"gapNow": {
"down": 0.15,
"up": 0.2
},
"volMultiple": 1,
"realizedVol": null,
"baseVol": 0.6,
"lossOnGap": {
"down": 11.9351,
"up": 21.218
},
"worst": 21.218,
"side": "up",
"budget": 52587.5,
"used": 0.00040348,
"poolCarriedConvexityShare": 1,
"maxLossShare": 0.25,
"leverageScale": 1,
"maxLeverageNow": {
"squared": 10,
"degen": 75
}
},
{
"coin": "HYPE",
"designGap": {
"down": 0.3,
"up": 0.4
},
"gapNow": {
"down": 0.3,
"up": 0.4
},
"volMultiple": 1,
"realizedVol": null,
"baseVol": 0.9,
"lossOnGap": {
"down": 0,
"up": 0
},
"worst": 0,
"side": "down",
"budget": 22537.5,
"used": 0,
"poolCarriedConvexityShare": 0,
"maxLossShare": 0.25,
"leverageScale": 0.5,
"maxLeverageNow": {
"squared": 5,
"degen": 37.5
}
}
]
Reserves
Proof of reserves: liabilities (a Merkle tree of balances) against the vault plus the hedge.
GET /v1/reserves
{
"seq": 64,
"t": 1794040342016,
"root": "0x72b35b8f8fb304e8cc581409926f4438201947bb1a7d15c615ba1ab409c04d66",
"accounts": 1,
"liabilities": 9960.13,
"internalLiabilities": 300000,
"reserves": {
"vault": 9400,
"hedge": 300000,
"total": 309400
},
"coverage": 0.998193,
"reserveRatio": 0.0303265,
"bridge": null,
"vault": null
}
Your proof
Check it against the root posted on the vault (verifyBalance). It's also what the escape hatch pays if the service ever stops.
GET /v1/reserves/proof/0xf77dbb8941bafb73767e13b0d91e80d7e47f8238
{
"root": "0x72b35b8f8fb304e8cc581409926f4438201947bb1a7d15c615ba1ab409c04d66",
"seq": 64,
"account": "0xf77dbb8941bafb73767e13b0d91e80d7e47f8238",
"balanceMicro": "9960134774",
"balance": 9960.13,
"proof": []
}
Stream
WS /ws, send {"subscribe":"markets"} or {"subscribe":"account:0x…"}. Frames are {channel, data}: the whole markets list, or the account view (same shape as GET /v1/accounts/…), at most a few times a second. client.subscribe reconnects and re-subscribes.
{
"channel": "account:0xf77dbb8941bafb73767e13b0d91e80d7e47f8238",
"data": {
"account": "0xf77dbb8941bafb73767e13b0d91e80d7e47f8238",
"cash": 9304.68,
"accountValue": 9460.13,
"collateral": 125,
"notional": 530.45,
"pnl": {
"realized": 30.45,
"unrealized": 30.45,
"fees": 0.765225,
"funding": -0.000001,
"total": 60.1348
},
"volume": 1530.45,
"trades": 2,
"liquidations": 0,
"knockouts": 0,
"deposited": 10000,
"withdrawn": 100,
"pool": {
"shares": 500000000,
"value": 500,
"queued": 0
},
"positions": [
{
"id": "0xf77dbb8941bafb73767e13b0d91e80d7e47f8238:1794040341934000",
"market": "ETH2",
"kind": "power",
"power": 2,
"side": "long",
"degen": false,
"size": 530.45,
"entryNotional": 500,
"collateral": 125,
"pnl": 30.45,
"funding": -0.000001,
"equity": 155.45,
"leverage": 3.41235,
"marginRatio": 5.86106,
"liquidationPrice": {
"low": 2665.57,
"high": null
},
"entryPrice": 3000,
"indexPrice": 3090,
"fundingRateYear": 0.417,
"openedAt": 1794040341949
}
]
}
}
Operations
GET /healthz (200 while serving; leader checks price freshness), GET /readyz (200 when the node can take traffic: leader, or a caught-up standby), GET /metrics (Prometheus text; docs/OPERATIONS.md), GET /v1/bridge (bridge transfers in flight, docs/BRIDGING.md).