Skip to main content
The unified Python SDK gives you a consistent surface across Polymarket discovery, market data, trading, account data, and realtime streams.
The Python SDK is currently in beta. We are keeping it in this beta phase while we address issues and harden the SDK before transitioning to a more stable release.
The SDK ships parallel async and sync clients with matching method names and arguments: AsyncPublicClient / PublicClient for public reads, and AsyncSecureClient / SecureClient for authenticated reads and trading. Prefer the async clients for servers, bots, and any code that already runs inside an event loop. Use the sync clients for scripts, notebooks, and one-off tools where an event loop would just add ceremony. Realtime stream subscriptions are async only and require the async clients. Examples below show the body of an async def main() function; wrap them with asyncio.run(main()) to run as a script, as shown in Quickstart. To switch a snippet to sync, swap AsyncPublicClient / AsyncSecureClient for PublicClient / SecureClient, drop await, replace async with with with, replace async for with for, and remove the asyncio.run(...) wrapper.

Quickstart

1

Install the Package

Install the SDK from PyPI.
2

Create a Public Client

Create an instance of the AsyncPublicClient inside an async with block so its network transports are released when you are done.
3

Fetch Markets

Fetch a page of markets to discover active trading opportunities.

SDK Patterns

The SDK uses consistent patterns for pagination, Python-native model values, and structured SDK exceptions across public and authenticated workflows.

Typed Primitives

Identifiers and EVM addresses are exposed as typing.NewType aliases (MarketId, ConditionId, TokenId, EventId, EvmAddress, …) so static type checkers can keep them distinct from plain strings. Precision-sensitive price, size, and amount fields generally use decimal.Decimal; date and time fields use datetime.date or datetime.datetime.

Market and Event Data

Market and event responses are returned as SDK models with snake_case fields and nested submodels.

Environment Configuration

Production is the default environment. Pass an Environment object when your integration needs to target a different deployment or custom endpoint set. The client owns network transports, so use async with (or call await client.close()) to release them when you are done.

Pagination

With async clients, list methods return an AsyncPaginator across paginated endpoints. Use async for to iterate through pages.
You can also fetch the first page directly and resume later from a cursor.
When you only care about the items and not page boundaries, iterate them directly.

Error Handling

All SDK exceptions inherit from PolymarketError. Catch specific subclasses to handle known cases, and catch PolymarketError as the final SDK fallback.
Catching PolymarketError last ensures error subclasses added in future SDK releases do not pass through unhandled.

Market Data

Use market data methods to fetch market and event details, order books, current prices, historical prices, and batch quotes.
Then fetch related tags, order books, prices, and history.

Discovery

Use discovery methods to browse events, markets, teams, tags, comments, sports metadata, and search results. The examples below show a few common entry points.

Realtime Streams

Subscribe through one SDK interface even when events come from different stream families. The SDK routes each subscription spec to the right stream and merges the results into one async iterator. Subscriptions are async only and require AsyncPublicClient or AsyncSecureClient.
AsyncSecureClient.subscribe accepts the same public subscription specs and adds UserSpec for user-scoped order and trade events on the authenticated wallet.

Authenticated Client

Create a secure client when you need wallet-scoped reads or trading.
Secure clients own multiple network transports. Wrap them in async with, or call await secure_client.close() when you are done, to release the underlying connections. The snippets below show client creation and subsequent calls as a flat sequence for readability — in real code, keep the client inside an async with block or close it explicitly.

Private Key Setup

The Python SDK authenticates with a local private key. By default, AsyncSecureClient.create uses the signer’s deterministic Deposit Wallet as the account wallet. Pass wallet when you want to authenticate an existing wallet, such as an existing Deposit Wallet, Poly Safe, Poly Proxy, or the signer address itself for EOA trading. The examples below pass wallet to make account selection explicit. Omit wallet to use the default Deposit Wallet flow.
Keep private keys and API credentials in your secret manager or local environment. Do not commit them to source control.

API Key Authorization

Configure API key authorization when the SDK needs to deploy a Deposit Wallet or submit approval transactions.
Builder API keys are supported for backwards compatibility with builders that still use them for wallet operations. They are not used for order attribution. Use builder_code on orders for attribution.

Trading Setup

Before placing orders, make sure the authenticated wallet is deployed and has the required trading approvals. AsyncSecureClient.create resolves the signer’s deterministic Deposit Wallet by default and deploys it if needed.
From this point forward, snippets in Trading Setup, Trading, Position Lifecycle, and Wallet Operations submit real on-chain transactions or live orders against the configured environment when executed. Review each call before running it against a wallet that holds funds.
Set up the approvals required for trading.
setup_trading_approvals() waits for the setup transaction internally and is idempotent. If the wallet already has the required approvals, it returns without submitting a transaction.

Trading

Use a secure client to create, sign, and submit orders. Limit orders specify the price and size you want to trade. Market orders execute against resting liquidity immediately. Order placement returns a discriminated response. Check response.ok before reading order details.

Place Orders

Create, Then Post

Create signed orders separately when you want to review, store, or batch them before submitting.

Position Lifecycle

