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

# Go SDK

> Official Go SDK for the Limitless Exchange API

## Overview

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

* Strongly typed structs for all API requests and responses
* Automatic venue caching for EIP-712 order signing
* Built-in retry logic with exponential backoff (using Go generics)
* WebSocket streaming with auto-reconnect
* Functional options pattern for flexible configuration

<Note>
  The SDK requires **Go 1.22+**. All I/O methods accept a `context.Context` as the first parameter and return `error` as the last return value, following standard Go conventions.
</Note>

## Installation

```bash theme={null}
go get github.com/limitless-labs-group/limitless-exchange-go-sdk@latest
```

## Quick Start

<Steps>
  <Step title="Initialize the HTTP client">
    ```go theme={null}
    package main

    import (
        "context"
        "fmt"
        "os"

        limitless "github.com/limitless-labs-group/limitless-exchange-go-sdk/limitless"
    )

    func main() {
        client := limitless.NewHttpClient(
            limitless.WithHMACCredentials(limitless.HMACCredentials{
                TokenID: os.Getenv("LMTS_TOKEN_ID"),
                Secret:  os.Getenv("LMTS_TOKEN_SECRET"),
            }),
        )
    }
    ```
  </Step>

  <Step title="Fetch active markets">
    ```go theme={null}
    func main() {
        client := limitless.NewHttpClient(
            limitless.WithHMACCredentials(limitless.HMACCredentials{
                TokenID: os.Getenv("LMTS_TOKEN_ID"),
                Secret:  os.Getenv("LMTS_TOKEN_SECRET"),
            }),
        )
        marketFetcher := limitless.NewMarketFetcher(client)

        ctx := context.Background()
        result, err := marketFetcher.GetActiveMarkets(ctx, &limitless.ActiveMarketsParams{
            Limit: 10,
            Page:  1,
        })
        if err != nil {
            panic(err)
        }

        for _, m := range result.Data {
            fmt.Println(m.Title, m.Slug)
        }
    }
    ```
  </Step>

  <Step title="Check your positions">
    ```go theme={null}
    func main() {
        client := limitless.NewHttpClient(
            limitless.WithHMACCredentials(limitless.HMACCredentials{
                TokenID: os.Getenv("LMTS_TOKEN_ID"),
                Secret:  os.Getenv("LMTS_TOKEN_SECRET"),
            }),
        )
        portfolio := limitless.NewPortfolioFetcher(client)

        ctx := context.Background()
        positions, err := portfolio.GetPositions(ctx)
        if err != nil {
            panic(err)
        }

        for _, pos := range positions.CLOB {
            fmt.Println(pos.Market.Title)
        }
    }
    ```
  </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](https://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)">
    Store the token ID and secret in your environment, then pass them as HMAC credentials:

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

    ```go theme={null}
    client := limitless.NewHttpClient(
        limitless.WithHMACCredentials(limitless.HMACCredentials{
            TokenID: os.Getenv("LMTS_TOKEN_ID"),
            Secret:  os.Getenv("LMTS_TOKEN_SECRET"),
        }),
    )
    ```
  </Tab>

  <Tab title="Legacy API key">
    Set the `LIMITLESS_API_KEY` environment variable and the `HttpClient` loads it automatically, or pass it explicitly with `WithAPIKey`:

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

    ```go theme={null}
    client := limitless.NewHttpClient() // auto-loads LIMITLESS_API_KEY

    // Or pass it explicitly:
    client = limitless.NewHttpClient(
        limitless.WithAPIKey("lmts_your_key_here"),
    )
    ```
  </Tab>
</Tabs>

<Info>
  With `WithHMACCredentials(...)` 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>

<Note>
  **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.
</Note>

<Warning>
  Never hardcode API 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 (markets, portfolio, orders, API tokens, partner accounts, delegated orders). Authenticate it with scoped-token HMAC credentials:

```go theme={null}
client := limitless.NewClient(
    limitless.WithHMACCredentials(limitless.HMACCredentials{
        TokenID: os.Getenv("LMTS_TOKEN_ID"),
        Secret:  os.Getenv("LMTS_TOKEN_SECRET"),
    }),
)

// client.Markets, client.Portfolio, client.Pages,
// client.ApiTokens, client.PartnerAccounts, client.DelegatedOrders
```

The legacy `WithAPIKey` option still works but is not recommended for new integrations:

```go theme={null}
client := limitless.NewClient(
    limitless.WithAPIKey("lmts_your_key_here"),
)
```

## HttpClient Options

The `HttpClient` uses the functional options pattern. Pass any combination of options to `NewHttpClient()` or `NewClient()`:

| Option                       | Type                | Default                          | Description                                                                                       |
| ---------------------------- | ------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------- |
| `WithBaseURL(url)`           | `string`            | `https://api.limitless.exchange` | API base URL                                                                                      |
| `WithAPIKey(key)`            | `string`            | Reads `LIMITLESS_API_KEY` env    | Legacy `X-API-Key` auth (still works; prefer a scoped API token)                                  |
| `WithHMACCredentials(creds)` | `HMACCredentials`   | --                               | HMAC credentials for scoped API token auth (see [Programmatic API](/developers/programmatic-api)) |
| `WithTimeout(d)`             | `time.Duration`     | `30s`                            | HTTP request timeout                                                                              |
| `WithMaxIdleConns(n)`        | `int`               | `50`                             | Maximum idle connections in the pool                                                              |
| `WithIdleConnTimeout(d)`     | `time.Duration`     | `60s`                            | How long idle connections remain in the pool                                                      |
| `WithTransport(t)`           | `http.RoundTripper` | Default transport                | Custom HTTP transport                                                                             |
| `WithAdditionalHeaders(h)`   | `map[string]string` | `nil`                            | Extra headers merged into every request                                                           |
| `WithLogger(l)`              | `Logger`            | `NoOpLogger`                     | Logger for request/response tracing                                                               |

```go theme={null}
client := limitless.NewHttpClient(
    limitless.WithHMACCredentials(limitless.HMACCredentials{
        TokenID: os.Getenv("LMTS_TOKEN_ID"),
        Secret:  os.Getenv("LMTS_TOKEN_SECRET"),
    }),
    limitless.WithTimeout(15 * time.Second),
    limitless.WithLogger(limitless.NewConsoleLogger(limitless.LogLevelDebug)),
)
```

## Logging

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

```go theme={null}
logger := limitless.NewConsoleLogger(limitless.LogLevelDebug)
client := limitless.NewHttpClient(limitless.WithLogger(logger))
```

| Level           | Description                                                                |
| --------------- | -------------------------------------------------------------------------- |
| `LogLevelDebug` | Verbose output including headers, venue cache operations, and raw payloads |
| `LogLevelInfo`  | General operational messages                                               |
| `LogLevelWarn`  | Warnings about potential issues                                            |
| `LogLevelError` | Errors only                                                                |

<Tip>
  Set `LogLevelDebug` during development to see request headers, venue cache hits/misses, and full API responses. Switch to `LogLevelInfo` or `LogLevelWarn` 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-exchange-go-sdk">
  Browse the source, report issues, and contribute at github.com/limitless-labs-group/limitless-exchange-go-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/go/markets">
    Discover markets, fetch orderbooks, and understand venue caching.
  </Card>

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

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

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

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

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

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

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

  <Card title="Error Handling & Retry" icon="rotate" href="/developers/sdk/go/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.

```go theme={null}
identityToken := os.Getenv("PRIVY_IDENTITY_TOKEN")
treasuryAddress := "0x0F3262730c909408042F9Da345a916dc0e1F9787"

_, err := client.PartnerAccounts.AddWithdrawalAddress(ctx, identityToken, limitless.PartnerWithdrawalAddressInput{
    Address: treasuryAddress,
    Label:   "treasury",
})
if err != nil {
    log.Fatal(err)
}

withdraw, err := client.ServerWallets.Withdraw(ctx, limitless.WithdrawServerWalletParams{
    Amount:      "1000000",
    OnBehalfOf:  childProfileID,
    Destination: treasuryAddress,
})
if err != nil {
    log.Fatal(err)
}

fmt.Println(withdraw.Destination)
```

Set `OnBehalfOf` 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. Leave `OnBehalfOf` as zero 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).
