polybrainz_polymarket 1.2.0
polybrainz_polymarket: ^1.2.0 copied to clipboard
A comprehensive Dart wrapper for the Polymarket API including Gamma, CLOB, Data APIs and WebSocket streams.
polybrainz_polymarket #
A comprehensive Dart SDK for the Polymarket prediction market APIs.
Features #
- Gamma API - Market discovery, events, tags, comments, profiles, search, leaderboard
- CLOB API - Order book, pricing, order management, trade history
- Data API - Positions, trades, activity, holders, leaderboard
- WebSocket - Real-time order book updates, price changes, user notifications
- Authentication - L1 (EIP-712) and L2 (HMAC-SHA256) authentication support
- Type-safe - Full Dart type safety with JSON serialization
- Category Enums - Strongly-typed enums for all market categories and subcategories
- Category Detection - Automatic category detection from events, markets, and tags
- Type-Safe Enums - Enum getters on all models for
side,status,outcome,typefields - Legacy Maps -
toLegacyMap()on all models for simplified Map output - Error handling - Comprehensive exception hierarchy and Result types
Installation #
Add to your pubspec.yaml:
dependencies:
polybrainz_polymarket: ^1.2.0
Then run:
dart pub get
Quick Start #
Public Client (No Authentication) #
import 'package:polybrainz_polymarket/polybrainz_polymarket.dart';
void main() async {
// Create a public client
final client = PolymarketClient.public();
// Get active events
final events = await client.gamma.events.listEvents(
limit: 10,
closed: false,
);
for (final event in events) {
print('${event.title} - ${event.markets.length} markets');
}
// Get order book for a token
final book = await client.clob.orderbook.getOrderBook('your-token-id');
print('Best bid: ${book.bestBid}, Best ask: ${book.bestAsk}');
// Clean up
client.close();
}
Authenticated Client (For Trading) #
import 'package:polybrainz_polymarket/polybrainz_polymarket.dart';
void main() async {
// Create an authenticated client
final client = PolymarketClient.authenticated(
credentials: ApiCredentials(
apiKey: 'your-api-key',
secret: 'your-secret',
passphrase: 'your-passphrase',
),
funder: '0xYourWalletAddress',
);
// Get your open orders
final orders = await client.clob.orders.getOpenOrders();
print('You have ${orders.length} open orders');
// Get your positions
final positions = await client.data.positions.getPositions(
userAddress: '0xYourWalletAddress',
);
for (final pos in positions) {
print('${pos.title}: ${pos.size} shares @ ${pos.avgPrice}');
}
client.close();
}
Real-Time Data with WebSocket #
import 'package:polybrainz_polymarket/polybrainz_polymarket.dart';
void main() async {
final client = PolymarketClient.public();
// Connect to WebSocket
await client.clobWebSocket.connect();
// Subscribe to price changes
client.clobWebSocket.subscribeToPriceChanges(['token-id-1', 'token-id-2'])
.listen((msg) {
for (final change in msg.priceChanges) {
print('${change.assetId}: ${change.price}');
}
});
// Subscribe to order book updates
client.clobWebSocket.subscribeToOrderBook('token-id')
.listen((book) {
print('Best bid: ${book.bestBid}, Best ask: ${book.bestAsk}');
});
// For crypto prices
await client.rtdsWebSocket.connect(topics: [RtdsTopic.cryptoPrices]);
client.rtdsWebSocket.cryptoPrices.listen((msg) {
print('BTC: ${msg.getPrice('BTC')}, ETH: ${msg.getPrice('ETH')}');
});
}
API Reference #
PolymarketClient #
The main entry point for all API access.
| Factory | Description |
|---|---|
PolymarketClient.public() |
Public client, no authentication |
PolymarketClient.authenticated() |
Authenticated client with API credentials |
PolymarketClient.withPrivateKey() |
Client with private key for deriving credentials |
Gamma API (Market Discovery) #
// Events
final events = await client.gamma.events.listEvents(limit: 100, closed: false);
final event = await client.gamma.events.getById(123);
final event = await client.gamma.events.getBySlug('event-slug');
// Markets
final markets = await client.gamma.markets.listMarkets(active: true);
final market = await client.gamma.markets.getByConditionId('condition-id');
// Tags
final tags = await client.gamma.tags.listTags();
final related = await client.gamma.tags.getRelatedTags(tagId);
// Search
final results = await client.gamma.search.search(query: 'bitcoin');
// Profiles
final profile = await client.gamma.profiles.getByAddress('0x...');
// Comments
final comments = await client.gamma.comments.listComments(
parentEntityType: ParentEntityType.market,
parentEntityId: 123,
);
// Leaderboard
final leaders = await client.gamma.leaderboard.getTopByProfit(limit: 10);
// Convenience methods
final hotEvents = await client.gamma.events.getHotEvents();
final featuredEvents = await client.gamma.events.getFeaturedEvents();
final politicsEvents = await client.gamma.events.getByTagSlug('politics');
final endingSoon = await client.gamma.events.getEndingSoon(within: Duration(days: 3));
CLOB API (Order Book & Trading) #
// Order Book
final book = await client.clob.orderbook.getOrderBook('token-id');
final books = await client.clob.orderbook.getOrderBooks(['token-1', 'token-2']);
// Pricing
final price = await client.clob.pricing.getPrice('token-id', OrderSide.buy);
final midpoint = await client.clob.pricing.getMidpoint('token-id');
final spread = await client.clob.pricing.getSpread('token-id');
final history = await client.clob.pricing.getPriceHistory('token-id');
// Orders (requires authentication)
final response = await client.clob.orders.postOrder(signedOrder);
final orders = await client.clob.orders.getOpenOrders();
await client.clob.orders.cancelOrder('order-id');
await client.clob.orders.cancelAllOrders();
// Trades
final trades = await client.clob.trades.getTrades(market: 'condition-id');
Data API (Analytics) #
// Positions
final positions = await client.data.positions.getPositions(
userAddress: '0x...',
sortBy: SortBy.value,
sortDirection: SortDirection.desc,
);
final closed = await client.data.positions.getClosedPositions(userAddress: '0x...');
// Trades
final trades = await client.data.trades.getUserTrades(userAddress: '0x...');
final marketTrades = await client.data.trades.getMarketTrades(conditionId: 'cond-id');
// Activity
final activity = await client.data.activity.getUserActivity(
userAddress: '0x...',
types: [ActivityType.trade, ActivityType.redeem],
);
// Holders
final holders = await client.data.holders.getTokenHolders(tokenId: 'token-id');
// Portfolio Value
final value = await client.data.value.getValue('0x...');
print('Total: ${value.totalValue}, PnL: ${value.totalPnl}');
// Leaderboard
final leaders = await client.data.leaderboard.getLeaderboard(
window: LeaderboardWindow.day7,
type: LeaderboardType.profit,
);
WebSocket Streams #
// CLOB WebSocket
await client.clobWebSocket.connect();
// Market data (public)
client.clobWebSocket.subscribeToMarket(['token-id']);
client.clobWebSocket.bookUpdates.listen((book) => print(book));
client.clobWebSocket.priceChanges.listen((price) => print(price));
client.clobWebSocket.lastTradePrices.listen((trade) => print(trade));
// User data (requires auth)
client.clobWebSocket.subscribeToUser(['token-id']);
client.clobWebSocket.userOrders.listen((order) => print(order));
client.clobWebSocket.userTrades.listen((trade) => print(trade));
// RTDS WebSocket
await client.rtdsWebSocket.connect(topics: [RtdsTopic.cryptoPrices, RtdsTopic.comments]);
client.rtdsWebSocket.cryptoPrices.listen((msg) => print(msg));
client.rtdsWebSocket.comments.listen((comment) => print(comment));
Authentication #
Using Existing API Credentials #
If you already have API credentials:
final client = PolymarketClient.authenticated(
credentials: ApiCredentials(
apiKey: 'your-api-key',
secret: 'your-secret',
passphrase: 'your-passphrase',
),
funder: '0xYourWalletAddress',
);
Deriving API Credentials (Requires web3dart) #
To create or derive API credentials from a private key, you'll need to implement EIP-712 signing using a library like web3dart:
final client = PolymarketClient.withPrivateKey(
privateKey: '0xYourPrivateKey',
walletAddress: '0xYourWalletAddress',
);
// This requires proper EIP-712 implementation
// await client.clob.auth.createOrDeriveApiKey();
Note: L1 authentication (EIP-712 signing) is implemented as a placeholder. For production use, integrate with
web3dartor a similar Ethereum signing library.
Error Handling #
The SDK provides typed exceptions for different error scenarios:
try {
final orders = await client.clob.orders.getOpenOrders();
} on AuthenticationException catch (e) {
print('Auth error: ${e.message}');
} on RateLimitException catch (e) {
print('Rate limited, retry after: ${e.retryAfter}');
} on ApiException catch (e) {
print('API error ${e.statusCode}: ${e.message}');
} on NetworkException catch (e) {
print('Network error: ${e.message}');
} on PolymarketException catch (e) {
print('Error: ${e.message}');
}
Category Detection #
The SDK includes comprehensive category enums and automatic detection utilities.
Available Categories #
| Category | Subcategory Enum |
|---|---|
MarketCategory.politics |
PoliticsSubcategory |
MarketCategory.sports |
SportsSubcategory |
MarketCategory.crypto |
CryptoSubcategory |
MarketCategory.popCulture |
PopCultureSubcategory |
MarketCategory.business |
BusinessSubcategory |
MarketCategory.science |
ScienceSubcategory |
Detecting Categories #
import 'package:polybrainz_polymarket/polybrainz_polymarket.dart';
// Detect from a single event
final result = CategoryDetector.detectFromEvent(event);
print(result.category); // MarketCategory.politics
print(result.subcategories); // [PoliticsSubcategory.usPresidential]
print(result.tagSlugs); // ['politics', 'us-presidential', 'trump']
// Detect from markets list
final markets = await client.gamma.markets.listMarkets(limit: 100);
final categories = markets.detectCategories(); // Extension method
// Group by category
final grouped = markets.groupByCategory();
for (final entry in grouped.entries) {
print('${entry.key.label}: ${entry.value.length} markets');
}
// Get unique categories
final unique = markets.uniqueCategories; // Set<MarketCategory>
// Filter by category using tag slugs
final cryptoMarkets = await client.gamma.markets.getByTagSlug('crypto');
final politicsEvents = await client.gamma.events.getByTagSlug('politics');
Using Category Enums #
// Get all available categories
final categories = CategoryDetector.getAllCategories();
// Get subcategories for a category
final sportsSubcats = CategoryDetector.getSubcategoriesFor(MarketCategory.sports);
// Returns: [SportsSubcategory.nfl, SportsSubcategory.nba, ...]
// Use category slug for filtering
final events = await client.gamma.events.listEvents(
tagSlug: MarketCategory.crypto.slug, // 'crypto'
);
// Use subcategory slug
final nflEvents = await client.gamma.events.listEvents(
tagSlug: SportsSubcategory.nfl.slug, // 'nfl'
);
Type-Safe Enums #
All models with string fields representing fixed values now have type-safe enum getters.
Using Enum Getters #
// Order side and status
final order = await client.clob.orders.getOrder('order-id');
if (order.sideEnum == OrderSide.buy) {
print('This is a buy order');
}
if (order.statusEnum?.isActive ?? false) {
print('Order is still active');
}
// Trade status with helper methods
final trade = trades.first;
if (trade.statusEnum.isTerminal) {
print('Trade is complete');
}
// Outcome type
final position = positions.first;
if (position.outcomeEnum == OutcomeType.yes) {
print('Holding YES tokens');
print('Opposite: ${position.oppositeOutcomeEnum}'); // OutcomeType.no
}
// Game status for sports events
final event = await client.gamma.events.getById(123);
if (event.gameStatusEnum?.isLive ?? false) {
print('Game is currently in progress!');
}
// Market prices
final market = markets.first;
print('YES: ${market.yesPrice}, NO: ${market.noPrice}');
Available Enums #
| Enum | Values | Helper Methods |
|---|---|---|
OutcomeType |
yes, no |
opposite, isYes, isNo |
OrderSide |
buy, sell |
opposite |
OrderType |
gtc, gtd, fok, fak |
- |
OrderStatus |
live, matched, filled, cancelled, pending, delayed |
isActive, isTerminal, isCancellable |
TradeStatus |
mined, confirmed, retrying, failed |
isTerminal, isPending |
GameStatus |
scheduled, inProgress, halftime, ended, postponed, cancelled, suspended |
isLive, isFinished, isUpcoming, isInterrupted |
ActivityType |
trade, split, merge, redeem, deposit, withdraw |
- |
toLegacyMap() #
All models have a toLegacyMap() method that returns a simplified Map<String, dynamic>:
final market = markets.first;
final map = market.toLegacyMap();
// Returns a Map with parsed numeric values and simplified structure
print(map['yesPrice']); // double instead of String
print(map['volume']); // double instead of String
Key Concepts #
Token IDs vs Condition IDs #
- Condition ID: Identifies a market (e.g., "Will X happen?")
- Token ID: Identifies a specific outcome token (Yes or No)
- A market has ONE condition ID but TWO token IDs
Order Types #
| Type | Description |
|---|---|
| GTC | Good Till Cancelled - rests on book until filled or cancelled |
| GTD | Good Till Date - expires at specified timestamp |
| FOK | Fill or Kill - must fill completely immediately or cancel |
| FAK | Fill and Kill (IOC) - fill what you can, cancel rest |
Negative Risk #
Some markets support "negative risk" where Yes + No tokens can be merged/split for capital efficiency. Check the negRisk field on markets.
Examples #
See the example directory for complete examples:
- Basic Usage - Simple API calls
- WebSocket Streaming - Real-time data
- Trading - Order management
API Documentation #
License #
MIT License - see LICENSE for details.