Skip to main content

Overview

Polymarket is a decentralized prediction market built on Polygon. It’s one of the largest prediction market platforms with deep liquidity and a wide variety of markets.
FeatureStatus
REST APIFull Support
WebSocketOrderbook Streaming
AuthenticationEthereum Wallet
ChainPolygon (Chain ID: 137)

Configuration

Basic Setup (Public Data Only)

use pc_exchange_polymarket::{Polymarket, PolymarketConfig};

let config = PolymarketConfig::new();
let exchange = Polymarket::new(config)?;

// Fetch public market data
let markets = exchange.fetch_markets(None).await?;

Authenticated Setup (Trading)

use pc_exchange_polymarket::{Polymarket, PolymarketConfig, PolymarketSignatureType};

let config = PolymarketConfig::new()
    .with_private_key("0x...")              // Your Ethereum private key
    .with_funder("0x...")                   // Your funder/proxy wallet address
    .with_signature_type(PolymarketSignatureType::Proxy);  // Wallet type

let exchange = Polymarket::new(config)?;

// Now you can trade
let order = exchange.create_order(...).await?;

Signature Types

Polymarket supports three wallet/signature types. You must set the correct type for your wallet:
TypeValueDescription
Eoa0Direct wallet (default). No funder address needed.
Proxy1Magic Link / email login wallet. Requires funder address.
GnosisSafe2MetaMask / browser wallet (Gnosis Safe). Requires funder address.
For Proxy and GnosisSafe types, if you omit the funder address, Parsecular will automatically derive it from your private key using the Polymarket SDK.

Auto-Authentication

When the API server starts, if a private key is configured but no API credentials are provided, Parsecular automatically derives CLOB API credentials via L1 authentication (EIP-712 signing). This means trading endpoints work immediately without a manual auth step. If you already have API credentials (e.g., from a prior session), you can provide them directly to skip the derivation:
let config = PolymarketConfig::new()
    .with_private_key("0x...")
    .with_signature_type(PolymarketSignatureType::Proxy)
    .with_funder("0x...")
    .with_api_credentials("api-key", "secret", "passphrase");

Full Configuration Options

use pc_exchange_polymarket::{Polymarket, PolymarketConfig, PolymarketSignatureType};

let config = PolymarketConfig::new()
    // Authentication
    .with_private_key("0x...")
    .with_funder("0x...")
    .with_signature_type(PolymarketSignatureType::Proxy)

    // Pre-existing API credentials (optional — auto-derived if omitted)
    .with_api_credentials("api-key", "secret", "passphrase")

    // API endpoints (optional - defaults to production)
    .with_gamma_url("https://gamma-api.polymarket.com")
    .with_clob_url("https://clob.polymarket.com")

    // Logging
    .with_verbose(true);

let exchange = Polymarket::new(config)?;

Configuration Reference

OptionTypeDefaultDescription
private_keyOption<String>NoneEthereum private key for signing
funderOption<String>NoneFunder wallet address (required for Proxy/GnosisSafe, auto-derived if omitted)
signature_typePolymarketSignatureTypeEoaWallet type: Eoa, Proxy, or GnosisSafe
api_keyOption<String>NonePre-existing CLOB API key
api_secretOption<String>NonePre-existing CLOB API secret
api_passphraseOption<String>NonePre-existing CLOB API passphrase
gamma_urlStringProduction URLGamma API endpoint
clob_urlStringProduction URLCLOB API endpoint
chain_idu64137Polygon chain ID
verboseboolfalseEnable debug logging

Environment Variables

Set these environment variables for authenticated access:
# Required for trading
export POLYMARKET_PRIVATE_KEY="0x..."

# Wallet type: eoa (default), proxy (Magic/email), gnosis (MetaMask/browser)
export POLYMARKET_SIGNATURE_TYPE="eoa"

# Funder address (required for proxy/gnosis, auto-derived if omitted)
export POLYMARKET_FUNDER="0x..."

# Pre-existing API credentials (optional — auto-derived from private key if omitted)
export POLYMARKET_API_KEY="..."
export POLYMARKET_API_SECRET="..."
export POLYMARKET_API_PASSPHRASE="..."
Then load from environment:
use std::env;
use pc_exchange_polymarket::PolymarketSignatureType;

let sig_type = env::var("POLYMARKET_SIGNATURE_TYPE").unwrap_or_default();

let mut config = PolymarketConfig::new()
    .with_private_key(env::var("POLYMARKET_PRIVATE_KEY")?)
    .with_signature_type(PolymarketSignatureType::from(sig_type.as_str()));

if let Ok(funder) = env::var("POLYMARKET_FUNDER") {
    config = config.with_funder(funder);
}

Examples

Fetch Markets

use pc_core::{Exchange, FetchMarketsParams};
use pc_exchange_polymarket::{Polymarket, PolymarketConfig};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let exchange = Polymarket::new(PolymarketConfig::new())?;

    // Fetch top 10 active markets
    let markets = exchange
        .fetch_markets(Some(FetchMarketsParams {
            limit: Some(10),
            active_only: true,
        }))
        .await?;

    for market in markets {
        println!("─────────────────────────────────");
        println!("ID: {}", market.id);
        println!("Question: {}", market.question);
        println!("Outcomes: {:?}", market.outcomes);

        // Get token IDs for trading
        let tokens = market.get_outcome_tokens();
        for token in tokens {
            println!("  {} -> {}", token.outcome, token.token_id);
        }
    }

    Ok(())
}

