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

pip install turbine-py-client

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

Quick Start

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.

Public (Read-Only)

What you need: host + chain_id

What you can do: Read markets, orderbooks, trades, prices

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")

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.

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

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.

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...")

Getting API Credentials

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

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

ParameterTypeRequiredDescription
hoststrYesAPI base URL (e.g., https://api.turbinefi.com)
chain_idintYesBlockchain chain ID
private_keystrNoWallet private key for EIP-712 signing
api_key_idstrNoEd25519 API key ID for bearer tokens
api_private_keystrNoEd25519 private key (hex) for bearer tokens
timeoutfloatNoHTTP timeout in seconds (default: 30.0)

Using Environment Variables

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

ChainIDSettlementUSDC
Polygon1370xdB96C91d9e5930fE3Ed1604603CfA4ece454725c0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359
Avalanche431140x893ca652525B1F9DC25189ED9c3AD0543ACfb9890xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E
Base Sepolia845320xF37B881F236033E55bF1cdAB628c7Cd88aAd89D40xf9065CCFF7025649F16D547DC341DAffF0C7F7f6

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

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

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:

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:

TypeValueMeaning
Price500000$0.50 (50% probability)
Price1$0.000001 (minimum)
Price999999$0.999999 (maximum)
Size10000001 share
Size1000000010 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

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}")