WebSocket
Stream live prices, market state, accounts, blocks, and trades. It’s the same feed the uplong website uses, open to everyone, with no API key.
Connecting
wss://api.uplong.fun/ws- Messages are JSON text frames, in both directions.
- Amounts are micro-USDC and prices are micro-USD, as integers:
83606360000is $83,606.36. - Subscribe to as many channels as you need on one connection.
Requests
{ "method": "subscribe", "subscription": { "type": "prices" } }
{ "method": "unsubscribe", "subscription": { "type": "prices" } }
{ "method": "subscribe", "subscription": { "type": "account", "address": "<base58 address>" } }
{ "method": "ping" }Every server message has the form { "channel": ..., "data": ... }. A subscribe or unsubscribe is confirmed with a subscriptionResponse echoing the request; a bad request gets an error message, and the connection stays open.
Channels
| Type | Sends | When |
|---|---|---|
prices | The live oracle price per market | Whenever a price changes, at least once a second, at most 20 a second |
markets | Block prices, open interest, pool, payout queue, fees | Every block |
account | One account’s balance, nonce, session key, positions, and queued winnings | Every block |
positions | Every open position on the exchange, largest first, each with its owner | Every block |
blocks | A summary of each block | Each committed block |
trades | Opens, closes, and liquidations in a block | Each committed block that has any |
prices, markets, account, and positions send the current state as soon as you subscribe, so there’s nothing to fetch first.
prices
{ "channel": "prices",
"data": { "prices": { "BTC": 83606360000, "ETH": 2533410000 }, "timestampMs": 1791746814302 } }A market missing from prices has no fresh oracle price right now. See Oracle.
markets
An excerpt; some fields are left out (the full payload is the same as GET /markets).
{ "channel": "markets",
"data": {
"height": 8879, "oracleFresh": true, "chainId": "3f9a0c51d27e8b46",
"minNotional": 10000000000, "maxSideGap": 10000000000000,
"withdrawalFee": 1000000, "longClaimFee": 1000000,
"pool": 211167956, "queuedProfit": 0, "queueLength": 0,
"feesCollected": 3626227, "impactRetained": 481249157,
"markets": [
{ "market": "BTC", "price": 83606360000, "maxLeverage": 1000,
"openInterest": 3000000000, "longOpenInterest": 3000000000, "shortOpenInterest": 0,
"longCap": null, "shortCap": null,
"longRoom": 9997000000000, "shortRoom": 10003000000000 },
{ "market": "ETH", ... }
] } }longRoom and shortRoom are how much new notional fits on each side right now; null is unlimited.
account
An excerpt; the full payload is the same as GET /account/:address.
{ "channel": "account",
"data": {
"address": "FQBE…Cj7M", "balance": 1392517066, "nonce": 49, "nextNonce": 49,
"agent": "HLkK…NBm", "agentExpiresMs": 1791833200000,
"longEarned": 1975000000, "longClaimed": 0,
"positions": [
{ "id": 41, "market": "BTC", "side": "long", "margin": 10000000, "leverage": 1000,
"notional": 10000000000, "entryPrice": 83600080000, "markPrice": 83599830000,
"liquidationPrice": 83516480000, "unrealizedPnl": -29902, "grossPnl": -29902,
"openedAtMs": 1791746800000 }
],
"pendingClaims": [ { "positionId": 37, "remaining": 2170000, "ahead": 0 } ] } }unrealizedPnlis what closing now would pay, after fees;grossPnlis before them.nextNonceis the nonce to sign next. See API.- Up to 10 account subscriptions per connection.
positions
{ "channel": "positions",
"data": { "height": 8879, "positions": [
{ "id": 41, "owner": "FQBE…Cj7M", "market": "BTC", "side": "long", "margin": 10000000,
"leverage": 1000, "notional": 10000000000, "entryPrice": 83600080000,
"markPrice": 83599830000, "liquidationPrice": 83516480000,
"unrealizedPnl": -29902, "grossPnl": -29902, "openedAtMs": 1791746800000 }
] } }blocks
{ "channel": "blocks",
"data": { "height": 8880, "hash": "0x3d8c…f77d", "timestampMs": 1791746815303,
"txCount": 2, "kinds": { "priceUpdate": 1, "deposit": 1 } } }trades
{ "channel": "trades",
"data": { "height": 6655, "events": [
{ "type": "positionOpened", "positionId": 39, "owner": "999q…MtXH", "market": "BTC",
"side": "long", "margin": 10000000, "leverage": 50, "entryPrice": 83578225000 }
] } }Events are positionOpened, positionClosed (with exitPrice, pnl after fees, grossPnl, impact, fee, profitPaid, profitQueued), and positionLiquidated (with price and marginLost).
Staying connected
- The server sends a WebSocket ping every 30 seconds; most clients answer it on their own. Clients that can’t send ping frames, like browsers, can send
{ "method": "ping" }and get{ "channel": "pong", "data": null }. - If you reconnect, subscribe again: subscriptions belong to a connection. The snapshots bring you back up to date.
- A client that reads too slowly skips blocks rather than falling behind. Every
marketsandaccountmessage is a full snapshot, so the latest one is always complete; for every trade without gaps, page throughGET /blocksorGET /trades.
Examples
JavaScript (browser or Node 22+)
const ws = new WebSocket("wss://api.uplong.fun/ws");
ws.onopen = () => {
ws.send(JSON.stringify({ method: "subscribe", subscription: { type: "prices" } }));
ws.send(JSON.stringify({ method: "subscribe", subscription: { type: "trades" } }));
};
ws.onmessage = (message) => {
const { channel, data } = JSON.parse(message.data);
if (channel === "prices") console.log("BTC", data.prices.BTC / 1e6);
if (channel === "trades") for (const event of data.events) console.log(event.type, event.market);
};Python
# pip install websockets
import asyncio, json, websockets
async def main():
async with websockets.connect("wss://api.uplong.fun/ws") as ws:
await ws.send(json.dumps({"method": "subscribe", "subscription": {"type": "prices"}}))
async for raw in ws:
message = json.loads(raw)
if message["channel"] == "prices":
print({market: price / 1e6 for market, price in message["data"]["prices"].items()})
asyncio.run(main())Command line
npx wscat -c wss://api.uplong.fun/ws
> {"method":"subscribe","subscription":{"type":"blocks"}}