Getting Started
Follow these steps to install the Openfish Rust SDK, pull live market information, and execute your first order.
Step 1: Fetch a Market
Section titled “Step 1: Fetch a Market”Market data endpoints are public — no authentication needed. Query the gamma server to browse available markets and grab token IDs.
curl "https://gamma.openfish.fun/markets?active=true&closed=false&limit=1"use openfish_client_sdk::gamma::Client;use openfish_client_sdk::gamma::types::request::MarketsRequest;
let client = Client::default();
let request = MarketsRequest::builder() .closed(false) .limit(1) .build();let markets = client.markets(&request).await?;
let market = &markets[0];println!("Question: {:?}", market.question);println!("Token IDs: {:?}", market.clob_token_ids);// Some(["abc123...", "def456..."]) -- [Yes token ID, No token ID]Hold on to a token ID from clob_token_ids. The first entry corresponds to the Yes outcome, the second to No.
Every market also carries a condition_id — this is the primary identifier that ties the market together across all services.
Step 2: Install the Rust SDK
Section titled “Step 2: Install the Rust SDK”Pull in the Openfish client as a dependency:
cargo add openfish-client-sdkAlternatively, declare it in Cargo.toml directly:
[dependencies]openfish-client-sdk = { version = "0.4", features = ["clob", "gamma"] }The SDK is split into feature-gated modules, each mapping to an Openfish backend service:
| Feature | Module | Description |
|---|---|---|
clob | openfish_client_sdk::clob | Trading, orders, and order book data |
gamma | openfish_client_sdk::gamma | Market metadata and events |
data | openfish_client_sdk::data | Analytics and positions |
bridge | openfish_client_sdk::bridge | Cross-chain deposits and withdrawals |
ctf | openfish_client_sdk::ctf | Conditional token operations (split/merge/redeem) |
ws | openfish_client_sdk::ws | WebSocket streams for real-time data |
Step 3: Set Up Your Client
Section titled “Step 3: Set Up Your Client”Generate API credentials and initialize the trading client. Openfish relies on a two-tier authentication scheme:
- L1 auth: A wallet signature proves you own the private key
- L2 auth: The server issues an API key and secret; all subsequent requests carry HMAC signatures derived from these credentials
use std::str::FromStr;use openfish_client_sdk::POLYGON;use openfish_client_sdk::auth::{LocalSigner, Signer};use openfish_client_sdk::clob::{Client, Config};
let private_key = std::env::var("OPENFISH_PRIVATE_KEY")?;let signer = LocalSigner::from_str(&private_key)? .with_chain_id(Some(POLYGON));
// Derive API credentials and initialize the trading client// The SDK handles L1 signing and L2 key derivation automatically// Signature type defaults to EOA (type 0)let client = Client::new("https://api.openfish.fun", Config::default())? .authentication_builder(&signer) .authenticate() .await?;Authentication Notes
Section titled “Authentication Notes”- EOA (type 0): Your wallet signs orders directly and pays its own gas in POL
- OPENFISH_PROXY (type 1): Orders are signed through your proxy wallet; gas is relayed by Openfish
- GNOSIS_SAFE (type 2): Orders are signed through your Gnosis Safe multisig
Your funder address must hold USDC.e (to purchase outcome tokens) and POL (for gas when using EOA type 0). Proxy and Safe wallet users can take advantage of Openfish’s gasless relayer instead.
Step 4: Place an Order
Section titled “Step 4: Place an Order”With the token_id from Step 1, submit a limit order:
use openfish_client_sdk::clob::types::Side;use openfish_client_sdk::types::dec;
// Parse the token ID from Step 1let token_id = "YOUR_TOKEN_ID".parse()?;
// The SDK auto-fetches tick size, neg risk flag, and fee rate// No manual lookup required -- the order builder handles itlet order = client .limit_order() .token_id(token_id) .price(dec!(0.50)) // Buy Yes at $0.50 (50% implied probability) .size(dec!(10)) // 10 shares .side(Side::Buy) .build() .await?;
// Sign and submitlet signed_order = client.sign(&signer, order).await?;let response = client.post_order(signed_order).await?;
println!("Order ID: {}", response.order_id);println!("Status: {:?}", response.status);What Happens Next
Section titled “What Happens Next”Once submitted, your order enters the matching engine:
- Immediately marketable (your buy price >= the lowest ask): the order fills against resting orders right away
- Not yet marketable: the order sits on the book as a GTC order, waiting to be matched or cancelled
- On match: the resulting trade is sent to the Exchange contract on Polygon for on-chain settlement
Order Types
Section titled “Order Types”Different order behaviors can be specified at build time:
// Good Till Date -- expires at a specific Unix timestamplet order = client .limit_order() .token_id(token_id) .price(dec!(0.45)) .size(dec!(20)) .side(Side::Buy) .order_type("GTD") .expiration(1735689600) // Unix timestamp .build() .await?;
// Fill Or Kill -- must fill entirely or is cancelledlet order = client .limit_order() .token_id(token_id) .price(dec!(0.50)) .size(dec!(10)) .side(Side::Buy) .order_type("FOK") .build() .await?;Step 5: Check Your Order
Section titled “Step 5: Check Your Order”Poll the CLOB server for the current status of an order:
let order_info = client.get_order("YOUR_ORDER_ID").await?;println!("Status: {:?}", order_info.status);println!("Size matched: {:?}", order_info.size_matched);Or retrieve all your open orders at once:
let open_orders = client.list_orders().await?;for order in &open_orders { println!("{}: {} @ {} -- {:?}", order.id, order.side, order.price, order.status);}Step 6: Cancel an Order
Section titled “Step 6: Cancel an Order”Remove a single order or clear everything:
// Cancel a single orderclient.cancel_order("YOUR_ORDER_ID").await?;
// Cancel all open ordersclient.cancel_all().await?;
// Cancel all orders for a specific marketclient.cancel_market_orders("CONDITION_ID").await?;Key API Endpoints
Section titled “Key API Endpoints”The CLOB server (port 3002) exposes these commonly used endpoints:
| Endpoint | Method | Auth | Description |
|---|---|---|---|
/markets | GET | No | List active markets |
/markets/{condition_id} | GET | No | Get a specific market |
/book | GET | No | Order book depth for a token |
/price | GET | No | Current price for a token |
/midpoint | GET | No | Midpoint price |
/spread | GET | No | Bid-ask spread |
/order | POST | Yes | Submit a new order |
/order | DELETE | Yes | Cancel an order |
/cancel-all | DELETE | Yes | Cancel all open orders |
/data/orders | GET | Yes | List your orders |
/data/trades | GET | Yes | List your trades |
/auth/derive-api-key | GET | L1 | Derive API credentials |
WebSocket Streams
Section titled “WebSocket Streams”For live data, connect to the WebSocket endpoints:
| Endpoint | Description |
|---|---|
/ws/market | Market-level events: trades, order book updates, resolutions |
/ws/user | User-specific events: order fills, cancellations, balance changes |
Next Steps
Section titled “Next Steps”- Markets & Events — How markets are organized and identified
- Order Lifecycle — The complete order flow from creation through settlement
- Prices & Orderbook — Mechanics of the in-memory order book
- Positions & Tokens — ERC1155 tokens, split/merge/redeem
- Resolution — Agent-submitted resolutions, 24h cooldown, and dispute mechanics