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

# Async HTTP

> AsyncSTX — same surface as STX, awaitable, for bots and high-fanout services.

`AsyncSTX` is a drop-in async variant of `STX`. Same operation names, same `Selection`, same exceptions — just `await` every call.

## Basic usage

```python theme={null}
import asyncio
from stx import AsyncSTX, Selection

async def main():
    async with AsyncSTX(
        region="ontario", env="staging",
        email="you@example.com", password="...",
    ) as client:
        markets = await client.markets(
            selections=Selection("market_id", "status"),
        )
        for m in markets:
            print(m.market_id, m.status)

asyncio.run(main())
```

## When to use which client

| Use                                               | Sync `STX` | Async `AsyncSTX`    |
| ------------------------------------------------- | ---------- | ------------------- |
| Scripts, notebooks, cron jobs                     | ✅          | —                   |
| Single-threaded bots that make one call at a time | ✅          | —                   |
| Bots with concurrent market feeds                 | —          | ✅                   |
| Long-running services with many markets in flight | —          | ✅                   |
| Pairing with `STXWebSocket`                       | —          | ✅ (same event loop) |
| FastAPI / aiohttp / Starlette handlers            | —          | ✅                   |

<Tip>
  If you're reaching for `asyncio.to_thread(sync_client.markets, ...)` repeatedly, that's the signal to switch to `AsyncSTX`.
</Tip>

## Context manager

`AsyncSTX` cleans up its aiohttp session on exit. Use `async with` whenever possible:

```python theme={null}
async with AsyncSTX(region="ontario", env="staging") as client:
    await client.markets()
# Session closed here.
```

Without `async with`, call `close()` manually:

```python theme={null}
client = AsyncSTX(region="ontario", env="staging")
try:
    await client.markets()
finally:
    await client.close()
```

Letting the client go out of scope without closing leaks the aiohttp session — you'll see `Unclosed client session` warnings.

## Parallelizing requests

The async client's killer feature — fanning out over markets:

```python theme={null}
import asyncio
from stx import AsyncSTX, Selection

async def fetch_orderbook(client, market_id):
    return await client.marketInfo(
        params={"market_id": market_id},
        selections=Selection(
            "market_id",
            orderbook=Selection("bids", "asks"),
        ),
    )

async def main():
    async with AsyncSTX(region="ontario", env="staging") as client:
        market_ids = ["mkt_1", "mkt_2", "mkt_3", "mkt_4", "mkt_5"]
        markets = await asyncio.gather(
            *(fetch_orderbook(client, mid) for mid in market_ids)
        )
        for m in markets:
            print(m.market_id, m.orderbook)

asyncio.run(main())
```

### Concurrency limits

`AsyncSTX` shares one aiohttp connection pool. The default pool is generous but not infinite — for huge fan-outs, bound concurrency with a semaphore:

```python theme={null}
sem = asyncio.Semaphore(20)   # at most 20 in flight

async def bounded(coro):
    async with sem:
        return await coro

books = await asyncio.gather(
    *(bounded(fetch_orderbook(client, mid)) for mid in huge_list)
)
```

## Sharing auth with sync `STX` and `STXWebSocket`

All three clients read and write the same `User` singleton — one login covers them all:

```python theme={null}
# In a single process / event loop:
sync   = STX(region="ontario", env="staging", email="...", password="...")
async_ = AsyncSTX(region="ontario", env="staging")    # re-uses JWT from singleton
ws     = STXWebSocket(region="ontario", env="staging")  # re-uses JWT

sync.market_infos()                                   # triggers the one-time login
await async_.market_infos()                           # uses cached JWT
async with ws:
    await ws.join(Channels.MARKETS, on_message=...)
```

## Error handling

Identical to sync — same exceptions, same retry policy. See [Errors & retries](/sdks/python/errors-and-retries).

```python theme={null}
from stx.exceptions import STXRateLimitException

try:
    resp = await client.orders(params={"status": "OPEN"})
except STXRateLimitException as e:
    await asyncio.sleep(e.retry_after)
    resp = await client.orders(params={"status": "OPEN"})
```

## Pairing with `STXWebSocket`

The common pattern: WebSocket for live feeds, `AsyncSTX` for control-plane calls (place/cancel orders, fetch positions). One event loop, both clients:

```python theme={null}
import asyncio
from stx import AsyncSTX, STXWebSocket
from stx.enums import Channels

async def run():
    async with AsyncSTX(region="ontario", env="staging",
                        email="you@example.com", password="...") as client, \
               STXWebSocket(region="ontario", env="staging") as ws:

        async def on_market(msg):
            if msg.event == "market_updated":
                # Act on the signal — async call into the same event loop.
                await client.place_order(params=..., selections=...)

        await ws.join(Channels.MARKETS, on_message=on_market)
        await asyncio.Future()   # run forever

asyncio.run(run())
```

## FastAPI example

```python theme={null}
from contextlib import asynccontextmanager
from fastapi import FastAPI
from stx import AsyncSTX, Selection

@asynccontextmanager
async def lifespan(app: FastAPI):
    app.state.stx = AsyncSTX(
        region="ontario", env="production",
        email="...", password="...",
    )
    yield
    await app.state.stx.close()

app = FastAPI(lifespan=lifespan)

@app.get("/markets")
async def list_markets():
    markets = await app.state.stx.market_infos(
        selections=Selection("market_id", "title", "status"),
    )
    # FastAPI serializes Pydantic models automatically — no .model_dump() needed.
    return markets
```

One shared `AsyncSTX` across all requests — its aiohttp session is connection-pool-backed and designed for concurrent use.

## Next

<CardGroup cols={2}>
  <Card title="WebSockets" icon="tower-broadcast" href="/sdks/python/websockets">
    Live order and market updates over Phoenix channels.
  </Card>

  <Card title="Errors & retries" icon="triangle-exclamation" href="/sdks/python/errors-and-retries">
    Exception hierarchy and the automatic retry policy.
  </Card>
</CardGroup>
