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

# Python SDK

> Official async Python SDK for the Limitless Exchange API

## Overview

The Limitless Exchange Python SDK (`limitless-sdk`) is an **async-first** Python client built on top of aiohttp. It provides:

* Fully asynchronous HTTP and WebSocket clients
* Pydantic models for type-safe request and response handling
* Automatic venue caching for EIP-712 order signing
* Built-in retry logic for transient API failures
* WebSocket streaming with auto-reconnect

<Note>
  The SDK requires **Python 3.9+** and uses `async`/`await` throughout. All network calls must be awaited inside an `asyncio` event loop.
</Note>

## Installation

```bash theme={null}
pip install limitless-sdk
```

## Quick Start

<Steps>
  <Step title="Initialize the HTTP client">
    ```python theme={null}
    import asyncio
    from limitless_sdk.api import HttpClient

    http_client = HttpClient()  # loads LIMITLESS_API_KEY from env
    ```
  </Step>

  <Step title="Fetch active markets">
    ```python theme={null}
    from limitless_sdk.markets import MarketFetcher

    async def main():
        market_fetcher = MarketFetcher(http_client)
        markets = await market_fetcher.get_active_markets()

        for market in markets["data"]:
            print(market["title"], market["slug"])

        await http_client.close()

    asyncio.run(main())
    ```
  </Step>

  <Step title="Check your positions">
    ```python theme={null}
    from limitless_sdk.portfolio import PortfolioFetcher

    async def main():
        portfolio = PortfolioFetcher(http_client)
        positions = await portfolio.get_positions()

        for pos in positions.get("clob", []):
            print(pos["market"]["title"], pos["size"])

        await http_client.close()

    asyncio.run(main())
    ```
  </Step>
</Steps>

## Authentication

Authentication uses scoped API tokens with HMAC-SHA256 request signing:

* HMAC headers `lmts-api-key`, `lmts-timestamp`, `lmts-signature` — the SDK builds and signs them for you when you pass HMAC credentials

<Tabs>
  <Tab title="Environment variable (recommended)">
    Set the `LIMITLESS_API_KEY` environment variable. The `HttpClient` loads it automatically:

    ```bash theme={null}
    export LIMITLESS_API_KEY="lmts_your_key_here"
    ```

    ```python theme={null}
    http_client = HttpClient()  # auto-loads LIMITLESS_API_KEY
    ```
  </Tab>

  <Tab title="HMAC (partner/programmatic)">
    Use the root client with scoped token credentials:

    ```python theme={null}
    from limitless_sdk import Client, HMACCredentials

    client = Client(
        base_url="https://api.limitless.exchange",
        hmac_credentials=HMACCredentials(
            token_id="your-token-id",
            secret="your-base64-secret",
        ),
    )
    ```
  </Tab>

  <Tab title="Explicit parameter">
    Pass `api_key` directly to the constructor:

    ```python theme={null}
    http_client = HttpClient(api_key="lmts_your_key_here")
    ```
  </Tab>
</Tabs>

<Info>
  With `hmac_credentials` set, the SDK automatically generates and sends `lmts-api-key`, `lmts-timestamp`, and `lmts-signature`. Do not manually build HMAC headers when using the SDK client.
</Info>

<Warning>
  Never hardcode API keys in source code or commit them to version control. Use environment variables or a secrets manager.
</Warning>

## Client constructor

The recommended entrypoint is the root `Client` class, which composes all domain services (markets, portfolio, orders, API tokens, partner accounts, delegated orders):

```python theme={null}
from limitless_sdk import Client

client = Client(base_url="https://api.limitless.exchange")
```

For partner integrations using HMAC authentication:

```python theme={null}
from limitless_sdk import Client, HMACCredentials

client = Client(
    base_url="https://api.limitless.exchange",
    hmac_credentials=HMACCredentials(
        token_id="your-token-id",
        secret="your-base64-secret",
    ),
)
```

| Parameter            | Type                      | Default                                | Description                                                                                       |
| -------------------- | ------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `base_url`           | `str`                     | `https://api.limitless.exchange`       | API base URL                                                                                      |
| `api_key`            | `str \| None`             | `None` (reads `LIMITLESS_API_KEY` env) | Legacy API key authentication                                                                     |
| `hmac_credentials`   | `HMACCredentials \| None` | `None`                                 | HMAC credentials for scoped API token auth (see [Programmatic API](/developers/programmatic-api)) |
| `additional_headers` | `dict \| None`            | `None`                                 | Extra headers merged into every request                                                           |

### HttpClient (lower-level)

You can also use `HttpClient` directly for more control:

```python theme={null}
from limitless_sdk.api import HttpClient

http_client = HttpClient(
    base_url="https://api.limitless.exchange",
    api_key="lmts_your_key_here",
)
```

<Tip>
  Always call `await http_client.close()` when you are finished to cleanly shut down the underlying aiohttp session.
</Tip>

## Logging

