Metadata-Version: 2.4
Name: dome-api-sdk
Version: 0.1.8
Summary: The Dome SDK - A comprehensive Python SDK for Dome API
Project-URL: Homepage, https://www.domeapi.io/
Project-URL: Documentation, https://docs.domeapi.io/
Author-email: Kurush Dubash <kurush@domeapi.com>, Kunal Roy <kunal@domeapi.com>
License: MIT License
        
        Copyright (c) 2025 Dome
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: api,client,dome,prediction markets,python,sdk
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: httpx>=0.24.0
Requires-Dist: typing-extensions>=4.5.0; python_version < '3.10'
Requires-Dist: websockets>=12.0
Provides-Extra: dev
Requires-Dist: black>=23.0; extra == 'dev'
Requires-Dist: build>=0.10; extra == 'dev'
Requires-Dist: flake8>=6.0; extra == 'dev'
Requires-Dist: isort>=5.12; extra == 'dev'
Requires-Dist: mypy>=1.0; extra == 'dev'
Requires-Dist: pre-commit>=3.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
Requires-Dist: pytest-httpx>=0.21.0; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: twine>=4.0; extra == 'dev'
Provides-Extra: docs
Requires-Dist: mkdocs-material>=9.0; extra == 'docs'
Requires-Dist: mkdocs>=1.4; extra == 'docs'
Requires-Dist: mkdocstrings[python]>=0.20; extra == 'docs'
Provides-Extra: test
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'test'
Requires-Dist: pytest-cov>=4.0; extra == 'test'
Requires-Dist: pytest-httpx>=0.21.0; extra == 'test'
Requires-Dist: pytest>=7.0; extra == 'test'
Description-Content-Type: text/markdown

# Dome Python SDK

