> For the complete documentation index, see [llms.txt](https://docs.ojolabs.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ojolabs.xyz/markets/api/python-sdk/getting-started.md).

# Getting Started

The Turbine Python SDK (`turbine-py-client`) provides EIP-712 order signing, Ed25519 bearer token authentication, HTTP API access, WebSocket streaming, and gasless on-chain operations for the Turbine prediction market platform.

## Installation

```bash
pip install turbine-py-client
```

Requires Python 3.9+. Dependencies: `eth-account`, `eth-utils`, `httpx`, `web3`, `websockets`, `pynacl`, `python-dotenv`.

## Quick Start

```python
from turbine_client import TurbineClient, Outcome, Side, OrderArgs

# Read-only client (public data only)
client = TurbineClient(
    host="https://api.turbinefi.com",
    chain_id=137,
)

# Fetch markets
markets = client.get_markets()
for market in markets:
    print(f"{market.question} (volume: {market.volume / 1e6:.2f} USDC)")
```

## Authentication Levels

The client supports three access levels. Each level unlocks additional functionality.

{% stepper %}
{% step %}

### Public (Read-Only)

What you need:

* `host` + `chain_id`

What you can do:

* Read markets, orderbooks, trades, prices

Example:

```python
client = TurbineClient(
    host="https://api.turbinefi.com",
    chain_id=137,
)

# These all work without auth
markets = client.get_markets()
orderbook = client.get_orderbook(market_id)
trades = client.get_trades(market_id)
qm = client.get_quick_market("BTC")
```

{% endstep %}

{% step %}

### Signing (Order Creation)

What you need:

* `private_key` (wallet private key)

What you can do:

* Sign orders locally (create `SignedOrder` objects). Cannot submit to API.

Example:

```python
client = TurbineClient(
    host="https://api.turbinefi.com",
    chain_id=137,
    private_key="0xYourPrivateKey",
)

# Sign an order locally
signed = client.create_limit_buy(
    market_id="0x...",
    outcome=Outcome.YES,
    price=500000,    # $0.50
    size=1000000,    # 1 share
)

print(f"Order hash: {signed.order_hash}")
print(f"Signature: {signed.signature}")

# client.post_order(signed)  # This would fail — no API credentials
```

{% endstep %}

{% step %}

### Full Access

What you need:

* `private_key` + `api_key_id` + `api_private_key` (Ed25519)

What you can do:

* Submit orders, cancel, get positions, gasless operations, and all authenticated endpoints.

Example:

```python
client = TurbineClient(
    host="https://api.turbinefi.com",
    chain_id=137,
    private_key="0xYourPrivateKey",
    api_key_id="your_api_key_id",
    api_private_key="your_ed25519_private_key_hex",
)

# Create, sign, and submit
signed = client.create_limit_buy(
    market_id="0x...",
    outcome=Outcome.YES,
    price=500000,
    size=1000000,
)
result = client.post_order(signed)
print(f"Submitted: {result}")

# Cancel, query positions, claim winnings, etc.
orders = client.get_orders(market_id="0x...")
positions = client.get_positions(market_id="0x...")
```

{% endstep %}
{% endstepper %}

## Getting API Credentials

API credentials are Ed25519 key pairs used to generate bearer tokens for authenticated endpoints. Register them by proving wallet ownership:

```python
credentials = TurbineClient.request_api_credentials(
    host="https://api.turbinefi.com",
    private_key="0xYourPrivateKey",
)

print(f"API Key ID:      {credentials['api_key_id']}")
print(f"API Private Key: {credentials['api_private_key']}")
```

This signs a message with your wallet (`"Register API key for Turbine: <address>"`) and sends it to `POST /api/v1/api-keys`. The server returns a new Ed25519 key pair. Save both values — the private key is not recoverable.

If your wallet already has a registered key, this raises `TurbineApiError` with status code `409`.

## Configuration

### Constructor Parameters

| Parameter         | Type    | Required | Description                                      |
| ----------------- | ------- | -------- | ------------------------------------------------ |
| `host`            | `str`   | Yes      | API base URL (e.g., `https://api.turbinefi.com`) |
| `chain_id`        | `int`   | Yes      | Blockchain chain ID                              |
| `private_key`     | `str`   | No       | Wallet private key for EIP-712 signing           |
| `api_key_id`      | `str`   | No       | Ed25519 API key ID for bearer tokens             |
| `api_private_key` | `str`   | No       | Ed25519 private key (hex) for bearer tokens      |
| `timeout`         | `float` | No       | HTTP timeout in seconds (default: `30.0`)        |

### Using Environment Variables

```python
import os
from dotenv import load_dotenv
from turbine_client import TurbineClient

load_dotenv()

client = TurbineClient(
    host=os.environ.get("TURBINE_HOST", "https://api.turbinefi.com"),
    chain_id=int(os.environ.get("CHAIN_ID", "137")),
    private_key=os.environ.get("TURBINE_PRIVATE_KEY"),
    api_key_id=os.environ.get("TURBINE_API_KEY_ID"),
    api_private_key=os.environ.get("TURBINE_API_PRIVATE_KEY"),
)
```

### Supported Chains

| Chain        | Chain ID | Settlement Address                           | USDC Address                                 |
| ------------ | -------- | -------------------------------------------- | -------------------------------------------- |
| Polygon      | `137`    | `0xdB96C91d9e5930fE3Ed1604603CfA4ece454725c` | `0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359` |
| Avalanche    | `43114`  | `0x893ca652525B1F9DC25189ED9c3AD0543ACfb989` | `0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E` |
| Base Sepolia | `84532`  | `0xF37B881F236033E55bF1cdAB628c7Cd88aAd89D4` | `0xf9065CCFF7025649F16D547DC341DAffF0C7F7f6` |

Chain configs are loaded automatically based on `chain_id`. Access them via:

```python
print(f"Settlement: {client._chain_config.settlement_address}")
print(f"CTF: {client._chain_config.ctf_address}")
print(f"USDC: {client._chain_config.usdc_address}")
```

### Client Properties

```python
client.host         # API base URL
client.chain_id     # Chain ID
client.address      # Wallet address (None if no signer)
client.can_sign     # True if private key is set
client.has_auth     # True if API credentials are set
```

### Context Manager

The client implements the context manager protocol for automatic resource cleanup:

```python
with TurbineClient(host="https://api.turbinefi.com", chain_id=137) as client:
    markets = client.get_markets()
# client.close() called automatically
```

## Price and Size Encoding

All prices and sizes use integer encoding with 6 decimal places:

| Concept | Raw Value  | Meaning                 |
| ------- | ---------- | ----------------------- |
| Price   | `500000`   | $0.50 (50% probability) |
| Price   | `1`        | $0.000001 (minimum)     |
| Price   | `999999`   | $0.999999 (maximum)     |
| Size    | `1000000`  | 1 share                 |
| Size    | `10000000` | 10 shares               |

Prices range from `1` to `999999` (exclusive of 0 and 1,000,000). A price of `500000` means $0.50 = 50% implied probability.

## Error Handling

```python
from turbine_client.exceptions import (
    TurbineError,          # Base exception
    TurbineApiError,       # HTTP API errors (has status_code)
    OrderValidationError,  # Invalid order parameters (has field)
    SignatureError,        # EIP-712 signing failures
    AuthenticationError,   # Missing credentials (has required_level)
    ConfigurationError,    # Invalid chain/config
    WebSocketError,        # WebSocket connection issues
)

try:
    result = client.post_order(signed_order)
except AuthenticationError as e:
    print(f"Auth failed (requires {e.required_level}): {e.message}")
except TurbineApiError as e:
    print(f"API error {e.status_code}: {e.message}")
except OrderValidationError as e:
    print(f"Invalid order ({e.field}): {e.message}")
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.ojolabs.xyz/markets/api/python-sdk/getting-started.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