Use position lifecycle methods to split collateral into outcome tokens, merge complete sets back into collateral, or redeem resolved positions. These examples assume the secure client is configured with API key authorization as shown in API Key Authorization, and that you set up trading approvals as shown above.

Wallet Operations

Use wallet operation methods for direct token movements from the authenticated wallet. Amounts are in base units. These examples assume the secure client is configured with API key authorization as shown in API Key Authorization.

Order Management

Manage open orders for the authenticated wallet after placement. These examples assume order_id comes from an accepted order response.

Rewards and Scoring

Use rewards methods to inspect active reward programs and scoring methods to check whether orders are eligible for scoring. list_current_rewards and list_market_rewards are public reads and are also available on AsyncPublicClient / PublicClient; get_order_scoring and get_orders_scoring require a secure client because they read account-scoped order data.

Account Data

Secure clients read account-scoped data for the authenticated wallet by default. Methods that take a user= parameter (positions, portfolio value, activity) accept a different wallet address to read its data instead.

Authentication Sessions

Secure clients expose the API credentials created for the authenticated session. Store them securely if you want to reuse the session later without producing a new authentication signature while the credentials remain valid.

Changelog

0.1.0b19

  • Added RESOLVED_PARTIAL to ComboPositionStatus so Combo positions that resolve at a fractional payout (for example a voided leg) parse correctly instead of failing validation.

0.1.0b18

  • Combo activity now parses the canonical type field returned by the Data API, instead of deriving lifecycle actions from legacy fields.

0.1.0b17

  • Added SDK pagination for Combo lifecycle activity and server-cursor pagination for Combo positions.
  • Added typed overloads for market, event, and tag lookups, mutually-exclusive lookup arguments, and redeem_positions.
  • Added trade time filters.
  • Hardened Combo pagination filters and branded Combo activity IDs.
  • Breaking beta change: Combo activity and position fields now use wallet, amount, and payout; Combo activity rows no longer expose module_kind.

0.1.0b16

  • Fixed Deposit Wallet trading setup approvals to use the current Protocol V2 auto-redeem operator.

0.1.0b15

  • Added support for Perps.

0.1.0b14

  • Added builder API key management for creating, fetching, and revoking builder API keys.
  • Added support for merging multiple positions in one request.
  • Added runnable Python SDK examples for common integration workflows.
  • Resolve closed markets when redeeming positions.
  • Gasless transaction handles now wait for relayer transactions to reach confirmed state before resolving.

0.1.0b13

  • Require GTD limit order expirations to be at least 3 minutes in the future.

0.1.0b12

  • Support CLOB order tick sizes 0.005 and 0.0025.

0.1.0b11

  • Preserve already-deployed legacy UUPS Deposit Wallets when secure clients resolve the default wallet, while new Deposit Wallet deployments use the beacon factory path.
  • Retry rejected JSON-RPC batches by splitting them into smaller batches.
  • Added typed Gamma search sort fields for search requests.

0.1.0b10

  • Preserve group_item_title on market responses so grouped market titles remain available after normalization.

0.1.0b9

  • RFQ quoter sessions now emit typed RfqTradeEvent events for confirmed Combos fills.
  • RFQ rejection errors now expose error_id values and parse INVALID_SIGNATURE and INTERNAL_ERROR codes.

0.1.0b8

  • Added parent_event_id to Event so child events can link back to their parent event.
  • Added max_price and min_price protection fields to market order requests.
  • Handle legacy multi-outcome market listings more safely by omitting markets that cannot be represented by the binary market model.
  • Normalize empty-string trade and position market icons to None.
  • Parse Combo trade activity rows correctly.
  • Support new Combos RFQ error codes for balance, allowance, and pre-execution reservation failures.
  • Broad user websocket subscriptions now omit market filters so all-market streams receive trade events.

0.1.0b7

  • Point Combos RFQ endpoints at the production domains: combos-rfq-api.polymarket.com (REST) and combos-rfq-gateway-quoter.polymarket.com (quoter WebSocket).

0.1.0b6

  • Added list_combo_markets for fetching the Combo market catalog with SDK pagination. See Combos.
  • Parse RFQ quote rejections that use the SUBMISSION_WINDOW_CLOSED gateway error code.

0.1.0b5

  • Added Combos support for multi-leg RFQ positions. See Combos.
  • Added notebook-friendly model display for Jupyter workflows.
  • ConditionId is now deprecated in favor of CtfConditionId; existing ConditionId exports remain available as deprecated aliases.

0.1.0b4

  • Added dataframe conversion support for SDK models and response collections.
Secure client setup now defaults to the Deposit Wallet flow AsyncSecureClient.create can now derive and use the signer’s deterministic Deposit Wallet when you omit wallet. If you already know which Polymarket wallet you want to use, keep passing wallet.
If you want to keep account selection explicit, no change is required:
setup_trading_approvals() now waits internally You no longer need to wait on the returned handle. Call the method once before trading; it is safe to call again if approvals are already set.
Gasless setup helpers are deprecated You no longer need to call is_gasless_ready() or setup_gasless_wallet() in the normal setup path. Create the secure client, then set up trading approvals.

0.1.0b1

First beta release of the unified Python SDK. Install the beta package with your package manager: