> ## 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.

# Rust SDK

> Official Rust SDK for the Limitless Exchange API

## Overview

The Limitless Exchange Rust SDK (`limitless-exchange-rust-sdk`) is a typed async client for interacting with both **CLOB** and **NegRisk** prediction markets. It provides:

* Strongly typed request and response models
* Built-in EIP-712 order building and signing
* Root `Client` composition for markets, portfolio, navigation, partner flows, and WebSockets
* Pluggable logging and retry helpers
* Async WebSocket streaming with auto-reconnect

<Note>
  The SDK requires **Rust 1.74+** and uses `async` / `await` throughout. The examples below assume a Tokio runtime.
</Note>

## Installation

```toml theme={null}
[dependencies]
limitless-exchange-rust-sdk = "1.1.0"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
```

## Quick Start

<Steps>
  <Step title="Initialize the client">
    ```rust theme={null}
    use limitless_exchange_rust_sdk::Client;

    #[tokio::main]
    async fn main() -> Result<(), Box<dyn std::error::Error>> {
        let client = Client::new()?;
        Ok(())
    }
    ```
  </Step>

  <Step title="Fetch active markets">
    ```rust theme={null}
    use limitless_exchange_rust_sdk::{ActiveMarketsParams, ActiveMarketsSortBy, Client};

    #[tokio::main]
    async fn main() -> Result<(), Box<dyn std::error::Error>> {
        let client = Client::new()?;

        let result = client
            .markets
            .get_active_markets(Some(&ActiveMarketsParams {
                limit: Some(10),
                page: Some(1),
                sort_by: Some(ActiveMarketsSortBy::Newest),
            }))
            .await?;

        for market in result.data {
            println!("{} {}", market.title, market.slug);
        }

        Ok(())
    }
    ```
  </Step>

  <Step title="Check your positions">
    ```rust theme={null}
    use limitless_exchange_rust_sdk::{Client, HmacCredentials};

    #[tokio::main]
    async fn main() -> Result<(), Box<dyn std::error::Error>> {
        // Authenticate with a scoped API token (HMAC credentials).
        let http = Client::builder()
            .hmac_credentials(HmacCredentials {
                token_id: std::env::var("LMTS_TOKEN_ID")?,
                secret: std::env::var("LMTS_TOKEN_SECRET")?,
            })
            .build()?;
        let client = Client::from_http_client(http)?;

        let positions = client.portfolio.get_positions().await?;
        println!("CLOB positions: {}", positions.clob.len());

        Ok(())
    }
    ```
  </Step>
</Steps>

## Authentication

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

* A scoped API token is a **token ID** plus a one-time **secret**, generated at limitless.exchange → profile menu → **Api keys**
* 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="Scoped API token (recommended)">
    Pass your token ID and secret as HMAC credentials via `Client::builder()`. Read them from the environment so they never live in source:

    ```bash theme={null}
    export LMTS_TOKEN_ID="your-token-id"
    export LMTS_TOKEN_SECRET="your-base64-secret"
    ```

    ```rust theme={null}
    use limitless_exchange_rust_sdk::{Client, HmacCredentials};

    let http = Client::builder()
        .hmac_credentials(HmacCredentials {
            token_id: std::env::var("LMTS_TOKEN_ID")?,
            secret: std::env::var("LMTS_TOKEN_SECRET")?,
        })
        .build()?;

    let client = Client::from_http_client(http)?;
    ```
  </Tab>

  <Tab title="Legacy API key">
    **Legacy:** an older API key (`LIMITLESS_API_KEY`, sent as the `X-API-Key` header) still works but is not recommended for new integrations. Prefer a scoped API token.

    Set `LIMITLESS_API_KEY` and let `Client::new()` load it automatically:

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

    ```rust theme={null}
    use limitless_exchange_rust_sdk::Client;

    let client = Client::new()?;
    ```

    Or pass it explicitly with the `api_key(...)` builder:

    ```rust theme={null}
    use limitless_exchange_rust_sdk::Client;

    let http = Client::builder()
        .api_key("lmts_your_key_here")
        .build()?;

    let client = Client::from_http_client(http)?;
    ```
  </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, HMAC secrets, or raw wallet private keys in source code or commit them to version control. Use environment variables or a secrets manager.
