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-clientRequires 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 credentialsFull 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
| 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
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 | ID | Settlement | USDC |
|---|---|---|---|
| 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:
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 setContext 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 automaticallyPrice and Size Encoding
All prices and sizes use integer encoding with 6 decimal places:
| Type | 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
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}")