> ## Documentation Index
> Fetch the complete documentation index at: https://docs.upsidemax.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Reading data with Info

> Use the Upside Python SDK Info client for market data, account and order queries, and realtime WebSocket subscriptions — no wallet or signing required.

The `Info` client covers every read: market data, account and order queries, and
realtime WebSocket streams. It needs no wallet and signs nothing. Every method
returns the raw parsed JSON — see the [Info API](/info/overview) pages for the
exact response shapes.

```python theme={null}
from upside import Info
from upside.utils import constants

info = Info(base_url=constants.QA_API_URL)   # WebSocket starts automatically
```

Pass `skip_ws=True` to construct a REST-only client (no background WebSocket
thread). Call `info.close()` when you are done to stop the WebSocket cleanly.

## Market data

```python theme={null}
info.configs()                                   # contracts, coins, scales, tiers — cache this
info.l2_book(asset)                              # full order-book snapshot
info.market_state(asset)                         # mark / oracle / last price, funding
info.candle_snapshot(asset, "1m", start_ms, end_ms)   # historical OHLCV
```

<Note>
  `configs` is the source of truth for contract IDs, coin IDs, and the
  `priceScale` / `qtyScale` / `tickSize` / `stepSize` you need to convert display
  values to the raw integers the API expects. Fetch it once and cache it.
</Note>

## Account & orders

```python theme={null}
info.user_account(account_id, market_deployer_id)        # balances + positions
info.user_market_deployers(account_id)                   # market deployers the account is enrolled in
info.user_agents(account_id)                             # authorized API wallets
info.user_orders(account_id, market_deployer_id, contract_id=0)   # active open orders (0 = all contracts)
info.orders_by_ids(market_deployer_id, ["8280"])         # look up by exchange order id
info.orders_by_cloids(account_id, market_deployer_id, ["1778844423064"])  # look up by client order id
info.share_group_state(group_id=0)                       # portfolio-margin share group
```

`account_id` accepts an int or string; ids that are not found are simply omitted
from the `orders_by_ids` / `orders_by_cloids` results.

## WebSocket streams

The `Info` client manages one shared WebSocket connection. Subscribe with a
subscription dict and a callback; the callback receives each decoded message.
`subscribe` returns an integer subscription id you pass back to `unsubscribe`.

```python theme={null}
sid = info.subscribe(
    {"type": "l2Book", "asset": "1"},
    lambda m: print(m["data"]["bookVersion"]),
)
info.subscribe({"type": "trades", "asset": "1"}, print)

# Per-address (private) channels take the wallet address as `user`:
info.subscribe({"type": "orderUpdates", "user": "0x<address>"}, print)
info.subscribe({"type": "userFills", "user": "0x<address>"}, print)

info.unsubscribe({"type": "l2Book", "asset": "1"}, sid)
info.close()
```

**Channels** — see the [WebSocket](/websocket/overview) reference for payloads:

| Scope       | Channels                                      |
| ----------- | --------------------------------------------- |
| Public      | `l2Book`, `bbo`, `trades`, `candle`, `config` |
| Per-address | `orderUpdates`, `openOrders`, `userFills`     |

The client pings every 30 seconds and automatically reconnects, replaying its
active subscriptions. The WebSocket does **not** push position or balance
changes — poll [`user_account`](/info/user-account) for those.
