Official docs alignment: Implements Polymarket Order Attribution (builder auth headers for leaderboard/grants) and follows the Builder Authentication/Remote Signing guidance referenced by the Relayer Client docs; official docs: Order Attribution, Relayer Client.
An unofficial, production-ready, and feature-complete Go SDK for the Polymarket CLOB (Central Limit Order Book). Designed for high-frequency trading, market making, and data analysis.
Note: This is a community-maintained project and is not officially affiliated with Polymarket. We aim to provide a high-quality, spec-compliant implementation that can be relied upon by professionals.
The SDK is organized as a layered trading foundation:
- Application layer:
Cliententry points for CLOB REST, WebSocket, and RTDS workflows. - Execution layer:
pkg/executionfor place/cancel/query/replay contracts and unified lifecycle state. - Protocol layer:
pkg/clob,pkg/clob/ws, andpkg/rtdsfor exchange interaction and streams. - Security layer:
pkg/authfor EIP-712/HMAC signing, Proxy/Safe/KMS flows, and builder attribution headers. - Transport layer:
pkg/transportfor retry policy, error normalization, and request shaping.
The SDK is organized into modular packages to ensure maintainability and extensibility:
graph TD
Client[Client Interface] --> Transport[Transport Layer]
Client --> CLOB[CLOB Module]
Client --> Auth[Auth Module]
Client --> WS[WebSocket Module]
CLOB --> Orders[Order Management]
CLOB --> Markets[Market Data]
CLOB --> Account[Account & Rewards]
Auth --> EOA[Private Key Signer]
Auth --> KMS[AWS KMS Signer]
WS --> Stream[Event Streams]
- Type-safe integration surface: Fully typed requests/responses and predictable error handling.
- Realtime resilience: Built-in heartbeat + reconnect behavior for long-running WebSocket sessions.
- Institutional auth support: EOA, Proxy, Safe, and AWS KMS signer compatibility.
- Builder-first integration: Native order attribution fields and remote signing support.
- Low-latency trading paths: Optimized REST/WS primitives for execution and market data.
pkg/clob: The core client for REST API interactions (Orders, Markets, Account).pkg/clob/ws: Robust WebSocket client with auto-reconnect and typed event channels.pkg/auth: Cryptographic primitives for EIP-712 signing and HMAC generation.pkg/transport: HTTP transport layer handling signing injection, retries, and error parsing.pkg/execution: Unified execution contract (Place/Cancel/Query/Replay) with CLOB adapter bindings.
- 6-state lifecycle model:
created->accepted->partial->filled/canceled/rejected. - Deterministic idempotency: Canonical key spec (
tenant + strategy + client_order_id) for replay-safe execution. - Standard retry policy: Shared handling for network timeout and HTTP
5xxfailure classes. - WS runtime policy helpers: Reconnect and heartbeat policy primitives for strategy services.
- Attribution pass-through: Execution payload compatibility for
builder,funder, andsource. - Schema compatibility tests: Guards for message aliases (
event_type/type,bids/asks+buys/sells,assets_ids+asset_ids).
go get github.com/GoPolymarket/polymarket-go-sdkpackage main
import (
"context"
"fmt"
"log"
"os"
"time"
"github.com/GoPolymarket/polymarket-go-sdk"
"github.com/GoPolymarket/polymarket-go-sdk/pkg/auth"
"github.com/GoPolymarket/polymarket-go-sdk/pkg/clob"
"github.com/GoPolymarket/polymarket-go-sdk/pkg/clob/clobtypes"
"github.com/GoPolymarket/polymarket-go-sdk/pkg/clob/ws"
"github.com/GoPolymarket/polymarket-go-sdk/pkg/rtds"
)
func main() {
// 1. Initialize Signer (Private Key or KMS)
pk := os.Getenv("POLYMARKET_PK")
signer, err := auth.NewPrivateKeySigner(pk, 137) // 137 = Polygon Mainnet
if err != nil {
log.Fatal(err)
}
// 2. Initialize Credentials
creds := &auth.APIKey{
Key: os.Getenv("POLY_API_KEY"),
Secret: os.Getenv("POLY_API_SECRET"),
Passphrase: os.Getenv("POLY_API_PASSPHRASE"),
}
// 3. Optional: Explicit WS/RTDS runtime config (instead of env vars)
wsCfg := ws.DefaultClientConfig()
wsCfg.ReconnectMax = 10
wsCfg.HeartbeatInterval = 5 * time.Second
rtdsCfg := rtds.DefaultClientConfig()
rtdsCfg.PingInterval = 3 * time.Second
// 4. Create Client (strict constructor returns init errors)
client, err := polymarket.NewClientE(
polymarket.WithCLOBWSConfig(wsCfg),
polymarket.WithRTDSConfig(rtdsCfg),
)
if err != nil {
log.Printf("client initialized with partial failures: %v", err)
}
client = client.WithAuth(signer, creds)
// 5. Check System Status
status, _ := client.CLOB.Health(context.Background())
fmt.Println("System Status:", status)
}Tip: call
WithAuth(...)before starting WebSocket subscriptions so auth and stream lifecycle stay aligned.
The SDK handles the complex EIP-712 hashing and signing automatically.
ctx := context.Background()
// Create an order builder
resp, err := client.CLOB.CreateOrder(ctx,
clob.NewOrderBuilder(client.CLOB, signer).
TokenID("TOKEN_ID_HERE").
Side("BUY").
Price(0.50).
Size(100.0).
OrderType(clobtypes.OrderTypeGTC).
Build(),
)
if err != nil {
log.Fatal("Order failed:", err)
}
fmt.Printf("Order Placed: %s\n", resp.ID)wsClient := client.CLOB.WS()
defer wsClient.Close()
// Subscribe to price updates
sub, err := wsClient.SubscribePrices(ctx, []string{"TOKEN_ID_HERE"})
if err != nil {
log.Fatal(err)
}
for event := range sub {
fmt.Printf("New Price for %s: %s\n", event.AssetID, event.Price)
}Forget about manually handling next_cursor.
// Automatically iterates through all pages
allMarkets, err := client.CLOB.MarketsAll(ctx, &clobtypes.MarketsRequest{
Active: boolPtr(true),
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Fetched %d active markets\n", len(allMarkets))Balance/allowance requests now support asset_type, token_id, and signature_type (with asset kept for compatibility). Responses return an allowances map keyed by spender address.
// Set a default signature type on the CLOB client (0=EOA, 1=Proxy, 2=Safe)
clobClient := client.CLOB.WithSignatureType(auth.SignatureProxy)
bal, err := clobClient.BalanceAllowance(ctx, &clobtypes.BalanceAllowanceRequest{
AssetType: clobtypes.AssetTypeConditional,
TokenID: "TOKEN_ID_HERE",
})
if err != nil {
log.Fatal(err)
}
fmt.Println("Balance:", bal.Balance)
fmt.Println("Allowances:", bal.Allowances)
rewards, err := clobClient.UserRewardsByMarket(ctx, &clobtypes.UserRewardsByMarketRequest{
Date: "2026-01-01",
OrderBy: "date",
NoCompetition: true,
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("User rewards: %d entries\n", len(rewards))You can set client-level defaults that apply to order signing and API key creation:
WithSignatureTypeapplies to order signing and balance/rewards queries.WithAuthNoncebecomes the default nonce for create/derive API key calls.WithFundersets a maker address override (Proxy/Safe flows).WithSaltGeneratorcustomizes order salt generation.
client := polymarket.NewClient()
authClient := client.CLOB.
WithAuth(signer, nil).
WithSignatureType(auth.SignatureProxy).
WithAuthNonce(1).
WithSaltGenerator(func() (*big.Int, error) {
return big.NewInt(42), nil
})
// Optional: explicit funder address for proxy/safe signatures
authClient = authClient.WithFunder(common.HexToAddress("0xFunder..."))
builder := clob.NewOrderBuilder(authClient, signer).
TokenID("TOKEN_ID_HERE").
Side("BUY").
Price(0.5).
Size(10).
TickSize("0.01").
FeeRateBps(0)
signable, _ := builder.BuildSignableWithContext(ctx)
fmt.Println("Maker:", signable.Order.Maker.Hex())See examples/client_defaults for a runnable version.
Use clob.StreamData to iterate through any cursor-based endpoint without writing a custom loop:
stream := clob.StreamData(ctx, func(ctx context.Context, cursor string) ([]clobtypes.Market, string, error) {
resp, err := client.CLOB.Markets(ctx, &clobtypes.MarketsRequest{
Limit: 3,
Cursor: cursor,
})
if err != nil {
return nil, "", err
}
return resp.Data, resp.NextCursor, nil
})
for res := range stream {
if res.Err != nil {
log.Fatal(res.Err)
}
fmt.Println(res.Item.Question)
}See examples/stream_data for a runnable version.
The SDK provides typed errors in pkg/errors to help you handle trading failures programmatically.
import (
"errors"
sdkerrors "github.com/GoPolymarket/polymarket-go-sdk/pkg/errors"
)
resp, err := client.CLOB.CreateOrder(ctx, order)
if err != nil {
if errors.Is(err, sdkerrors.ErrInsufficientFunds) {
fmt.Println("Please deposit more USDC")
} else if errors.Is(err, sdkerrors.ErrRateLimitExceeded) {
fmt.Println("Backing off due to rate limits...")
}
}Always use decimal.Decimal (via PriceDec or SizeDec) when precision is critical to avoid floating-point issues common in financial applications.
builder.PriceDec(decimal.NewFromFloat(0.5001)).
SizeDec(decimal.NewFromInt(100))If you are developing a client-side application (Web/Mobile) and want to receive builder rewards without exposing your Builder Secret to the end users, you can use the Remote Signer pattern.
- Deploy the standalone signer service found in
cmd/signer-serverto your secure infrastructure (support for Docker included). - Configure your client to use the remote signer:
client := polymarket.NewClient(
polymarket.WithBuilderConfig(&auth.BuilderConfig{
Remote: &auth.BuilderRemoteConfig{
Host: "https://your-signer-api.com/v1/sign-builder",
},
}),
)If you need to switch an already-authenticated client into builder attribution mode (and restart heartbeats with the new headers), use PromoteToBuilder:
builderClient := authClient.PromoteToBuilder(myBuilderConfig)We are committed to maintaining this SDK as the best-in-class solution for Polymarket.
- Core CLOB REST API: Complete coverage of Order, Market, and Account endpoints.
- WebSocket Client: Robust, auto-reconnecting stream client with heartbeat.
- Authentication: Support for EOA, Proxy, Safe, and AWS KMS.
- Pagination: Helper methods for automatic resource iteration (
MarketsAll,OrdersAll). - Gamma API: Read-only metadata and discovery services.
- CI/CD: Linting, Testing, and strictly enforced Coverage.
- Institutional Performance Benchmarking: High-throughput stress testing and tick-to-trade latency analysis.
- CTF Exchange: Direct interaction with the CTF Exchange contract for on-chain actions.
- CLI Tool: A standalone CLI for managing orders and keys.
Contributions are welcome! Please check out the examples/ directory for more usage patterns.
- Fork the repository.
- Create your feature branch (
git checkout -b feature/amazing-feature). - Commit your changes (
git commit -m 'Add some amazing feature'). - Push to the branch (
git push origin feature/amazing-feature). - Open a Pull Request.
Requirements:
- Pass
go test ./... - Pass
golangci-lint run ./... - Maintain >=40% test coverage (strictly enforced by CI).
Distributed under the Apache License 2.0. See LICENSE for more information.
This project is an independent effort to provide a high-quality Go ecosystem for Polymarket. If you find it useful, please star the repo!