> ## 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 Quick Start

> End-to-end Python implementation for trading on Limitless Exchange

## Overview

This guide walks you through a complete Python implementation for trading on Limitless Exchange: authentication, fetching market data, building and signing orders with EIP-712, and submitting them via the REST API.

## Prerequisites

<Steps>
  <Step title="Install dependencies">
    Install the required packages:

    ```bash theme={null}
    pip install eth-account requests web3
    ```

    * **eth-account**: EIP-712 signing and key management
    * **requests**: HTTP client for the REST API
    * **web3**: Address checksumming and utilities
  </Step>

  <Step title="Obtain credentials">
    * **Scoped API Token**: Derive a token at [limitless.exchange](https://limitless.exchange) → profile menu → API Tokens → **Derive**. You get a **token ID** and a **secret** (base64-encoded). The secret is shown once — store it securely. See [Authentication](/developers/authentication) for the full flow.
    * **Private Key**: Your wallet's private key for EIP-712 order signing. Never share or commit it.
  </Step>
</Steps>

<Warning>
  **Never share your private key.** Store it in environment variables or a secure secrets manager. Do not hardcode it in source code or commit it to version control.
</Warning>

## Authentication

Authenticated API requests (e.g. submitting orders) are signed with HMAC-SHA256 using your scoped API token. Each request carries three headers — `lmts-api-key`, `lmts-timestamp`, and `lmts-signature` — computed over a canonical message. See [Authentication](/developers/authentication) for the full reference.

<Note>
  Your **private key** is used only for **EIP-712 order signing**. The **scoped API token** (token ID + secret) handles request authentication. Both are required for trading. Public market data (browsing markets, orderbooks) needs no authentication.
</Note>

```python theme={null}
import os
import hmac
import hashlib
import base64
from datetime import datetime, timezone

API_BASE = "https://api.limitless.exchange"
TOKEN_ID = os.environ["LMTS_TOKEN_ID"]       # token ID from token derivation
TOKEN_SECRET = os.environ["LMTS_TOKEN_SECRET"]  # base64-encoded secret


def sign_request(token_id: str, secret: str, method: str, path: str, body: str = "") -> dict:
    """Build HMAC auth headers for a single request (method + path + body)."""
    timestamp = datetime.now(timezone.utc).isoformat()
    message = f"{timestamp}\n{method}\n{path}\n{body}"
    signature = base64.b64encode(
        hmac.new(base64.b64decode(secret), message.encode("utf-8"), hashlib.sha256).digest()
    ).decode("utf-8")
    return {"lmts-api-key": token_id, "lmts-timestamp": timestamp, "lmts-signature": signature}
```

<Warning>
  The signed `path` must include the **query string** if present. The timestamp must be within **30 seconds** of server time. For GET requests, the body is an empty string.
</Warning>

## Fetching Market Data

Use `GET /markets/:slug` to retrieve market details, including venue addresses and position IDs. Cache this data per market; it is static.

<CodeGroup>
  ```python theme={null}
  def fetch_market(slug: str) -> dict:
      """Fetch market data including venue and position IDs. Public endpoint — no auth."""
      resp = requests.get(f"{API_BASE}/markets/{slug}")
      resp.raise_for_status()
      return resp.json()
  ```

  ```python theme={null}
  # Example response (CLOB market)
  {
      "slug": "btc-above-100k-march-2025",
      "venue": {
          "exchange": "0xA1b2C3d4E5f6...",
          "adapter": null
      },
      "tokens": {"yes": "19633...", "no": "19633..."}
  }
  ```
</CodeGroup>

<Tip>
  **tokens.yes** is the YES token ID, **tokens.no** is the NO token ID. Use the appropriate one based on your order side and outcome.
</Tip>

## Building Order Payloads

Orders require specific fields. Key values:

| Field           | Value | Description         |
| --------------- | ----- | ------------------- |
| `side`          | `0`   | BUY                 |
| `side`          | `1`   | SELL                |
| `signatureType` | `0`   | EOA wallet          |
| `orderType`     | `GTC` | Good Till Cancelled |
| `orderType`     | `FOK` | Fill or Kill        |

USDC uses **6 decimals** (1 USDC = 1,000,000 units). Shares are scaled by 1e6.

<Tabs>
  <Tab title="BUY order">
    You pay USDC, receive shares. Use `tokens.yes` for YES, `tokens.no` for NO.

    ```
    makerAmount = price_in_dollars * num_shares * 1e6   # USDC you pay
    takerAmount = num_shares * 1e6                       # Shares you receive
    side = 0
    ```

    Example: BUY 10 YES shares at \$0.65 → `makerAmount` = 6,500,000, `takerAmount` = 10,000,000
  </Tab>

  <Tab title="SELL order">
    You pay shares, receive USDC. Use the token ID of the shares you are selling.

    ```
    makerAmount = num_shares * 1e6                       # Shares you pay
    takerAmount = price_in_dollars * num_shares * 1e6   # USDC you receive
    side = 1
    ```

    Example: SELL 10 YES shares at \$0.65 → `makerAmount` = 10,000,000, `takerAmount` = 6,500,000
  </Tab>
</Tabs>

## EIP-712 Signing

Sign orders using EIP-712 with the venue's exchange address as `verifyingContract`.

<Info>
  See [EIP-712 Order Signing](/developers/eip712-signing) for the full type definition and field reference.
</Info>

```python theme={null}
from eth_account import Account
from eth_account.messages import encode_typed_data
from web3 import Web3

CHAIN_ID = 8453  # Base
ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"

def sign_order(order_data: dict, verifying_contract: str, private_key: str) -> str:
    """Sign order with EIP-712 using venue.exchange as verifyingContract."""
    domain = {
        "name": "Limitless CTF Exchange",
        "version": "1",
        "chainId": CHAIN_ID,
        "verifyingContract": Web3.to_checksum_address(verifying_contract),
    }
    types = {
        "EIP712Domain": [
            {"name": "name", "type": "string"},
            {"name": "version", "type": "string"},
            {"name": "chainId", "type": "uint256"},
            {"name": "verifyingContract", "type": "address"},
        ],
        "Order": [
            {"name": "salt", "type": "uint256"},
            {"name": "maker", "type": "address"},
            {"name": "signer", "type": "address"},
            {"name": "taker", "type": "address"},
            {"name": "tokenId", "type": "uint256"},
            {"name": "makerAmount", "type": "uint256"},
            {"name": "takerAmount", "type": "uint256"},
            {"name": "expiration", "type": "uint256"},
            {"name": "nonce", "type": "uint256"},
            {"name": "feeRateBps", "type": "uint256"},
            {"name": "side", "type": "uint8"},
            {"name": "signatureType", "type": "uint8"},
        ],
    }
    message = {
        "salt": order_data["salt"],
        "maker": Web3.to_checksum_address(order_data["maker"]),
        "signer": Web3.to_checksum_address(order_data["signer"]),
        "taker": Web3.to_checksum_address(order_data["taker"]),
        "tokenId": int(order_data["tokenId"]),
        "makerAmount": order_data["makerAmount"],
        "takerAmount": order_data["takerAmount"],
        "expiration": order_data["expiration"],
        "nonce": order_data["nonce"],
        "feeRateBps": order_data["feeRateBps"],
        "side": order_data["side"],
        "signatureType": order_data["signatureType"],
    }
    typed_data = {
        "types": types,
        "primaryType": "Order",
        "domain": domain,
        "message": message,
    }
    encoded = encode_typed_data(typed_data)
    signed = Account.sign_message(encoded, private_key=private_key)
    return signed.signature.hex()
```

<Note>
  All addresses must be **checksummed** (EIP-55). Use `Web3.to_checksum_address()`.
</Note>

## Submitting Orders

Send the signed order to `POST /orders`:

```python theme={null}
def submit_order(order_payload: dict) -> dict:
    """Submit a signed order to the API (HMAC-authenticated)."""
    body = json.dumps(order_payload)
    auth = sign_request(TOKEN_ID, TOKEN_SECRET, "POST", "/orders", body)
    resp = requests.post(
        f"{API_BASE}/orders",
        headers={**auth, "Content-Type": "application/json"},
        data=body,
    )
    resp.raise_for_status()
    return resp.json()
```

## Complete Working Example

<CodeGroup>
  ```python theme={null}
  """
  Limitless Exchange - Python Quick Start
  Place a BUY order for YES shares on a CLOB market.
  """
  import os
  import time
  import json
  import hmac
  import hashlib
  import base64
  from datetime import datetime, timezone
  import requests
  from eth_account import Account
  from eth_account.messages import encode_typed_data
  from web3 import Web3

  API_BASE = "https://api.limitless.exchange"
  CHAIN_ID = 8453
  ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"

  # Load from environment
  TOKEN_ID = os.environ["LMTS_TOKEN_ID"]
  TOKEN_SECRET = os.environ["LMTS_TOKEN_SECRET"]  # base64-encoded
  PRIVATE_KEY = os.environ["PRIVATE_KEY"]
  OWNER_ID = int(os.environ.get("OWNER_ID", "0"))  # Profile ID from API


  def sign_request(token_id: str, secret: str, method: str, path: str, body: str = "") -> dict:
      timestamp = datetime.now(timezone.utc).isoformat()
      message = f"{timestamp}\n{method}\n{path}\n{body}"
      signature = base64.b64encode(
          hmac.new(base64.b64decode(secret), message.encode("utf-8"), hashlib.sha256).digest()
      ).decode("utf-8")
      return {"lmts-api-key": token_id, "lmts-timestamp": timestamp, "lmts-signature": signature}


  def fetch_market(slug: str) -> dict:
      # Public endpoint — no auth required.
      resp = requests.get(f"{API_BASE}/markets/{slug}")
      resp.raise_for_status()
      return resp.json()


  def sign_order(order_data: dict, verifying_contract: str, pk: str) -> str:
      domain = {
          "name": "Limitless CTF Exchange",
          "version": "1",
          "chainId": CHAIN_ID,
          "verifyingContract": Web3.to_checksum_address(verifying_contract),
      }
      types = {
          "EIP712Domain": [
              {"name": "name", "type": "string"},
              {"name": "version", "type": "string"},
              {"name": "chainId", "type": "uint256"},
              {"name": "verifyingContract", "type": "address"},
          ],
          "Order": [
              {"name": "salt", "type": "uint256"},
              {"name": "maker", "type": "address"},
              {"name": "signer", "type": "address"},
              {"name": "taker", "type": "address"},
              {"name": "tokenId", "type": "uint256"},
              {"name": "makerAmount", "type": "uint256"},
              {"name": "takerAmount", "type": "uint256"},
              {"name": "expiration", "type": "uint256"},
              {"name": "nonce", "type": "uint256"},
              {"name": "feeRateBps", "type": "uint256"},
              {"name": "side", "type": "uint8"},
              {"name": "signatureType", "type": "uint8"},
          ],
      }
      msg = {
          "salt": order_data["salt"],
          "maker": Web3.to_checksum_address(order_data["maker"]),
          "signer": Web3.to_checksum_address(order_data["signer"]),
          "taker": Web3.to_checksum_address(order_data["taker"]),
          "tokenId": int(order_data["tokenId"]),
          "makerAmount": order_data["makerAmount"],
          "takerAmount": order_data["takerAmount"],
          "expiration": order_data["expiration"],
          "nonce": order_data["nonce"],
          "feeRateBps": order_data["feeRateBps"],
          "side": order_data["side"],
          "signatureType": order_data["signatureType"],
      }
      encoded = encode_typed_data({
          "types": types,
          "primaryType": "Order",
          "domain": domain,
          "message": msg,
      })
      signed = Account.sign_message(encoded, private_key=pk)
      return signed.signature.hex()


  def place_buy_order(
      market_slug: str,
      num_shares: float,
      price_per_share: float,
      order_type: str = "GTC",
  ) -> dict:
      market = fetch_market(market_slug)
      venue = market["venue"]
      tokens = market["tokens"]
      account = Account.from_key(PRIVATE_KEY)
      maker = account.address

      # YES token is tokens["yes"], NO token is tokens["no"]
      token_id = tokens["yes"]
      maker_amount = int(price_per_share * num_shares * 1e6)
      taker_amount = int(num_shares * 1e6)

      salt = int(time.time() * 1000)
      order_data = {
          "salt": salt,
          "maker": Web3.to_checksum_address(maker),
          "signer": Web3.to_checksum_address(maker),
          "taker": ZERO_ADDRESS,
          "tokenId": token_id,
          "makerAmount": maker_amount,
          "takerAmount": taker_amount,
          "expiration": 0,
          "nonce": 0,
          "feeRateBps": 0,
          "side": 0,  # BUY
          "signatureType": 0,  # EOA
      }
      signature = sign_order(order_data, venue["exchange"], PRIVATE_KEY)

      order_payload = {
          "order": {**order_data, "signature": signature},
          "ownerId": OWNER_ID,
          "orderType": order_type,
          "marketSlug": market_slug,
      }
      body = json.dumps(order_payload)
      auth = sign_request(TOKEN_ID, TOKEN_SECRET, "POST", "/orders", body)
      resp = requests.post(
          f"{API_BASE}/orders",
          headers={**auth, "Content-Type": "application/json"},
          data=body,
      )
      resp.raise_for_status()
      return resp.json()


  if __name__ == "__main__":
      result = place_buy_order(
          market_slug="your-market-slug",
          num_shares=10.0,
          price_per_share=0.65,
          order_type="GTC",
      )
      print(result)
  ```

  ```bash theme={null}
  # Run with environment variables
  export LMTS_TOKEN_ID="your_token_id"
  export LMTS_TOKEN_SECRET="your_base64_secret"
  export PRIVATE_KEY="0x..."
  export OWNER_ID="12345"  # Your profile ID
  python quickstart.py
  ```
</CodeGroup>

<Tip>
  **ownerId** is your profile ID. Obtain it from your first authenticated response (e.g. portfolio or auth endpoints) or from the Limitless UI. Set `OWNER_ID` in your environment.
</Tip>

## Troubleshooting

<Steps>
  <Step title="401 Unauthorized">
    * Verify `LMTS_TOKEN_ID` and `LMTS_TOKEN_SECRET` are set and the token is active in the Limitless UI.
    * Ensure `lmts-timestamp` is within **30 seconds** of server time (check your clock).
    * Confirm the signed `path` matches the request path **including any query string**, and the signed body is the exact bytes you send.
  </Step>

  <Step title="400 Invalid order / signature mismatch">
    * Verify `verifyingContract` is the market's `venue.exchange` address.
    * Ensure all addresses are checksummed (EIP-55).
    * Confirm `makerAmount` and `takerAmount` use 1e6 scaling for USDC and shares.
  </Step>

  <Step title="Insufficient balance or allowance">
    * Ensure you have enough USDC on Base for BUY orders.
    * Approve USDC to `venue.exchange` for BUY; Conditional Tokens to `venue.exchange` (and `venue.adapter` for NegRisk SELL) for SELL.
  </Step>

  <Step title="Wrong tokenId">
    Use `tokens.yes` for YES and `tokens.no` for NO. Double-check you are trading the correct outcome.
  </Step>
</Steps>

## Next Steps

<CardGroup cols={2}>
  <Card title="EIP-712 Signing" icon="pen" href="/developers/eip712-signing">
    Full order type definition and field reference.
  </Card>

  <Card title="Venue System" icon="building" href="/developers/venue-system">
    Understanding venue contracts and token approvals.
  </Card>

  <Card title="API Reference" icon="book" href="/api-reference/introduction">
    Complete endpoint documentation.
  </Card>

  <Card title="Authentication" icon="key" href="/developers/authentication">
    Scoped API token setup and HMAC request signing.
  </Card>
</CardGroup>