</Warning>

## Root Client

The recommended entrypoint is the root `Client`, which composes all domain services:

```rust theme={null}
use limitless_exchange_rust_sdk::Client;

let client = Client::new()?;

// client.markets
// client.portfolio
// client.pages
// client.api_tokens
// client.partner_accounts
// client.delegated_orders
// client.server_wallets
```

For signing orders, create an `OrderClient` from the root client:

```rust theme={null}
let order_client = client.new_order_client(&std::env::var("PRIVATE_KEY")?, None)?;
```

For streaming, create a `WebSocketClient` from the root client:

```rust theme={null}
let ws = client.new_websocket_client(None);
```

## HttpClient Builder Options

The SDK uses a builder pattern on `Client::builder()`:

| Method                    | Type                      | Default                          | Description                                                      |
| ------------------------- | ------------------------- | -------------------------------- | ---------------------------------------------------------------- |
| `base_url(url)`           | `String`                  | `https://api.limitless.exchange` | API base URL                                                     |
| `timeout(duration)`       | `Duration`                | `30s`                            | HTTP request timeout                                             |
| `api_key(key)`            | `String`                  | Reads `LIMITLESS_API_KEY` env    | Legacy `X-API-Key` auth (still works; prefer a scoped API token) |
| `hmac_credentials(creds)` | `HmacCredentials`         | --                               | HMAC credentials for scoped API-token auth                       |
| `additional_headers(map)` | `HashMap<String, String>` | empty                            | Extra headers merged into every request                          |
| `logger(logger)`          | `SharedLogger`            | `NoopLogger`                     | Logger for request/response tracing                              |

```rust theme={null}
use std::{collections::HashMap, sync::Arc, time::Duration};

use limitless_exchange_rust_sdk::{Client, ConsoleLogger, LogLevel};

let mut headers = HashMap::new();
headers.insert("X-Strategy-Name".to_string(), "market-maker-a".to_string());

let http = Client::builder()
    .timeout(Duration::from_secs(15))
    .additional_headers(headers)
    .logger(Arc::new(ConsoleLogger::new(LogLevel::Debug)))
    .build()?;

let client = Client::from_http_client(http)?;
```

## Logging

The SDK provides a pluggable `Logger` trait with a built-in `ConsoleLogger`:

```rust theme={null}
use std::sync::Arc;

use limitless_exchange_rust_sdk::{Client, ConsoleLogger, LogLevel};

let http = Client::builder()
    .logger(Arc::new(ConsoleLogger::new(LogLevel::Debug)))
    .build()?;

let client = Client::from_http_client(http)?;
```

| Level             | Description                                                                    |
| ----------------- | ------------------------------------------------------------------------------ |
| `LogLevel::Debug` | Verbose request/response output, venue cache behavior, and WebSocket lifecycle |
| `LogLevel::Info`  | General operational messages                                                   |
| `LogLevel::Warn`  | Warnings about missing auth, cache misses, or retry behavior                   |
| `LogLevel::Error` | Errors only                                                                    |

<Tip>
  Use `LogLevel::Debug` during development when integrating signing, partner flows, or WebSockets. Switch to `Info` or `Warn` in production.
</Tip>

## 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.

```rust theme={null}
use limitless_exchange_rust_sdk::{
    PartnerWithdrawalAddressInput, WithdrawServerWalletParams,
};

let identity_token = std::env::var("PRIVY_IDENTITY_TOKEN")?;
let treasury_address = "0x0F3262730c909408042F9Da345a916dc0e1F9787";

client
    .partner_accounts
    .add_withdrawal_address(
        &identity_token,
        &PartnerWithdrawalAddressInput {
            address: treasury_address.to_string(),
            label: Some("treasury".to_string()),
        },
    )
    .await?;

let withdraw = client
    .server_wallets
    .withdraw(&WithdrawServerWalletParams {
        amount: "1000000".to_string(),
        on_behalf_of: Some(child_profile_id),
        token: None,
        destination: Some(treasury_address.to_string()),
    })
    .await?;

println!("{}", 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).

## 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-exchange-rust-sdk">
  Browse the source, report issues, and contribute at github.com/limitless-labs-group/limitless-exchange-rust-sdk
</Card>
