A comprehensive Go SDK for the Polymarket CLOB (Central Limit Order Book) API, fully implementing all core features from py-clob-client.
Follow at X: @netu5er
- β Complete API Coverage: All endpoints from py-clob-client
- β Three Authentication Levels: L0 (read-only), L1 (private key), L2 (full access)
- β Order Management: Create, submit, cancel, and query orders
- β Market Data: Order books, prices, spreads, and market information
- β RFQ Support: Request for Quote functionality
- β Type Safety: Strong typing with Go's type system
- β EIP-712 Signing: Full support for Ethereum message signing
go get github.com/0xNetuser/Polymarket-golangpackage main
import (
"fmt"
"github.com/0xNetuser/Polymarket-golang/polymarket"
)
func main() {
// Create read-only client
client, err := polymarket.NewClobClient(
"https://clob.polymarket.com",
137, // Polygon chain ID
"", // No private key
nil, // No API credentials
nil, // No signature type
"", // No funder address
)
if err != nil {
panic(err)
}
// Health check
ok, err := client.GetOK()
fmt.Println("Server OK:", ok)
// Get order book
orderBook, err := client.GetOrderBook("token-id")
if err != nil {
panic(err)
}
fmt.Printf("OrderBook: %+v\n", orderBook)
}client, err := polymarket.NewClobClient(
"https://clob.polymarket.com",
137,
"your-private-key-hex",
nil,
nil,
"",
)
// Create or derive API credentials
creds, err := client.CreateOrDeriveAPIKey(nil)
if err != nil {
panic(err)
}
fmt.Printf("API Key: %s\n", creds.APIKey)creds := &polymarket.ApiCreds{
APIKey: "your-api-key",
APISecret: "your-api-secret",
APIPassphrase: "your-passphrase",
}
client, err := polymarket.NewClobClient(
"https://clob.polymarket.com",
137,
"your-private-key-hex",
creds,
nil,
"",
)
// Query balance
balance, err := client.GetBalanceAllowance(&polymarket.BalanceAllowanceParams{
AssetType: polymarket.AssetTypeCollateral,
})
if err != nil {
panic(err)
}
fmt.Printf("Balance: %+v\n", balance)cd examples/check_balance
export PRIVATE_KEY="your-private-key"
export CHAIN_ID="137" # Optional, defaults to 137 (Polygon)
export SIGNATURE_TYPE="0" # Optional, 0=EOA, 1=Magic/Email, 2=Browser
export FUNDER="" # Optional, for proxy wallets
go run main.go// Create order
orderArgs := &polymarket.OrderArgs{
TokenID: "token-id",
Price: 0.5,
Size: 100.0,
Side: "BUY",
FeeRateBps: 0,
Nonce: 1,
Expiration: 1234567890,
}
order, err := client.CreateOrder(orderArgs, nil)
if err != nil {
panic(err)
}
// Post order
result, err := client.PostOrder(order, polymarket.OrderTypeGTC)
if err != nil {
panic(err)
}
fmt.Printf("Order posted: %+v\n", result)By default, CreateOrder fetches the market's tick_size, neg_risk, and fee_rate from the server. If you want to skip these API calls and provide these values yourself, use the RawOrder option:
orderArgs := &polymarket.OrderArgs{
TokenID: "token-id",
Price: 0.56,
Size: 100.0,
Side: "BUY",
Expiration: 0,
}
// Use RawOrder mode to skip server requests
// Must provide TickSize and NegRisk
tickSize := polymarket.TickSize("0.01")
negRisk := false
options := &polymarket.PartialCreateOrderOptions{
RawOrder: true, // Skip server requests for tick_size/neg_risk/fee_rate
TickSize: &tickSize, // Required in RawOrder mode
NegRisk: &negRisk, // Required in RawOrder mode
}
order, err := client.CreateOrder(orderArgs, options)
// or
result, err := client.CreateAndPostOrder(orderArgs, options)Note: In RawOrder mode, TickSize and NegRisk are required. The library still uses TickSize to convert price/size to the correct amounts.
CreateAndPostOrder supports different order types via the OrderType option:
// FAK order (Fill And Kill) - partial fill, cancel remaining
orderType := polymarket.OrderTypeFAK
options := &polymarket.PartialCreateOrderOptions{
OrderType: &orderType,
}
result, err := client.CreateAndPostOrder(orderArgs, options)
// FOK order (Fill Or Kill) - full fill or cancel
orderType := polymarket.OrderTypeFOK
options := &polymarket.PartialCreateOrderOptions{
OrderType: &orderType,
}
result, err := client.CreateAndPostOrder(orderArgs, options)| Order Type | Description |
|---|---|
GTC |
Good Till Cancel - remains until cancelled (default) |
FOK |
Fill Or Kill - full fill or cancel entirely |
FAK |
Fill And Kill - partial fill, cancel remaining |
GTD |
Good Till Date - expires at specified time (requires Expiration) |
Post Only orders are only accepted if they add liquidity to the order book (become a maker order). If a Post Only order would immediately match and become a taker, it will be rejected.
// Use PostOrderWithOptions for Post Only orders
result, err := client.PostOrderWithOptions(signedOrder, polymarket.OrderTypeGTC, true) // postOnly=true
// Or use PostOrders with PostOnly field
args := []polymarket.PostOrdersArgs{
{Order: signedOrder1, OrderType: polymarket.OrderTypeGTC, PostOnly: true},
{Order: signedOrder2, OrderType: polymarket.OrderTypeGTD, PostOnly: true},
}
result, err := client.PostOrders(args)Note: Post Only is only valid for GTC and GTD order types.
The Heartbeat API allows you to automatically cancel all orders if your connection is lost. Once started, you must send a heartbeat every 10 seconds or all orders will be cancelled.
// Start heartbeat with an optional ID
heartbeatID := "my-session-123"
result, err := client.PostHeartbeat(&heartbeatID)
// Or send without ID
result, err := client.PostHeartbeat(nil)Use Case: Prevent stale orders when your trading system goes offline unexpectedly.
The SDK includes two Web3 clients for on-chain operations:
import "github.com/0xNetuser/Polymarket-golang/polymarket/web3"
// Create Web3 client (pays gas for transactions)
client, err := web3.NewPolymarketWeb3Client(
"your-private-key",
web3.SignatureTypePolyProxy, // 0=EOA, 1=PolyProxy, 2=Safe
137, // Chain ID
"", // RPC URL (empty = default)
)
// Get balances
polBalance, _ := client.GetPOLBalance()
usdcBalance, _ := client.GetUSDCBalance(common.Address{})
tokenBalance, _ := client.GetTokenBalance("token-id", common.Address{})
// Set all necessary approvals
receipts, _ := client.SetAllApprovals()
// Split USDC into positions
receipt, _ := client.SplitPosition(conditionID, 100.0, true) // negRisk=true
// Merge positions back to USDC
receipt, _ := client.MergePosition(conditionID, 100.0, true)
// Transfer USDC
receipt, _ := client.TransferUSDC(recipient, 50.0)
// Transfer conditional tokens
receipt, _ := client.TransferToken("token-id", recipient, 50.0)// Create Gasless Web3 client (transactions via relay, no gas required)
// Only supports signature_type=1 (PolyProxy) or signature_type=2 (Safe)
client, err := web3.NewPolymarketGaslessWeb3Client(
"your-private-key",
web3.SignatureTypePolyProxy,
nil, // Optional: builder credentials
137,
"",
)
// Same operations as PolymarketWeb3Client
receipt, _ := client.SplitPosition(conditionID, 100.0, true)
receipt, _ := client.MergePosition(conditionID, 100.0, true)polymarket/
βββ client.go # Main client structure
βββ client_api.go # API methods (health check, API keys, market data)
βββ client_orders.go # Order management methods (submit, cancel, query)
βββ client_order_creation.go # Order creation methods (CreateOrder, CreateMarketOrder)
βββ client_misc.go # Other features (readonly API keys, order scoring, market queries)
βββ rfq_client.go # RFQ client convenience methods
βββ config.go # Contract configuration
βββ constants.go # Constants
βββ endpoints.go # API endpoint constants
βββ http_client.go # HTTP client
βββ http_helpers.go # HTTP helper functions (query parameter building)
βββ signer.go # Signer
βββ signing_internal.go # Signing implementation (EIP-712, HMAC)
βββ types.go # Type definitions
βββ utilities.go # Utility functions
βββ order_summary_wrapper.go # OrderSummary wrapper
βββ headers/ # Authentication headers (wrapper functions)
β βββ headers.go
βββ order_builder/ # Order builder
β βββ order_builder.go # Order builder implementation
β βββ helpers.go # Order builder helper functions
βββ rfq/ # RFQ client
β βββ rfq_client.go # RFQ client implementation
β βββ types.go # RFQ type definitions
βββ web3/ # Web3 clients for on-chain operations
βββ base_client.go # Base Web3 client (shared logic)
βββ web3_client.go # PolymarketWeb3Client (pay gas)
βββ gasless_client.go # PolymarketGaslessWeb3Client (no gas)
βββ types.go # Web3 type definitions
βββ helpers.go # Web3 helper functions
βββ abi_loader.go # ABI loading utilities
βββ abis/ # Contract ABI files
- Basic type definitions (all py-clob-client types)
- Signer - EIP-712 and HMAC signing
- L0/L1/L2 authentication header generation
- HTTP client wrapper
- Client base structure (supports three modes)
- Health Check:
GetOK(),GetServerTime() - API Key Management:
CreateAPIKey(),DeriveAPIKey(),CreateOrDeriveAPIKey(),GetAPIKeys(),DeleteAPIKey() - Market Data:
GetMidpoint(),GetMidpoints(),GetPrice(),GetPrices(),GetSpread(),GetSpreads() - Order Book:
GetOrderBook(),GetOrderBooks(),GetOrderBookHash() - Market Info:
GetTickSize(),GetNegRisk(),GetFeeRateBps()(with caching) - Last Trade Price:
GetLastTradePrice(),GetLastTradesPrices()
- Order Submission:
PostOrder(),PostOrders(),PostOrderWithOptions()(with PostOnly support) - Order Cancellation:
Cancel(),CancelOrders(),CancelAll(),CancelMarketOrders() - Order Query:
GetOrders(),GetOrder() - Trade Query:
GetTrades() - Balance Query:
GetBalanceAllowance() - Notification Management:
GetNotifications(),DropNotifications() - Heartbeat:
PostHeartbeat()- Keep orders alive (auto-cancel after 10s without heartbeat)
- Complete order builder implementation (using go-order-utils)
- Order creation methods:
CreateOrder(),CreateMarketOrder(),CreateAndPostOrder() - Market price calculation:
CalculateMarketPrice() - Rounding configuration and amount calculation
-
CreateReadonlyAPIKey()- Create readonly API key -
GetReadonlyAPIKeys()- Get readonly API key list -
DeleteReadonlyAPIKey()- Delete readonly API key -
ValidateReadonlyAPIKey()- Validate readonly API key
-
CreateRfqRequest()- Create RFQ request -
CancelRfqRequest()- Cancel RFQ request -
GetRfqRequests()- Get RFQ request list -
CreateRfqQuote()- Create RFQ quote -
CancelRfqQuote()- Cancel RFQ quote -
GetRfqRequesterQuotes()- Get quotes on your requests (requester view) -
GetRfqQuoterQuotes()- Get quotes you created (quoter view) -
GetRfqBestQuote()- Get best RFQ quote -
AcceptQuote()- Accept quote (requester side) -
ApproveOrder()- Approve order (quoter side) -
GetRfqConfig()- Get RFQ configuration
-
PolymarketWeb3Client- On-chain transactions (pays gas)- Supports EOA, PolyProxy, and Safe wallets
- Balance queries (POL, USDC, conditional tokens)
- Approval management (
SetAllApprovals()) - Position operations (
SplitPosition(),MergePosition(),RedeemPosition(),RedeemPositions(),ConvertPositions()) - Token transfers (
TransferUSDC(),TransferToken())
-
PolymarketGaslessWeb3Client- Gasless transactions via relay- Supports PolyProxy and Safe wallets
- Same operations as Web3Client without gas fees
- Requires Builder credentials (obtained from Polymarket)
- Dynamic Relay Address: Automatically fetches the current relay node address from
/relay-payloadendpoint - Batch Redeem:
RedeemPositions()- Redeem multiple conditionIds in a single transaction
- Order scoring:
IsOrderScoring(),AreOrdersScoring() - Market queries:
GetMarkets(),GetSimplifiedMarkets(),GetSamplingMarkets(),GetSamplingSimplifiedMarkets() - Market details:
GetMarket(),GetMarketTradesEvents() - Balance update:
UpdateBalanceAllowance() - Order book hash:
GetOrderBookHash() - Builder trades:
GetBuilderTrades()
| Feature | py-clob-client | Go SDK | Status |
|---|---|---|---|
| Basic client | β | β | Complete |
| L0/L1/L2 auth | β | β | Complete |
| API key management | β | β | Complete |
| Market data queries | β | β | Complete |
| Order book queries | β | β | Complete |
| Order submit/cancel | β | β | Complete |
| Order queries | β | β | Complete |
| Trade queries | β | β | Complete |
| Balance queries | β | β | Complete |
| Order builder | β | β | Fully implemented |
| RFQ features | β | β | Fully implemented |
| Readonly API keys | β | β | Fully implemented |
The example programs use the following environment variables:
PRIVATE_KEY(required): Your Ethereum private key in hex formatCHAIN_ID(optional): Chain ID (default: 137 for Polygon)SIGNATURE_TYPE(optional): Signature type (0=EOA, 1=Magic/Email, 2=Browser, default: 0)FUNDER(optional): Funder address for proxy walletsCLOB_HOST(optional): CLOB API host (default: https://clob.polymarket.com)CLOB_API_KEY(optional): API key for L2 authenticationCLOB_SECRET(optional): API secret for L2 authenticationCLOB_PASSPHRASE(optional): API passphrase for L2 authenticationTOKEN_ID(optional): Token ID for conditional token balance queries
- Fixed Polygon Bor v2.6.0
eth_callCompatibility - Use raweth_callRPC withblockOverrides(baseFeePerGas: 0) to bypass baseFee validation- Bor v2.6.0 (announcement) synced upstream go-ethereum's
eth_callvalidation logic; nodes now reject calls wheremaxFeePerGasis lower thanbaseFee - The Bor node's
setDefaultsinjects conflicting gas fields, making it impossible to fix viaCallMsggas parameters alone (settingGasFeeCap/GasTipCapcauses "both gasPrice and maxFeePerGas specified"; settingGasPriceis ignored) - Fix: replace all
ethclient.CallContractwith rawrpc.Client.CallContexteth_call, using the 4th parameterblockOverrides: {"baseFeePerGas": "0x0"}to set block context's baseFee to 0 before gas validation - For
estimateGas, gas fields are removed; all call sites have fallback gas limits - This only affects read-only contract calls; real transaction gas price remains unchanged
- Affects all Polygon RPC providers, not provider-specific
- Bor v2.6.0 (announcement) synced upstream go-ethereum's
- Fixed RPC 429 Rate Limit Error -
waitForReceiptnow includes proper polling interval and timeout- Added 4-second polling interval between RPC calls
- Added 5-minute timeout to prevent infinite waiting
- Applies to both
PolymarketWeb3ClientandPolymarketGaslessWeb3Client
- Unified Batch Redeem - Single transaction redemption for multiple conditionIds in both Gas and Gasless clients
- Updated
RedeemPositions(requests []RedeemRequest)to support single-transaction batching forPolyProxyon-chain (previously only serial) - Synced API between
PolymarketWeb3ClientandPolymarketGaslessWeb3Client - Added
ExecuteBatchfor generic multi-call execution on-chain - Added auto-discovery example in
examples/gasless_batch_redeem - Dramatically reduces Gas costs and transaction time for large portfolios
- Updated
- Gasless Web3 Client - Fixed Invalid Signature Error
- Fixed
SignatureParams.relayto use the dynamic relay address from/relay-payloadendpoint - Previously, the signature used a dynamic relay address while
SignatureParams.relayused a static configured address, causing signature validation failures - Reverted incorrect
to = ProxyFactoryAddresschange that was breakingProxyCall.Totarget address - Now both signature generation and request parameters use consistent dynamic relay address
- Fixed
- Gasless Web3 Client - Dynamic Relay Address
- Added
getRelayPayload()method to fetch dynamic relay node address from/relay-payloadendpoint - Polymarket's relay service may dynamically assign different relay nodes; the code now fetches the current relay address in real-time
- Added
- py-clob-client - Official Python implementation
- Polymarket CLOB Documentation
- go-order-utils - Order building utility library
This project is licensed under the MIT License.
Contributions are welcome! Please feel free to submit a Pull Request.