Fetch Market by Slug

Polymarket supports fetching markets by their URL slug:
// Fetch all markets related to a specific event
let markets = exchange
    .fetch_markets_by_slug("presidential-election-2024")
    .await?;

for market in markets {
    println!("{}: {}", market.id, market.question);
}

Place an Order

use pc_core::{Exchange, OrderSide};
use pc_exchange_polymarket::{Polymarket, PolymarketConfig};
use std::collections::HashMap;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let config = PolymarketConfig::new()
        .with_private_key("0x...")
        .with_funder("0x...");

    let exchange = Polymarket::new(config)?;

    // First, fetch the market to get token IDs
    let market = exchange.fetch_market("market-condition-id").await?;
    let tokens = market.get_outcome_tokens();

    // Get the token ID for "Yes"
    let yes_token = tokens.iter()
        .find(|t| t.outcome == "Yes")
        .expect("Yes outcome not found");

    // Create order parameters
    let mut params = HashMap::new();
    params.insert("token_id".to_string(), yes_token.token_id.clone());

    // Place a buy order for 100 shares at $0.65
    let order = exchange
        .create_order(
            &market.id,
            "Yes",
            OrderSide::Buy,
            0.65,    // price
            100.0,   // size
            params,
        )
        .await?;

    println!("Order placed!");
    println!("  ID: {}", order.id);
    println!("  Status: {:?}", order.status);
    println!("  Price: ${:.2}", order.price);
    println!("  Size: {}", order.size);

    Ok(())
}

Cancel an Order

let cancelled = exchange
    .cancel_order("order-id", Some("market-id"))
    .await?;

println!("Order cancelled: {:?}", cancelled.status);

Fetch Open Orders

use pc_core::FetchOrdersParams;

// Fetch all open orders
let orders = exchange.fetch_open_orders(None).await?;

// Or filter by market
let orders = exchange
    .fetch_open_orders(Some(FetchOrdersParams {
        market_id: Some("market-id".to_string()),
    }))
    .await?;

for order in orders {
    println!(
        "{}: {} {} @ ${:.2} ({:?})",
        order.id, order.side, order.size, order.price, order.status
    );
}

Fetch Positions

// Fetch all positions across all markets (uses Polymarket Data API)
let positions = exchange.fetch_positions(None).await?;

// Or fetch positions for a specific market (uses CLOB token balances)
let positions = exchange.fetch_positions(Some("market-id")).await?;

for pos in positions {
    println!("Market: {}", pos.market_id);
    println!("  Outcome: {}", pos.outcome);
    println!("  Size: {} shares", pos.size);
    println!("  Avg Price: ${:.4}", pos.average_price);
    println!("  Current: ${:.4}", pos.current_price);
    println!("  P&L: ${:.2} ({:.1}%)",
        pos.unrealized_pnl(),
        pos.unrealized_pnl_percent()
    );
}
When fetching all positions (no market_id), average entry prices and current prices are provided by the Polymarket Data API. When filtering by a specific market, only token balances are available from the CLOB API, so average_price will be 0.0.

Fetch Balance

let balance = exchange.fetch_balance().await?;

for (asset, amount) in balance {
    println!("{}: ${:.2}", asset, amount);
}

WebSocket Streaming

Polymarket supports real-time orderbook streaming via WebSocket:
use pc_core::OrderBookWebSocket;
use pc_exchange_polymarket::PolymarketWebSocket;
use futures::StreamExt;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let mut ws = PolymarketWebSocket::new();

    // Connect to WebSocket
    ws.connect().await?;
    println!("Connected!");

    // Subscribe to a token's orderbook
    let token_id = "21742633143463906290569050155826241533067272736897614950488156847949938836455";
    ws.subscribe(token_id).await?;
    println!("Subscribed to orderbook");

    // Stream orderbook updates
    let mut stream = ws.orderbook_stream(token_id).await?;

    while let Some(result) = stream.next().await {
        match result {
            Ok(orderbook) => {
                if let (Some(bid), Some(ask)) = (orderbook.best_bid(), orderbook.best_ask()) {
                    println!(
                        "Bid: {:.4} | Ask: {:.4} | Spread: {:.4}",
                        bid, ask, ask - bid
                    );
                }
            }
            Err(e) => eprintln!("Error: {}", e),
        }
    }

    ws.disconnect().await?;
    Ok(())
}
See WebSocket Overview for more details.

Token IDs

Polymarket uses CLOB token IDs for trading. Each outcome in a market has a unique token ID. You can get these from the market’s metadata:
let market = exchange.fetch_market("condition-id").await?;

// Method 1: Get all token IDs
let token_ids = market.get_token_ids();
// ["token-id-for-yes", "token-id-for-no"]

// Method 2: Get outcome-token pairs
let outcome_tokens = market.get_outcome_tokens();
for ot in outcome_tokens {
    println!("{} -> {}", ot.outcome, ot.token_id);
}
// Yes -> 21742633143463906290569050155826241533067272736897614950488156847949938836455
// No -> 48331043336612883890938759509493159234755048973500640148014422747788308965732

Tick Size

Polymarket uses a tick size of 0.01 (1 cent). All prices must be multiples of this value:
use pc_core::utils::round_to_tick_size;

let price = 0.653;
let tick_size = market.tick_size; // 0.01

let rounded = round_to_tick_size(price, tick_size)?;
// 0.65

Next Steps