[![PyPI version](https://badge.fury.io/py/dome-api-sdk.svg)](https://badge.fury.io/py/dome-api-sdk)
[![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![Type checked: mypy](https://img.shields.io/badge/type%20checked-mypy-blue.svg)](https://mypy.readthedocs.io/)

A comprehensive, type-safe, async-first Python SDK for [Dome API](https://www.domeapi.io/). Features include market data, wallet analytics, order tracking, and cross-platform market matching for prediction markets. For detailed API documentation, visit [DomeApi.io](https://www.domeapi.io/).

## Installation

```bash
# Using pip
pip install dome-api-sdk

# Using poetry  
poetry add dome-api-sdk

# Using pipenv
pipenv install dome-api-sdk
```

## Quick Start

```python
from dome_api_sdk import DomeClient

# Initialize the client with your API key
dome = DomeClient({"api_key": "your-dome-api-key-here"})

# Get market price
market_price = dome.polymarket.markets.get_market_price({
    "token_id": "98250445447699368679516529207365255018790721464590833209064266254238063117329"
})
print(f"Market Price: {market_price.price}")
```

## Configuration

The SDK accepts the following configuration options:

```python
from dome_api_sdk import DomeClient

config = {
    "api_key": "your-api-key",           # Authentication token (required)
    "base_url": "https://api.domeapi.io/v1",  # Base URL (optional)
    "timeout": 30.0,                     # Request timeout (optional)
}

client = DomeClient(config)
```

### Environment Variables

You can also configure the SDK using environment variables:

```bash
export DOME_API_KEY="your-api-key"
```

```python
from dome_api_sdk import DomeClient

# Will automatically use DOME_API_KEY from environment
client = DomeClient()
```

## Trading with Polymarket Router

The SDK includes a `PolymarketRouter` for integrating wallet providers (Privy, MetaMask, etc.) with Polymarket trading. This allows users to sign once to create API credentials, then trade without signing every order.

### Polymarket Router Endpoints

| Method | Description | Endpoint Path |
|--------|-------------|---------------|
| `router.link_user()` | Link a user to Polymarket by creating CLOB API credentials | Direct CLOB integration |
| `router.place_order()` | Place an order on Polymarket via Dome server | `/polymarket/placeOrder` |
| `router.check_allowances()` | Check if wallet has required token allowances | RPC call |

### Quick Start: Privy + Polymarket Trading

```python
from dome_api_sdk import (
    DomeClient,
    PolymarketRouter,
    create_privy_client,
    create_privy_signer,
)

# Initialize router with Privy config
router = PolymarketRouter({
    "api_key": "your-dome-api-key",
    "privy": {
        "app_id": "your-privy-app-id",
        "app_secret": "your-privy-app-secret",
        "authorization_key": "your-privy-auth-key",
    },
})

# Create signer for user's wallet
privy = create_privy_client({
    "app_id": "your-privy-app-id",
    "app_secret": "your-privy-app-secret",
    "authorization_key": "your-privy-auth-key",
})
signer = create_privy_signer(privy, privy_wallet_id, wallet_address)

# Step 1: Link user (one-time, creates API credentials)
credentials = await router.link_user({
    "user_id": "user-123",
    "signer": signer,
    "privy_wallet_id": privy_wallet_id,
    "auto_set_allowances": True,
})

# Step 2: Place orders (no signatures required after linking)
result = await router.place_order({
    "user_id": "user-123",
    "market_id": "104173557214744537570424345347209544585775842950109756851652855913015295701992",
    "side": "buy",
    "size": 10,
    "price": 0.65,
    "order_type": "GTC",  # 'GTC' | 'GTD' | 'FOK' | 'FAK'
    "signer": signer,
}, credentials)
```

**Order Types:**
- `GTC` (Good Till Cancel) - Stays on book until filled (default)
- `GTD` (Good Till Date) - Expires at specified time
- `FOK` (Fill Or Kill) - Fill completely immediately or cancel
- `FAK` (Fill And Kill) - Fill as much as possible, cancel rest

See the [examples/](./examples/) directory for complete integration examples.

## API Reference

### Complete API Endpoint List

The Dome SDK provides access to the following API endpoints, organized by platform:

#### Polymarket Endpoints

All Polymarket endpoints are accessed through `dome.polymarket.*`:

| Category | Method | Description | Endpoint Path |
|----------|--------|-------------|---------------|
| **Markets** | `markets.get_market_price()` | Get current or historical market price by token ID | `/polymarket/market-price/{token_id}` |
| **Markets** | `markets.get_candlesticks()` | Get historical candlestick data for a market | `/polymarket/candlesticks/{condition_id}` |
| **Markets** | `markets.get_markets()` | Get market data with filtering (slug, tags, status, etc.) | `/polymarket/markets` |
| **Markets** | `markets.get_orderbooks()` | Get historical orderbook snapshots for an asset | `/polymarket/orderbooks` |
| **Orders** | `orders.get_orders()` | Get order data with filtering (market, user, time range, etc.) | `/polymarket/orders` |
| **Trading** | `router.place_order()` | Place an order on Polymarket (requires PolymarketRouter) | `/polymarket/placeOrder` |
| **WebSocket** | `websocket.subscribe()` | Subscribe to real-time order events via WebSocket (supports users, condition_ids, market_slugs filters) | `wss://ws.domeapi.io/{api_key}` |
| **WebSocket** | `websocket.update()` | Update an existing subscription's filters | `wss://ws.domeapi.io/{api_key}` |
| **WebSocket** | `websocket.unsubscribe()` | Unsubscribe from order events | `wss://ws.domeapi.io/{api_key}` |
| **WebSocket** | `websocket.get_active_subscriptions()` | Get all active subscriptions | N/A |
| **Wallet** | `wallet.get_wallet_pnl()` | Get realized profit and loss (PnL) for a wallet | `/polymarket/wallet/pnl/{wallet_address}` |
| **Activity** | `activity.get_activity()` | Get trading activity (MERGE, SPLIT, REDEEM) for a user | `/polymarket/activity` |

#### Kalshi Endpoints

All Kalshi endpoints are accessed through `dome.kalshi.*`:

| Category | Method | Description | Endpoint Path |
|----------|--------|-------------|---------------|
| **Markets** | `markets.get_markets()` | Get Kalshi market data with filtering | `/kalshi/markets` |
| **Orderbooks** | `orderbooks.get_orderbooks()` | Get historical Kalshi orderbook snapshots | `/kalshi/orderbooks` |

#### Matching Markets Endpoints

Cross-platform market matching endpoints are accessed through `dome.matching_markets.*`:

| Method | Description | Endpoint Path |
|--------|-------------|---------------|
| `get_matching_markets()` | Find equivalent markets across platforms by Polymarket slug or Kalshi ticker | `/matching-markets/sports/` |
| `get_matching_markets_by_sport()` | Find equivalent markets by sport and date | `/matching-markets/sports/{sport}/` |

#### Crypto Prices Endpoints

Crypto price data endpoints are accessed through `dome.crypto_prices.*`:

| Method | Description | Endpoint Path |
|--------|-------------|---------------|
| **Binance** | `binance.get_binance_prices()` | Get historical crypto price data from Binance | `/crypto-prices/binance` |
| **Chainlink** | `chainlink.get_chainlink_prices()` | Get historical crypto price data from Chainlink | `/crypto-prices/chainlink` |

---

## API Endpoints

### Market Price

Get current or historical market prices:

```python
from dome_api_sdk import DomeClient

dome = DomeClient({"api_key": "your-api-key"})

# Current price
price = dome.polymarket.markets.get_market_price({
    "token_id": "1234567890"
})
print(f"Current Price: {price.price}")

# Historical price
historical_price = dome.polymarket.markets.get_market_price({
    "token_id": "1234567890",
    "at_time": 1740000000  # Unix timestamp
})
print(f"Historical Price: {historical_price.price}")
```

### Candlestick Data

Get historical candlestick data for market analysis:

```python
from dome_api_sdk import DomeClient

dome = DomeClient({"api_key": "your-api-key"})

candlesticks = dome.polymarket.markets.get_candlesticks({
    "condition_id": "0x4567b275e6b667a6217f5cb4f06a797d3a1eaf1d0281fb5bc8c75e2046ae7e57",
    "start_time": 1640995200,
    "end_time": 1672531200,
    "interval": 60  # 1 = 1m, 60 = 1h, 1440 = 1d
})
print(f"Candlesticks: {len(candlesticks.candlesticks)}")
```

### Markets

Get market data with filtering and search:

```python
from dome_api_sdk import DomeClient

dome = DomeClient({"api_key": "your-api-key"})

# Get markets by status
markets = dome.polymarket.markets.get_markets({
    "status": "open",
    "limit": 20,
    "min_volume": 100000
})
print(f"Markets: {len(markets.markets)}")

# Get markets by slug(s)
markets_filtered = dome.polymarket.markets.get_markets({
    "market_slug": ["bitcoin-up-or-down-july-25-8pm-et"],
    "limit": 10
})

# Get markets by tags
markets_by_tags = dome.polymarket.markets.get_markets({
    "tags": ["crypto", "politics"],
    "status": "open"
})
```

### Orderbooks

Get historical orderbook snapshots:

```python
from dome_api_sdk import DomeClient

dome = DomeClient({"api_key": "your-api-key"})

orderbooks = dome.polymarket.markets.get_orderbooks({
    "token_id": "18823838997443878656879952590502524526556504037944392973476854588563571859850",
    "start_time": 1760470000000,  # milliseconds
    "end_time": 1760480000000,    # milliseconds
    "limit": 100
})
print(f"Orderbook snapshots: {len(orderbooks.snapshots)}")
```

### Orders

Get order data with filtering:

```python
from dome_api_sdk import DomeClient

dome = DomeClient({"api_key": "your-api-key"})

# Get orders by market slug
orders = dome.polymarket.orders.get_orders({
    "market_slug": "bitcoin-up-or-down-july-25-8pm-et",
    "limit": 50,
    "offset": 0,
    "start_time": 1640995200,
    "end_time": 1672531200
})
print(f"Orders: {len(orders.orders)}")

# Get orders by user
user_orders = dome.polymarket.orders.get_orders({
    "user": "0x7c3db723f1d4d8cb9c550095203b686cb11e5c6b",
    "limit": 100
})

# Get orders with array filters
orders_array = dome.polymarket.orders.get_orders({
    "market_slug": ["slug1", "slug2"],
    "limit": 50
})
```

### WebSocket - Real-time Order Events

Subscribe to real-time Polymarket order data via WebSocket. The SDK automatically handles reconnection with exponential backoff and subscription management.

#### Basic Usage - Subscribe by Users

```python
import asyncio
from dome_api_sdk import DomeClient, WebSocketOrderEvent

async def main():
    dome = DomeClient({"api_key": "your-api-key"})
    ws_client = dome.polymarket.websocket

    # Define event handler
    def on_order_event(event: WebSocketOrderEvent):
        print(f"New order: {event.data.side} {event.data.shares_normalized} shares")
        print(f"Market: {event.data.market_slug}")
        print(f"User: {event.data.user}")
        print(f"Price: {event.data.price}")

    # Connect and subscribe
    await ws_client.connect()
    subscription_id = await ws_client.subscribe(
        users=["0x6031b6eed1c97e853c6e0f03ad3ce3529351f96d"],
        on_event=on_order_event
    )
    print(f"Subscribed with ID: {subscription_id}")

    # Keep running to receive events
    await asyncio.sleep(60)

    # Unsubscribe when done
    await ws_client.unsubscribe(subscription_id)
    await ws_client.disconnect()

asyncio.run(main())
```

#### Subscribe by Condition IDs

```python
import asyncio
from dome_api_sdk import DomeClient, WebSocketOrderEvent

async def main():
    dome = DomeClient({"api_key": "your-api-key"})
    ws_client = dome.polymarket.websocket

    def on_order_event(event: WebSocketOrderEvent):
        print(f"Order for condition: {event.data.condition_id}")

    await ws_client.connect()
    subscription_id = await ws_client.subscribe(
        condition_ids=["0x17815081230e3b9c78b098162c33b1ffa68c4ec29c123d3d14989599e0c2e113"],
        on_event=on_order_event
    )

    await asyncio.sleep(60)
    await ws_client.unsubscribe(subscription_id)
    await ws_client.disconnect()

asyncio.run(main())
```

#### Subscribe by Market Slugs

```python
import asyncio
from dome_api_sdk import DomeClient, WebSocketOrderEvent

async def main():
    dome = DomeClient({"api_key": "your-api-key"})
    ws_client = dome.polymarket.websocket

    def on_order_event(event: WebSocketOrderEvent):
        print(f"Order in market: {event.data.market_slug}")

    await ws_client.connect()
    subscription_id = await ws_client.subscribe(
        market_slugs=["btc-updown-15m-1762755300"],
        on_event=on_order_event
    )

    await asyncio.sleep(60)
    await ws_client.unsubscribe(subscription_id)
    await ws_client.disconnect()

asyncio.run(main())
```

#### Update Subscription

Update an existing subscription's filters without creating a new subscription:

```python
import asyncio
from dome_api_sdk import DomeClient, WebSocketOrderEvent

async def main():
    dome = DomeClient({"api_key": "your-api-key"})
    ws_client = dome.polymarket.websocket

    def on_order_event(event: WebSocketOrderEvent):
        print(f"Order: {event.data.user}")

    await ws_client.connect()
    
    # Initial subscription
    subscription_id = await ws_client.subscribe(
        users=["0x7c3db723f1d4d8cb9c550095203b686cb11e5c6b"],
        on_event=on_order_event
    )

    await asyncio.sleep(10)

    # Update to track different users (keeps same subscription_id)
    await ws_client.update(
        subscription_id=subscription_id,
        users=["0x6031b6eed1c97e853c6e0f03ad3ce3529351f96d"]
    )

    await asyncio.sleep(60)
    await ws_client.unsubscribe(subscription_id)
    await ws_client.disconnect()

asyncio.run(main())
```

#### Using Context Manager

```python
import asyncio
from dome_api_sdk import DomeClient, WebSocketOrderEvent

async def main():
    dome = DomeClient({"api_key": "your-api-key"})
    ws_client = dome.polymarket.websocket

    def on_order_event(event: WebSocketOrderEvent):
        print(f"Order event: {event.data}")

    # Context manager handles connection/disconnection
    async with ws_client:
        subscription_id = await ws_client.subscribe(
            users=["0x6031b6eed1c97e853c6e0f03ad3ce3529351f96d"],
            on_event=on_order_event
        )

        # Keep running
        await asyncio.sleep(60)

        # Unsubscribe before exiting context
        await ws_client.unsubscribe(subscription_id)

asyncio.run(main())
```

#### Multiple Subscriptions

```python
import asyncio
from dome_api_sdk import DomeClient, WebSocketOrderEvent

async def main():
    dome = DomeClient({"api_key": "your-api-key"})
    ws_client = dome.polymarket.websocket

    def on_order_event(event: WebSocketOrderEvent):
        print(f"Order from subscription {event.subscription_id}: {event.data.user}")

    await ws_client.connect()

    # Subscribe to multiple users
    sub1 = await ws_client.subscribe(
        users=["0x6031b6eed1c97e853c6e0f03ad3ce3529351f96d"],
        on_event=on_order_event
    )

    sub2 = await ws_client.subscribe(
        users=["0x7c3db723f1d4d8cb9c550095203b686cb11e5c6b"],
        on_event=on_order_event
    )

    # Subscribe by condition IDs
    sub3 = await ws_client.subscribe(
        condition_ids=["0x17815081230e3b9c78b098162c33b1ffa68c4ec29c123d3d14989599e0c2e113"],
        on_event=on_order_event
    )

    # Get all active subscriptions
    active = ws_client.get_active_subscriptions()
    print(f"Active subscriptions: {len(active)}")
    for sub in active:
        filters = sub.request['filters']
        filter_desc = []
        if filters.get('users'):
            filter_desc.append(f"users: {len(filters['users'])}")
        if filters.get('condition_ids'):
            filter_desc.append(f"condition_ids: {len(filters['condition_ids'])}")
        if filters.get('market_slugs'):
            filter_desc.append(f"market_slugs: {len(filters['market_slugs'])}")
        print(f"  - {sub.subscription_id}: {', '.join(filter_desc)}")

    await asyncio.sleep(60)

    # Unsubscribe from all
    for sub in active:
        await ws_client.unsubscribe(sub.subscription_id)

    await ws_client.disconnect()

asyncio.run(main())
```

#### Automatic Reconnection

The SDK automatically handles reconnection with exponential backoff (up to 10 retries) and re-subscribes to all active subscriptions:

```python
import asyncio
from dome_api_sdk import DomeClient, WebSocketOrderEvent

async def main():
    dome = DomeClient({"api_key": "your-api-key"})
    ws_client = dome.polymarket.websocket

    def on_order_event(event: WebSocketOrderEvent):
        print(f"Order: {event.data}")

    await ws_client.connect()
    subscription_id = await ws_client.subscribe(
        users=["0x6031b6eed1c97e853c6e0f03ad3ce3529351f96d"],
        on_event=on_order_event
    )

    # If connection drops, SDK will:
    # 1. Attempt to reconnect with exponential backoff (1s, 2s, 4s, 8s, ...)
    # 2. Automatically re-subscribe to all active subscriptions
    # 3. Continue receiving events seamlessly

    await asyncio.sleep(300)  # Run for 5 minutes

    await ws_client.unsubscribe(subscription_id)
    await ws_client.disconnect()

asyncio.run(main())
```

#### WebSocket Features

- **Multiple Filter Types**: Subscribe by users, condition_ids, or market_slugs
- **Update Subscriptions**: Change filters without unsubscribing
- **Automatic Reconnection**: Exponential backoff up to 10 retries
- **Subscription Management**: Track and manage all active subscriptions
- **Event Handling**: Callback-based event processing
- **Re-subscription**: Automatically re-subscribes on reconnection
- **Type Safety**: Full type hints for all WebSocket messages and events

### Wallet PnL

Get realized profit and loss for a wallet:

```python
from dome_api_sdk import DomeClient

dome = DomeClient({"api_key": "your-api-key"})

wallet_pnl = dome.polymarket.wallet.get_wallet_pnl({
    "wallet_address": "0x7c3db723f1d4d8cb9c550095203b686cb11e5c6b",
    "granularity": "day",
    "start_time": 1726857600,
    "end_time": 1758316829
})
print(f"PnL data points: {len(wallet_pnl.pnl_over_time)}")
```

### Activity

Get trading activity (MERGE, SPLIT, REDEEM) for a user:

```python
from dome_api_sdk import DomeClient

dome = DomeClient({"api_key": "your-api-key"})

activity = dome.polymarket.activity.get_activity({
    "user": "0x7c3db723f1d4d8cb9c550095203b686cb11e5c6b",
    "start_time": 1726857600,
    "end_time": 1758316829,
    "limit": 50
})
print(f"Activities: {len(activity.activities)}")
```

### Trading - Place Orders on Polymarket

Place orders on Polymarket using the PolymarketRouter. This requires one-time user linking and then allows gasless trading via API credentials.

```python
from dome_api_sdk import (
    PolymarketRouter,
    create_privy_client,
    create_privy_signer,
)

# Initialize router
router = PolymarketRouter({
    "api_key": "your-dome-api-key",
    "privy": {
        "app_id": "your-privy-app-id",
        "app_secret": "your-privy-app-secret",
        "authorization_key": "your-privy-auth-key",
    },
})

# Create Privy signer
privy = create_privy_client({
    "app_id": "your-privy-app-id",
    "app_secret": "your-privy-app-secret",
    "authorization_key": "your-privy-auth-key",
})
signer = create_privy_signer(privy, privy_wallet_id, wallet_address)

# Link user (one-time setup)
credentials = await router.link_user({
    "user_id": "user-123",
    "signer": signer,
    "privy_wallet_id": privy_wallet_id,
    "auto_set_allowances": True,  # Automatically set token approvals
    "sponsor_gas": False,  # Optional: Use Privy gas sponsorship
})

# Place a market order
result = await router.place_order({
    "user_id": "user-123",
    "market_id": "104173557214744537570424345347209544585775842950109756851652855913015295701992",
    "side": "buy",  # "buy" or "sell"
    "size": 10,  # Number of shares
    "price": 0.65,  # Price per share
    "order_type": "GTC",  # 'GTC', 'GTD', 'FOK', 'FAK'
    "signer": signer,
}, credentials)

print(f"Order placed! Order ID: {result.get('orderId')}")
print(f"Status: {result['status']}")

# Check allowances before trading
allowances = await router.check_allowances(wallet_address)
if not allowances.all_set:
    print("Token allowances need to be set")
```

**Router Features:**
- **Wallet Agnostic**: Works with Privy, MetaMask, or any EIP-712 signer
- **One-Time Linking**: User signs once to create Polymarket API credentials
- **Gasless Trading**: Orders placed via API keys, no gas required
- **Automatic Allowances**: Optionally auto-set token approvals during linking
- **Order Types**: Supports GTC, GTD, FOK, and FAK order types

See the [examples/](./examples/) directory for complete integration examples with Privy, including server-side signing.

### Kalshi Markets

Get Kalshi market data:

```python
from dome_api_sdk import DomeClient

dome = DomeClient({"api_key": "your-api-key"})

# Get Kalshi markets
kalshi_markets = dome.kalshi.markets.get_markets({
    "status": "open",
    "limit": 20,
    "min_volume": 10000000  # in cents
})
print(f"Kalshi markets: {len(kalshi_markets.markets)}")

# Get Kalshi markets by ticker(s)
kalshi_filtered = dome.kalshi.markets.get_markets({
    "market_ticker": ["KXNFLGAME-25AUG16ARIDEN-ARI"],
    "limit": 10
})
```

### Kalshi Orderbooks

Get historical Kalshi orderbook snapshots:

```python
from dome_api_sdk import DomeClient

dome = DomeClient({"api_key": "your-api-key"})

kalshi_orderbooks = dome.kalshi.orderbooks.get_orderbooks({
    "ticker": "KXNFLGAME-25AUG16ARIDEN-ARI",
    "start_time": 1760470000000,  # milliseconds
    "end_time": 1760480000000,    # milliseconds
    "limit": 100
})
print(f"Kalshi orderbook snapshots: {len(kalshi_orderbooks.snapshots)}")
```

### Matching Markets

Find equivalent markets across different platforms:

```python
from dome_api_sdk import DomeClient

dome = DomeClient({"api_key": "your-api-key"})

# By Polymarket market slugs
matching_markets = dome.matching_markets.get_matching_markets({
    "polymarket_market_slug": ["nfl-ari-den-2025-08-16"]
})
print(f"Matching Markets: {len(matching_markets.markets)}")

# By Kalshi event tickers
matching_markets_kalshi = dome.matching_markets.get_matching_markets({
    "kalshi_event_ticker": ["KXNFLGAME-25AUG16ARIDEN"]
})
print(f"Kalshi Markets: {len(matching_markets_kalshi.markets)}")

# By sport and date
matching_markets_by_sport = dome.matching_markets.get_matching_markets_by_sport({
    "sport": "nfl",
    "date": "2025-08-16"
})
print(f"Sport Markets: {len(matching_markets_by_sport.markets)}")
```

### Crypto Prices

Get historical crypto price data from Binance or Chainlink:

#### Binance Prices

```python
from dome_api_sdk import DomeClient

dome = DomeClient({"api_key": "your-api-key"})

# Get latest price (no time range)
binance_prices = dome.crypto_prices.binance.get_binance_prices({
    "currency": "btcusdt"  # Lowercase, no separators
})
print(f"Latest BTC/USDT price: {binance_prices.prices[0].value}")
print(f"Timestamp: {binance_prices.prices[0].timestamp}")

# Get historical prices with time range
binance_historical = dome.crypto_prices.binance.get_binance_prices({
    "currency": "btcusdt",
    "start_time": 1766130000000,  # milliseconds
    "end_time": 1766131000000,    # milliseconds
    "limit": 100
})
print(f"Historical prices: {binance_historical.total} data points")
for price in binance_historical.prices[:5]:  # Show first 5
    print(f"  {price.symbol}: {price.value} at {price.timestamp}")
```

#### Chainlink Prices

```python
from dome_api_sdk import DomeClient

dome = DomeClient({"api_key": "your-api-key"})

# Get latest price (no time range)
chainlink_prices = dome.crypto_prices.chainlink.get_chainlink_prices({
    "currency": "eth/usd"  # Slash-separated
})
print(f"Latest ETH/USD price: {chainlink_prices.prices[0].value}")
print(f"Timestamp: {chainlink_prices.prices[0].timestamp}")

# Get historical prices with time range
chainlink_historical = dome.crypto_prices.chainlink.get_chainlink_prices({
    "currency": "eth/usd",
    "start_time": 1766130000000,  # milliseconds
    "end_time": 1766131000000,    # milliseconds
    "limit": 100
})
print(f"Historical prices: {chainlink_historical.total} data points")
```

## Error Handling

The SDK provides comprehensive error handling:

```python
from dome_api_sdk import DomeClient

dome = DomeClient({"api_key": "your-api-key"})

try:
    result = dome.polymarket.markets.get_market_price({
        "token_id": "invalid-token"
    })
except ValueError as error:
    if "API Error" in str(error):
        print(f"API Error: {error}")
    else:
        print(f"Network Error: {error}")
```

## Integration Testing

The SDK includes a comprehensive integration test that makes live calls to the real API endpoints to verify everything works correctly.

```bash
# Using Makefile (recommended)
make integration-test API_KEY=your-api-key

# Or using Python directly
python tests/integration_test.py your-api-key

# Or set environment variable
export DOME_API_KEY=your-api-key
make integration-test
```

This smoke test covers all endpoints with various parameter combinations and provides detailed results.

## Development

### Setting up the Development Environment

1. Clone the repository:
```bash
git clone https://github.com/dome/dome-sdk-py.git
cd dome-sdk-py
```

2. Install development dependencies:
```bash
make dev-setup
```

3. Run tests:
```bash
make test
```

4. Run type checking:
```bash
make type-check
```

5. Run linting:
```bash
make lint
```

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## Authors

- **Kurush Dubash** - [kurush@domeapi.com](mailto:kurush@domeapi.com)
- **Kunal Roy** - [kunal@domeapi.com](mailto:kunal@domeapi.com)