The SDK provides a `ConsoleLogger` with configurable log levels for debugging:

```python theme={null}
from limitless_sdk.types import ConsoleLogger, LogLevel

logger = ConsoleLogger(level=LogLevel.DEBUG)
```

| Level            | Description                                                                |
| ---------------- | -------------------------------------------------------------------------- |
| `LogLevel.DEBUG` | Verbose output including headers, venue cache operations, and raw payloads |
| `LogLevel.INFO`  | General operational messages                                               |
| `LogLevel.WARN`  | Warnings about potential issues                                            |
| `LogLevel.ERROR` | Errors only                                                                |

<Tip>
  Set `LogLevel.DEBUG` during development to see request headers, venue cache hits/misses, and full API responses. Switch to `INFO` or `WARN` in production.
</Tip>

## Source Code

The SDK is open source. Contributions and issue reports are welcome.

<Card title="GitHub Repository" icon="github" href="https://github.com/limitless-labs-group/limitless-sdk">
  Browse the source, report issues, and contribute at github.com/limitless-labs-group/limitless-sdk
</Card>

## Disclaimer

<Warning>
  **USE AT YOUR OWN RISK.** This SDK is provided as-is with no guarantees. You are solely responsible for any trading activity conducted through this software. Limitless Exchange is not available to users in the United States or other restricted jurisdictions. By using this SDK, you confirm compliance with all applicable local laws and regulations.
</Warning>

## Next Steps

<CardGroup cols={2}>
  <Card title="Markets" icon="chart-bar" href="/developers/sdk/python/markets">
    Discover markets, fetch orderbooks, and understand venue caching.
  </Card>

  <Card title="Market Pages" icon="compass" href="/developers/sdk/python/market-pages">
    Browse markets by category with navigation, filters, and pagination.
  </Card>

  <Card title="Trading & Orders" icon="arrow-right-arrow-left" href="/developers/sdk/python/orders">
    Place GTC and FOK orders, cancel orders, and manage token approvals.
  </Card>

  <Card title="Portfolio & Positions" icon="wallet" href="/developers/sdk/python/portfolio">
    Track your open positions and trading history.
  </Card>

  <Card title="API Tokens" icon="shield-halved" href="/developers/sdk/python/api-tokens">
    Derive, list, and revoke scoped HMAC tokens for partner integrations.
  </Card>

  <Card title="Partner Accounts" icon="users" href="/developers/sdk/python/partner-accounts">
    Create sub-accounts with server wallets or EOA verification.
  </Card>

  <Card title="Delegated Orders" icon="user-check" href="/developers/sdk/python/delegated-orders">
    Place orders on behalf of sub-accounts with server-side signing.
  </Card>

  <Card title="WebSocket Streaming" icon="bolt" href="/developers/sdk/python/websocket">
    Subscribe to real-time orderbook and price updates.
  </Card>

  <Card title="Error Handling & Retry" icon="rotate" href="/developers/sdk/python/error-handling">
    Retry logic, error types, and debugging strategies.
  </Card>
</CardGroup>

## Server Wallet Redemption and Withdrawal

For partner server-wallet sub-accounts, the SDK provides helper methods for payout settlement and treasury movement:

* [`POST /portfolio/redeem`](/api-reference/portfolio/redeem) — claim resolved positions
* [`POST /portfolio/withdraw`](/api-reference/portfolio/withdraw) — transfer ERC20 funds from managed sub-accounts
* [`POST /portfolio/withdrawal-addresses`](/api-reference/portfolio/add-withdrawal-address) — allowlist an explicit treasury destination with Privy identity auth
* [`DELETE /portfolio/withdrawal-addresses/:address`](/api-reference/portfolio/delete-withdrawal-address) — remove an allowlisted destination with Privy identity auth

Required scopes for `apiToken` auth: `trading` for redeem and `withdrawal` for withdraw. Allowlist add/delete calls use a Privy identity token instead of API-token/HMAC auth.

```python theme={null}
import os
from limitless_sdk import PartnerWithdrawalAddressInput

identity_token = os.environ["PRIVY_IDENTITY_TOKEN"]
treasury_address = "0x0F3262730c909408042F9Da345a916dc0e1F9787"

await client.partner_accounts.add_withdrawal_address(
    identity_token,
    PartnerWithdrawalAddressInput(address=treasury_address, label="treasury"),
)

withdraw = await client.server_wallets.withdraw(
    amount="1000000",
    on_behalf_of=child_profile_id,
    destination=treasury_address,
)

print(withdraw.destination)
```

Set `on_behalf_of` when withdrawing from a child server-wallet profile. `destination` is optional for child withdrawals; when omitted, the API defaults to the authenticated partner smart wallet when present, otherwise the authenticated partner account. You can omit `on_behalf_of` only when withdrawing the authenticated caller's own server wallet to an explicit `destination`.

See the full flow and scope guidance in [Programmatic API](/developers/programmatic-api).
