> ## Documentation Index
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrate from Legacy SDKs to Unified SDKs

> Move an existing Polymarket integration to the unified SDKs.

Migrate from the previous CLOB, relayer, and builder-signing clients to the
unified SDK.

**TypeScript**

The examples below map previous client capabilities to
`@polymarket/client`. The SDK also covers the Gamma API and Data API. Migrating
direct Gamma and Data calls can simplify application code and give you
normalized, typed models that work seamlessly with the SDK's trading and
account workflows.

## Install the Unified SDK

Remove the previous CLOB, relayer, and builder-signing packages used by your
integration. Then install the unified SDK and your wallet library.

```bash npm theme={null}
npm uninstall @polymarket/clob-client-v2 @polymarket/builder-relayer-client @polymarket/builder-signing-sdk
npm install @polymarket/client@latest viem
```

```bash pnpm theme={null}
pnpm remove @polymarket/clob-client-v2 @polymarket/builder-relayer-client @polymarket/builder-signing-sdk
pnpm add @polymarket/client@latest viem
```

```bash Yarn theme={null}
yarn remove @polymarket/clob-client-v2 @polymarket/builder-relayer-client @polymarket/builder-signing-sdk
yarn add @polymarket/client@latest viem
```

```bash Bun theme={null}
bun remove @polymarket/clob-client-v2 @polymarket/builder-relayer-client @polymarket/builder-signing-sdk
bun add @polymarket/client@latest viem
```

> [!NOTE]
>
> The unified SDK includes signer adapters for Viem, Privy, and Ethers v5, so
> you can connect your wallet library without implementing CLOB-specific
> signing. See [Wallet
> Integrations](/getting-started/typescript#wallet-integrations) for setup
> examples.

## Client and Wallet Setup

### Create a Public Client

`PublicClient` provides unauthenticated market discovery and data reads.
`createPublicClient` uses production by default and does not require a host or
chain ID.

```ts Before theme={null}
import { ClobClient } from "@polymarket/clob-client-v2";

const client = new ClobClient({
  host: "https://clob.polymarket.com",
  chain: 137,
});
```

```ts After theme={null}
import { createPublicClient } from "@polymarket/client";

const client = createPublicClient();
```

### Create an Authenticated Client

`SecureClient` adds authenticated trading, account, and wallet actions.
`createSecureClient` derives or creates CLOB credentials, resolves the account
wallet, and configures the correct signing flow.

```ts Before theme={null}
import { ClobClient, SignatureTypeV2 } from "@polymarket/clob-client-v2";

const tempClient = new ClobClient({
  host: "https://clob.polymarket.com",
  chain: 137,
  signer,
});
const credentials = await tempClient.createOrDeriveApiKey();

const client = new ClobClient({
  host: "https://clob.polymarket.com",
  chain: 137,
  signer,
  creds: credentials,
  signatureType: SignatureTypeV2.POLY_1271,
  funderAddress: process.env.POLYMARKET_WALLET_ADDRESS,
});
```

```ts After theme={null}
import { type ApiKeyCreds, createSecureClient } from "@polymarket/client";
import { privateKey } from "@polymarket/client/viem";

const client = await createSecureClient({
  wallet: process.env.POLYMARKET_WALLET_ADDRESS,
  signer: privateKey(process.env.POLYMARKET_PRIVATE_KEY),
});
```

Omit `wallet` to use the default Deposit Wallet flow.

### Resume With Existing Credentials

Read credentials from an authenticated client, store them securely, and pass
them to a new client to resume with the same API key. The signer and wallet must
identify the account that owns the credentials.

```ts Before theme={null}
import { ClobClient, SignatureTypeV2 } from "@polymarket/clob-client-v2";

const credentials = client.creds;
if (!credentials) throw new Error("Client has no credentials");

// Store the credentials securely.

const resumedClient = new ClobClient({
  host: "https://clob.polymarket.com",
  chain: 137,
  signer,
  creds: credentials,
  signatureType: SignatureTypeV2.POLY_1271,
  funderAddress: process.env.POLYMARKET_WALLET_ADDRESS,
});
```

```ts After theme={null}
import { createSecureClient } from "@polymarket/client";
import { privateKey } from "@polymarket/client/viem";

const credentials = client.credentials;

// Store the credentials securely.

const resumedClient = await createSecureClient({
  wallet: process.env.POLYMARKET_WALLET_ADDRESS,
  signer: privateKey(process.env.POLYMARKET_PRIVATE_KEY),
  // Restore the type if loading from storage erased it.
  credentials: credentials as ApiKeyCreds,
});
```

### Revoke the Current API Key

Ending authentication revokes the current API key, invalidates the
`SecureClient`, and returns a `PublicClient`.

```ts Before theme={null}
await client.deleteApiKey();
```

```ts After theme={null}
const publicClient = await client.endAuthentication();
```

### Configure Builder API Keys

`SecureClient` accepts Builder authorization for gasless wallet actions.
Migrate local or remote Builder signing to the matching helper.

**Local Builder API key**

Keep local Builder credentials on the server. The Node.js entrypoint generates
the required HMAC headers.

```ts Before theme={null}
import { RelayClient } from "@polymarket/builder-relayer-client";
import { BuilderConfig } from "@polymarket/builder-signing-sdk";

const builderConfig = new BuilderConfig({
  localBuilderCreds: {
    key: process.env.POLYMARKET_BUILDER_API_KEY!,
    secret: process.env.POLYMARKET_BUILDER_SECRET!,
    passphrase: process.env.POLYMARKET_BUILDER_PASSPHRASE!,
  },
});

const relayer = new RelayClient(
  "https://relayer-v2.polymarket.com",
  137,
  walletClient,
  builderConfig,
);
```

```ts After theme={null}
import { createSecureClient } from "@polymarket/client";
import { builderApiKey } from "@polymarket/client/node";
import { privateKey } from "@polymarket/client/viem";

const client = await createSecureClient({
  signer: privateKey(process.env.POLYMARKET_PRIVATE_KEY),
  apiKey: builderApiKey({
    key: process.env.POLYMARKET_BUILDER_API_KEY!,
    secret: process.env.POLYMARKET_BUILDER_SECRET!,
    passphrase: process.env.POLYMARKET_BUILDER_PASSPHRASE!,
  }),
});
```

**Remote Builder Signing**

Keep Builder credentials behind your signing endpoint. The client sends the
same `{ method, path, body }` request and applies the same Builder headers, so
the endpoint contract does not change.

```ts Before theme={null}
import { RelayClient } from "@polymarket/builder-relayer-client";
import { BuilderConfig } from "@polymarket/builder-signing-sdk";

const builderConfig = new BuilderConfig({
  remoteBuilderConfig: {
    url: "https://example.com/api/builder/sign",
    token: process.env.BUILDER_SIGNING_TOKEN,
  },
});

const relayer = new RelayClient(
  "https://relayer-v2.polymarket.com",
  137,
  walletClient,
  builderConfig,
);
```

```ts After theme={null}
import { createSecureClient, remoteBuilderSigning } from "@polymarket/client";

const client = await createSecureClient({
  signer,
  apiKey: remoteBuilderSigning({
    url: "https://example.com/api/builder/sign",
    headers: {
      Authorization: `Bearer ${process.env.BUILDER_SIGNING_TOKEN}`,
    },
  }),
});
```

On the signing server, replace `BuilderConfig.generateBuilderHeaders` with
`buildHmacSignature`. Keep your existing caller authentication and
authorization around this handler.

```ts Before theme={null}
import { BuilderConfig } from "@polymarket/builder-signing-sdk";

const builderConfig = new BuilderConfig({
  localBuilderCreds: {
    key: process.env.POLYMARKET_BUILDER_API_KEY!,
    secret: process.env.POLYMARKET_BUILDER_SECRET!,
    passphrase: process.env.POLYMARKET_BUILDER_PASSPHRASE!,
  },
});

export async function POST(request: Request): Promise<Response> {
  const { body, method, path } = await request.json();
  const headers = await builderConfig.generateBuilderHeaders(
    method,
    path,
    body,
  );

  return Response.json(headers);
}
```

```ts After theme={null}
import { buildHmacSignature } from "@polymarket/client";

export async function POST(request: Request): Promise<Response> {
  const { body, method, path } = await request.json();
  const timestamp = Math.floor(Date.now() / 1000);

  return Response.json({
    POLY_BUILDER_API_KEY: process.env.POLYMARKET_BUILDER_API_KEY!,
    POLY_BUILDER_PASSPHRASE: process.env.POLYMARKET_BUILDER_PASSPHRASE!,
    POLY_BUILDER_SIGNATURE: await buildHmacSignature(
      process.env.POLYMARKET_BUILDER_SECRET!,
      timestamp,
      method,
      path,
      body,
    ),
    POLY_BUILDER_TIMESTAMP: `${timestamp}`,
  });
}
```

### Configure Relayer API Keys

`SecureClient` configures Relayer API keys directly. Pass the key and its
associated address to `relayerApiKey` when reconnecting an existing account.

```ts theme={null}
import { createSecureClient, relayerApiKey } from "@polymarket/client";
import { privateKey } from "@polymarket/client/viem";

const client = await createSecureClient({
  wallet: process.env.POLYMARKET_WALLET_ADDRESS,
  signer: privateKey(process.env.POLYMARKET_PRIVATE_KEY),
  apiKey: relayerApiKey({
    key: process.env.POLYMARKET_RELAYER_API_KEY!,
    address: process.env.POLYMARKET_RELAYER_API_KEY_ADDRESS!,
  }),
});
```

### Deploy a Deposit Wallet

Creating a `SecureClient` without a `wallet` derives the signer's Deposit Wallet
address and deploys it when needed. Use one of the Builder authorization
strategies above to authorize the deployment.

```ts Before theme={null}
const deployment = await relayer.deployDepositWallet();
await deployment.wait();
```

```ts After theme={null}
import { createSecureClient } from "@polymarket/client";
import { builderApiKey } from "@polymarket/client/node";
import { privateKey } from "@polymarket/client/viem";

const client = await createSecureClient({
  signer: privateKey(process.env.POLYMARKET_PRIVATE_KEY),
  apiKey: builderApiKey({
    key: process.env.POLYMARKET_BUILDER_API_KEY!,
    secret: process.env.POLYMARKET_BUILDER_SECRET!,
    passphrase: process.env.POLYMARKET_BUILDER_PASSPHRASE!,
  }),
});

const depositWalletAddress = client.account.wallet;
```

## Market Discovery

### Fetch a Market

Both `PublicClient` and `SecureClient` provide `fetchMarket` for reads by Gamma
market ID, slug, or Polymarket URL.

```ts Before theme={null}
const market = await client.getMarket("CONDITION_ID");
```

```ts After theme={null}
const market = await client.fetchMarket({ slug: "MARKET_SLUG" });
```

If you only have a condition ID, filter `listMarkets` and fetch its first page.

```ts theme={null}
const page = await client
  .listMarkets({ conditionIds: ["CONDITION_ID"] })
  .firstPage();

const market = page.items[0];
```

### List Markets

Both `PublicClient` and `SecureClient` provide `listMarkets`, which returns a
paginator and accepts filters directly.

```ts Before theme={null}
const page = await client.getMarkets();
const markets = page.data;
```

```ts After theme={null}
const pages = client.listMarkets({ closed: false, pageSize: 20 });
const page = await pages.firstPage();
const markets = page.items;
```

`getSimplifiedMarkets` does not need a separate replacement. Unified market
models are normalized for SDK use. Sampling-market reads should migrate to
`listCurrentRewards`, which lists the active reward configurations.

```ts Before theme={null}
const markets = await client.getSamplingMarkets();
const page = await client.getSamplingSimplifiedMarkets();
```

```ts After theme={null}
const pages = client.listCurrentRewards();
const page = await pages.firstPage();
```

## Market Data

### Read Trading Parameters

Both `PublicClient` and `SecureClient` return tick size and negative-risk status
on the unified market model. Order methods also resolve them automatically, so
you no longer pass either value when placing an order.

```ts Before theme={null}
const tickSize = await client.getTickSize("TOKEN_ID");
const negRisk = await client.getNegRisk("TOKEN_ID");
```

```ts After theme={null}
const market = await client.fetchMarket({ slug: "MARKET_SLUG" });
const tickSize = market.trading.minimumTickSize;
const negRisk = market.state.negRisk;
```

### Read CLOB Market Details

Both `PublicClient` and `SecureClient` return the normalized market model for
public product data. Its trading fields replace the compact CLOB market response
and standalone fee reads.

```ts Before theme={null}
const info = await client.getClobMarketInfo("CONDITION_ID");
const feeRateBps = await client.getFeeRateBps("TOKEN_ID");
const feeExponent = await client.getFeeExponent("TOKEN_ID");
```

```ts After theme={null}
const page = await client
  .listMarkets({ conditionIds: ["CONDITION_ID"] })
  .firstPage();

const market = page.items[0];
const feeSchedule = market?.trading.feeSchedule;
```

### Fetch Order Books

Both `PublicClient` and `SecureClient` provide single and batch order book reads
with camelCase request fields.

```ts Before theme={null}
const book = await client.getOrderBook("TOKEN_ID");
const books = await client.getOrderBooks([
  { token_id: "TOKEN_ID_1" },
  { token_id: "TOKEN_ID_2" },
]);
```

The unified SDK uses `assetId` for an outcome's trading identifier: a token ID
for a CTF market or a position ID for a Polymarket Protocol V2 market. Use the
identifier exposed for that outcome.

```ts After theme={null}
const book = await client.fetchOrderBook({ assetId: "ASSET_ID" });
const books = await client.fetchOrderBooks([
  { assetId: "ASSET_ID_1" },
  { assetId: "ASSET_ID_2" },
]);
```

### Fetch Prices

Both `PublicClient` and `SecureClient` provide single and batch price reads with
`OrderSide` and camelCase request fields.

```ts Before theme={null}
import { Side } from "@polymarket/clob-client-v2";

const price = await client.getPrice("TOKEN_ID", Side.BUY);
const prices = await client.getPrices([
  { token_id: "TOKEN_ID_1", side: Side.BUY },
  { token_id: "TOKEN_ID_2", side: Side.SELL },
]);
```

```ts After theme={null}
import { OrderSide } from "@polymarket/client";

const price = await client.fetchPrice({
  assetId: "ASSET_ID",
  side: OrderSide.BUY,
});
const prices = await client.fetchPrices([
  { assetId: "ASSET_ID_1", side: OrderSide.BUY },
  { assetId: "ASSET_ID_2", side: OrderSide.SELL },
]);
```

### Fetch Midpoints

Both `PublicClient` and `SecureClient` provide `fetchMidpoint` and
`fetchMidpoints` for single and batch reads.

```ts Before theme={null}
const midpoint = await client.getMidpoint("TOKEN_ID");
const midpoints = await client.getMidpoints([
  { token_id: "TOKEN_ID_1" },
  { token_id: "TOKEN_ID_2" },
]);
```

```ts After theme={null}
const midpoint = await client.fetchMidpoint({ assetId: "ASSET_ID" });
const midpoints = await client.fetchMidpoints([
  { assetId: "ASSET_ID_1" },
  { assetId: "ASSET_ID_2" },
]);
```

### Fetch Spreads

Both `PublicClient` and `SecureClient` provide single and batch spread reads
with the same request pattern.

```ts Before theme={null}
const spread = await client.getSpread("TOKEN_ID");
const spreads = await client.getSpreads([
  { token_id: "TOKEN_ID_1" },
  { token_id: "TOKEN_ID_2" },
]);
```

```ts After theme={null}
const spread = await client.fetchSpread({ assetId: "ASSET_ID" });
const spreads = await client.fetchSpreads([
  { assetId: "ASSET_ID_1" },
  { assetId: "ASSET_ID_2" },
]);
```

### Fetch Last Trade Prices

Both `PublicClient` and `SecureClient` provide singular and batch methods for
last-trade prices.

```ts Before theme={null}
const lastTrade = await client.getLastTradePrice("TOKEN_ID");
const lastTrades = await client.getLastTradesPrices([
  { token_id: "TOKEN_ID_1" },
  { token_id: "TOKEN_ID_2" },
]);
```

```ts After theme={null}
const lastTrade = await client.fetchLastTradePrice({ assetId: "ASSET_ID" });
const lastTrades = await client.fetchLastTradePrices([
  { assetId: "ASSET_ID_1" },
  { assetId: "ASSET_ID_2" },
]);
```

### Fetch Price History

Both `PublicClient` and `SecureClient` provide price history. Pass all parameters
in one request object; the response uses camelCase fields and typed timestamps.

```ts Before theme={null}
const history = await client.getPricesHistory({
  market: "TOKEN_ID",
  interval: "1d",
  fidelity: 60,
});
```

```ts After theme={null}
import { PriceHistoryInterval } from "@polymarket/client";

const history = await client.fetchPriceHistory({
  assetId: "ASSET_ID",
  interval: PriceHistoryInterval.ONE_DAY,
  fidelity: 60,
});
```

### Estimate a Market Order Price

Both `PublicClient` and `SecureClient` provide market-order price estimates. The
request distinguishes collateral spent for buys from shares sold for sells.

```ts Before theme={null}
const price = await client.calculateMarketPrice(
  "TOKEN_ID",
  Side.BUY,
  100,
  OrderType.FAK,
);
```

```ts After theme={null}
const price = await client.estimateMarketPrice({
  assetId: "ASSET_ID",
  side: OrderSide.BUY,
  amount: 100,
});
```

### List Recent Market Trades

Both `PublicClient` and `SecureClient` provide the public trade paginator, which
replaces the previous market-events response.

```ts Before theme={null}
const trades = await client.getMarketTradesEvents("CONDITION_ID");
```

```ts After theme={null}
const pages = client.listTrades({ market: ["CONDITION_ID"] });
const page = await pages.firstPage();
const trades = page.items;
```

## Orders

### Place a Limit Order

`SecureClient` resolves tick size, negative-risk status, fees, and signing
details before it submits a limit order.

```ts Before theme={null}
const response = await client.createAndPostOrder(
  {
    tokenID: "TOKEN_ID",
    price: 0.52,
    size: 10,
    side: Side.BUY,
  },
  { tickSize: "0.01", negRisk: false },
  OrderType.GTC,
);
```

```ts After theme={null}
const response = await client.placeLimitOrder({
  assetId: "ASSET_ID",
  price: 0.52,
  size: 10,
  side: OrderSide.BUY,
});
```

Set `expiration` for a GTD order and `postOnly: true` for a post-only order.

### Place a Market Order

`SecureClient` places market orders. Buys specify collateral to spend, while
sells specify shares to sell.

```ts Before theme={null}
const response = await client.createAndPostMarketOrder(
  {
    tokenID: "TOKEN_ID",
    amount: 10,
    userUSDCBalance: 10,
    side: Side.BUY,
  },
  { tickSize: "0.01", negRisk: false },
  OrderType.FAK,
);
```

```ts After theme={null}
const response = await client.placeMarketOrder({
  assetId: "ASSET_ID",
  amount: 10,
  maxSpend: 10,
  side: OrderSide.BUY,
  orderType: OrderType.FAK,
});
```

`userUSDCBalance` becomes `maxSpend`. The previous field supplied the account
balance used to adjust the order for fees; the unified SDK instead accepts the
maximum total USD to spend. Set `maxSpend` equal to `amount` when the amount
should include fees, or omit it to pay applicable fees on top.

### Sign Without Posting

`SecureClient` provides order-type-specific creation methods when signing and
submission need to happen separately.

```ts Before theme={null}
const signedOrder = await client.createOrder(
  {
    tokenID: "TOKEN_ID",
    price: 0.52,
    size: 10,
    side: Side.BUY,
  },
  { tickSize: "0.01", negRisk: false },
);

const response = await client.postOrder(signedOrder, OrderType.GTC);
```

```ts After theme={null}
const signedOrder = await client.createLimitOrder({
  assetId: "ASSET_ID",
  price: 0.52,
  size: 10,
  side: OrderSide.BUY,
});

const response = await client.postOrder(signedOrder);
```

Use `createMarketOrder` instead when preparing an FAK or FOK market order.

### Post Several Orders

`SecureClient` provides `postOrders`. Order type and post-only behavior are part
of each signed order, so the method accepts the signed orders directly.

```ts Before theme={null}
const response = await client.postOrders([
  { order: firstOrder, orderType: OrderType.GTC },
  { order: secondOrder, orderType: OrderType.GTC },
]);
```

```ts After theme={null}
const response = await client.postOrders([firstOrder, secondOrder]);
```

### Attribute an Order to a Builder

`SecureClient` attaches the builder code to each order.

```ts Before theme={null}
const response = await client.createAndPostOrder(
  {
    tokenID: "TOKEN_ID",
    price: 0.52,
    size: 10,
    side: Side.BUY,
    builderCode: process.env.POLYMARKET_BUILDER_CODE,
  },
  { tickSize: "0.01", negRisk: false },
);
```

```ts After theme={null}
const response = await client.placeLimitOrder({
  assetId: "ASSET_ID",
  price: 0.52,
  size: 10,
  side: OrderSide.BUY,
  builderCode: process.env.POLYMARKET_BUILDER_CODE,
});
```

### Cancel Orders

`SecureClient` provides the cancel methods. They now accept camelCase request
objects, while `cancelAll` remains parameterless.

```ts Before theme={null}
await client.cancelOrder("ORDER_ID");
await client.cancelOrders(["ORDER_ID_1", "ORDER_ID_2"]);
await client.cancelAll();
await client.cancelMarketOrders({
  market: "CONDITION_ID",
  asset_id: "TOKEN_ID",
});
```

```ts After theme={null}
await client.cancelOrder({ orderId: "ORDER_ID" });
await client.cancelOrders({ orderIds: ["ORDER_ID_1", "ORDER_ID_2"] });
await client.cancelAll();
await client.cancelMarketOrders({
  market: "CONDITION_ID",
  assetId: "ASSET_ID",
});
```

### Fetch an Order

`SecureClient` fetches an order by ID using a request object.

```ts Before theme={null}
const order = await client.getOrder("ORDER_ID");
```

```ts After theme={null}
const order = await client.fetchOrder({ orderId: "ORDER_ID" });
```

### List Open Orders

`SecureClient` provides `listOpenOrders`, which returns a paginator. Filters and
response fields use camelCase.

```ts Before theme={null}
const orders = await client.getOpenOrders({
  market: "CONDITION_ID",
  asset_id: "TOKEN_ID",
});
```

```ts After theme={null}
const pages = client.listOpenOrders({
  market: "CONDITION_ID",
  assetId: "ASSET_ID",
});
const orders = [];
for await (const page of pages) {
  orders.push(...page.items);
}
```

### Check Order Scoring

`SecureClient` provides `fetchOrderScoring` for one order and
`fetchOrdersScoring` for several.

```ts Before theme={null}
const scoring = await client.isOrderScoring({ orderId: "ORDER_ID" });
const batch = await client.areOrdersScoring({
  orderIds: ["ORDER_ID_1", "ORDER_ID_2"],
});
```

```ts After theme={null}
const scoring = await client.fetchOrderScoring({ orderId: "ORDER_ID" });
const batch = await client.fetchOrdersScoring({
  orderIds: ["ORDER_ID_1", "ORDER_ID_2"],
});
```

## Account Activity and Balances

### List Account Trades

`SecureClient` replaces both previous account trade-history methods with one
paginator.

```ts Before theme={null}
const trades = await client.getTrades({ market: "CONDITION_ID" });
const page = await client.getTradesPaginated({ market: "CONDITION_ID" });
```

```ts After theme={null}
const pages = client.listAccountTrades({ market: "CONDITION_ID" });
const firstPage = await pages.firstPage();

const trades = [];
for await (const page of pages) {
  trades.push(...page.items);
}
```

### List Builder Trades

Both `PublicClient` and `SecureClient` provide public builder trade history,
filtered by builder code.

```ts Before theme={null}
const trades = await client.getBuilderTrades();
```

```ts After theme={null}
const pages = client.listBuilderTrades({
  builderCode: process.env.POLYMARKET_BUILDER_CODE,
});
const page = await pages.firstPage();
const trades = page.items;
```

### Read and Drop Notifications

`SecureClient` provides notification methods with action-oriented names and
camelCase request fields.

```ts Before theme={null}
const notifications = await client.getNotifications();
await client.dropNotifications({ ids: [1, 2] });
```

```ts After theme={null}
const notifications = await client.fetchNotifications();
await client.dropNotifications({ ids: ["1", "2"] });
```

### Refresh Balances and Allowances

`SecureClient` manages balances and allowances while placing orders. It detects
a missing allowance, completes the required approval, refreshes the balance and
allowance, and retries the order.

```ts Before theme={null}
await client.updateBalanceAllowance({
  asset_type: AssetType.COLLATERAL,
});

const balance = await client.getBalanceAllowance({
  asset_type: AssetType.COLLATERAL,
});
```

```ts After theme={null}
const response = await client.placeLimitOrder({
  assetId: "ASSET_ID",
  price: 0.52,
  size: 10,
  side: OrderSide.BUY,
});
```

## Positions

The unified methods build and submit the wallet transactions. You no longer
need to encode contract calls or pass transaction arrays to `execute`.

### Split a Position

`SecureClient` splits collateral into a complete set of YES and NO outcome
tokens.

```ts Before theme={null}
const splitTx = {
  to: CTF_COLLATERAL_ADAPTER_ADDRESS,
  data: collateralAdapterInterface.encodeFunctionData("splitPosition", [
    PUSD_ADDRESS,
    ethers.constants.HashZero,
    conditionId,
    [1, 2],
    ethers.utils.parseUnits("1", 6),
  ]),
  value: "0",
};

const split = await relayer.execute([splitTx], "Split position");
await split.wait();
```

```ts After theme={null}
const split = await client.splitPosition({
  conditionId,
  amount: 1_000_000n,
});

await split.wait();
```

### Merge Positions

`SecureClient` merges balanced YES and NO tokens back into collateral.

```ts Before theme={null}
const mergeTx = {
  to: CTF_COLLATERAL_ADAPTER_ADDRESS,
  data: collateralAdapterInterface.encodeFunctionData("mergePositions", [
    PUSD_ADDRESS,
    ethers.constants.HashZero,
    conditionId,
    [1, 2],
    ethers.utils.parseUnits("1", 6),
  ]),
  value: "0",
};

const merge = await relayer.execute([mergeTx], "Merge positions");
await merge.wait();
```

```ts After theme={null}
const merge = await client.mergePositions({
  conditionId,
  amount: "max",
});

await merge.wait();
```

### Redeem Resolved Positions

`SecureClient` redeems winning outcome tokens for collateral after resolution.

```ts Before theme={null}
const redeemTx = {
  to: CTF_COLLATERAL_ADAPTER_ADDRESS,
  data: collateralAdapterInterface.encodeFunctionData("redeemPositions", [
    PUSD_ADDRESS,
    ethers.constants.HashZero,
    conditionId,
    [1, 2],
  ]),
  value: "0",
};

const redeem = await relayer.execute([redeemTx], "Redeem positions");
await redeem.wait();
```

```ts After theme={null}
const redeem = await client.redeemPositions({ conditionId });
await redeem.wait();
```

## Service Status

Neither `PublicClient` nor `SecureClient` requires these calls. The unified
clients manage request timing internally.

```ts Before theme={null}
await client.getOk();
const timestamp = await client.getServerTime();
```

```ts After theme={null}
// No client call is required for request timestamp synchronization.
```

**Python**

The examples below map previous client capabilities to `polymarket-client`.
The SDK also covers the Gamma API and Data API. Migrating direct Gamma and
Data calls can simplify application code and give you normalized, typed
models that work seamlessly with the SDK's trading and account workflows.

Public clients provide unauthenticated market discovery and data reads.
Secure clients add authenticated trading, account, and wallet actions.
Python provides async and sync versions of each, so choose the interface
that matches your application's execution model.

| Interface | Clients | Best for |
| - | - | - |
| Async | `AsyncPublicClient`, `AsyncSecureClient` | Services, bots, and applications using an event loop |
| Sync | `PublicClient`, `SecureClient` | Scripts, notebooks, and synchronous applications |

The examples below use the async clients.

> [!NOTE]
>
> Some features are available only through the async clients due to their
> streaming nature.

## Install the Unified SDK

Remove the previous CLOB, relayer, and builder-signing packages. Then install the
unified SDK.

```bash uv theme={null}
uv remove py-clob-client-v2 py-builder-relayer-client py-builder-signing-sdk
uv add polymarket-client
```

```bash pip theme={null}
pip uninstall -y py-clob-client-v2 py-builder-relayer-client py-builder-signing-sdk
pip install polymarket-client
```

```bash Poetry theme={null}
poetry remove py-clob-client-v2 py-builder-relayer-client py-builder-signing-sdk
poetry add polymarket-client
```

## Client and Wallet Setup

### Create a Public Client

`AsyncPublicClient` provides unauthenticated market discovery and data reads.
Production is the default environment.

```python Before theme={null}
from py_clob_client_v2.client import ClobClient

client = ClobClient("https://clob.polymarket.com", chain_id=137)
```

```python After theme={null}
from polymarket import AsyncPublicClient

client = AsyncPublicClient()
```

### Create an Authenticated Client

`AsyncSecureClient` adds authenticated trading, account, and wallet actions.
`create` derives or creates CLOB credentials, resolves the account wallet, and
configures signing.

```python Before theme={null}
import os

from py_clob_client_v2.client import ClobClient
from py_clob_client_v2.order_utils.model import SignatureTypeV2

temporary_client = ClobClient(
    "https://clob.polymarket.com",
    chain_id=137,
    key=os.environ["POLYMARKET_PRIVATE_KEY"],
)
credentials = temporary_client.create_or_derive_api_key()

client = ClobClient(
    "https://clob.polymarket.com",
    chain_id=137,
    key=os.environ["POLYMARKET_PRIVATE_KEY"],
    creds=credentials,
    signature_type=SignatureTypeV2.POLY_1271,
    funder=os.environ["POLYMARKET_WALLET_ADDRESS"],
)
```

```python After theme={null}
import os

from polymarket import AsyncSecureClient

client = await AsyncSecureClient.create(
    private_key=os.environ["POLYMARKET_PRIVATE_KEY"],
    wallet=os.environ["POLYMARKET_WALLET_ADDRESS"],
)
```

Omit `wallet` to use the default Deposit Wallet flow.

### Resume With Existing Credentials

Read credentials from an authenticated client, store them securely, and pass
them to a new client to resume with the same API key. The private key and wallet
must identify the account that owns the credentials.

```python Before theme={null}
import os

from py_clob_client_v2.client import ClobClient
from py_clob_client_v2.order_utils.model import SignatureTypeV2

credentials = client.creds
if credentials is None:
    raise RuntimeError("Client has no credentials")

# Store the credentials securely.

resumed_client = ClobClient(
    "https://clob.polymarket.com",
    chain_id=137,
    key=os.environ["POLYMARKET_PRIVATE_KEY"],
    creds=credentials,
    signature_type=SignatureTypeV2.POLY_1271,
    funder=os.environ["POLYMARKET_WALLET_ADDRESS"],
)
```

```python After theme={null}
import os

from polymarket import AsyncSecureClient

credentials = client.credentials

# Store the credentials securely.

resumed_client = await AsyncSecureClient.create(
    private_key=os.environ["POLYMARKET_PRIVATE_KEY"],
    wallet=os.environ["POLYMARKET_WALLET_ADDRESS"],
    credentials=credentials,
)
```

### Revoke the Current API Key

Ending authentication revokes the current API key, invalidates the
`AsyncSecureClient`, and returns an `AsyncPublicClient`.

```python Before theme={null}
client.delete_api_key()
```

```python After theme={null}
public_client = await client.end_authentication()
```

### Configure Builder API Keys

`AsyncSecureClient` accepts a `BuilderApiKey` for gasless wallet actions. Keep
the key, secret, and passphrase on the server.

```python Before theme={null}
import os

from py_builder_relayer_client.client import RelayClient
from py_builder_signing_sdk.config import BuilderConfig
from py_builder_signing_sdk.sdk_types import BuilderApiKeyCreds

builder_config = BuilderConfig(
    local_builder_creds=BuilderApiKeyCreds(
        key=os.environ["POLYMARKET_BUILDER_API_KEY"],
        secret=os.environ["POLYMARKET_BUILDER_SECRET"],
        passphrase=os.environ["POLYMARKET_BUILDER_PASSPHRASE"],
    )
)

relayer = RelayClient(
    "https://relayer-v2.polymarket.com",
    137,
    os.environ["POLYMARKET_PRIVATE_KEY"],
    builder_config,
)
```

```python After theme={null}
import os

from polymarket import AsyncSecureClient, BuilderApiKey

client = await AsyncSecureClient.create(
    private_key=os.environ["POLYMARKET_PRIVATE_KEY"],
    api_key=BuilderApiKey(
        key=os.environ["POLYMARKET_BUILDER_API_KEY"],
        secret=os.environ["POLYMARKET_BUILDER_SECRET"],
        passphrase=os.environ["POLYMARKET_BUILDER_PASSPHRASE"],
    ),
)
```

### Configure Relayer API Keys

`AsyncSecureClient` configures Relayer API keys directly. Pass the key and its
associated address when reconnecting an existing account.

```python theme={null}
import os

from polymarket import AsyncSecureClient, RelayerApiKey

client = await AsyncSecureClient.create(
    private_key=os.environ["POLYMARKET_PRIVATE_KEY"],
    wallet=os.environ["POLYMARKET_WALLET_ADDRESS"],
    api_key=RelayerApiKey(
        key=os.environ["POLYMARKET_RELAYER_API_KEY"],
        address=os.environ["POLYMARKET_RELAYER_API_KEY_ADDRESS"],
    ),
)
```

### Deploy a Deposit Wallet

Creating an `AsyncSecureClient` without a `wallet` derives the signer's Deposit
Wallet address and deploys it when needed. Use Builder authorization to
authorize the deployment.

```python Before theme={null}
deployment = relayer.deploy_deposit_wallet()
deployment.wait()
```

```python After theme={null}
import os

from polymarket import AsyncSecureClient, BuilderApiKey

client = await AsyncSecureClient.create(
    private_key=os.environ["POLYMARKET_PRIVATE_KEY"],
    api_key=BuilderApiKey(
        key=os.environ["POLYMARKET_BUILDER_API_KEY"],
        secret=os.environ["POLYMARKET_BUILDER_SECRET"],
        passphrase=os.environ["POLYMARKET_BUILDER_PASSPHRASE"],
    ),
)

deposit_wallet_address = client.wallet
```

## Market Discovery

### Fetch a Market

Both `AsyncPublicClient` and `AsyncSecureClient` provide `get_market` for reads
by Gamma market ID, slug, or Polymarket URL.

```python Before theme={null}
market = client.get_market("CONDITION_ID")
```

```python After theme={null}
market = await client.get_market(slug="MARKET_SLUG")
```

If you only have a condition ID, filter `list_markets` and fetch its first page.

```python theme={null}
pages = client.list_markets(condition_ids=["CONDITION_ID"])
page = await pages.first_page()
market = page.items[0]
```

### List Markets

Both `AsyncPublicClient` and `AsyncSecureClient` provide `list_markets`, which
returns an async paginator and accepts filters directly.

```python Before theme={null}
page = client.get_markets()
markets = page["data"]
```

```python After theme={null}
pages = client.list_markets(closed=False, page_size=20)
page = await pages.first_page()
markets = page.items
```

Simplified-market reads do not need a separate replacement. Sampling-market
reads migrate to `list_current_rewards`, which lists active reward
configurations.

```python Before theme={null}
markets = client.get_sampling_markets()
page = client.get_sampling_simplified_markets()
```

```python After theme={null}
pages = client.list_current_rewards()
page = await pages.first_page()
```

## Market Data

### Read Trading Parameters

Both `AsyncPublicClient` and `AsyncSecureClient` return tick size and
negative-risk status on the market model. Order methods also resolve them
automatically.

```python Before theme={null}
tick_size = client.get_tick_size("TOKEN_ID")
neg_risk = client.get_neg_risk("TOKEN_ID")
fee_rate_bps = client.get_fee_rate_bps("TOKEN_ID")
```

```python After theme={null}
market = await client.get_market(slug="MARKET_SLUG")
tick_size = market.trading.minimum_tick_size
neg_risk = market.state.neg_risk
fee_schedule = market.trading.fee_schedule
```

### Read CLOB Market Details

Both `AsyncPublicClient` and `AsyncSecureClient` return the typed market model.
Its trading fields replace the compact CLOB market response.

```python Before theme={null}
details = client.get_clob_market_info("CONDITION_ID")
tick_size = details["mts"]
neg_risk = details["nr"]
fee_details = details["fd"]
```

```python After theme={null}
market = await client.get_market(slug="MARKET_SLUG")
tick_size = market.trading.minimum_tick_size
neg_risk = market.state.neg_risk
fee_schedule = market.trading.fee_schedule
```

### Fetch Order Books

Both `AsyncPublicClient` and `AsyncSecureClient` provide single and batch order
book reads.

```python Before theme={null}
from py_clob_client_v2 import BookParams

book = client.get_order_book("TOKEN_ID")
books = client.get_order_books(
    [BookParams(token_id="TOKEN_ID_1"), BookParams(token_id="TOKEN_ID_2")]
)
```

```python After theme={null}
book = await client.get_order_book(asset_id="ASSET_ID")
books = await client.get_order_books(asset_ids=["ASSET_ID_1", "ASSET_ID_2"])
```

### Fetch Prices

Both `AsyncPublicClient` and `AsyncSecureClient` provide single and batch price
reads with typed requests.

```python Before theme={null}
from py_clob_client_v2 import BookParams, Side

price = client.get_price("TOKEN_ID", Side.BUY)
prices = client.get_prices(
    [
        BookParams(token_id="TOKEN_ID_1", side=Side.BUY),
        BookParams(token_id="TOKEN_ID_2", side=Side.SELL),
    ]
)
```

```python After theme={null}
from polymarket import PriceRequest

price = await client.get_price(asset_id="ASSET_ID", side="BUY")
prices = await client.get_prices(
    requests=[
        PriceRequest(asset_id="ASSET_ID_1", side="BUY"),
        PriceRequest(asset_id="ASSET_ID_2", side="SELL"),
    ]
)
```

### Fetch Midpoints

Both `AsyncPublicClient` and `AsyncSecureClient` provide single and batch
midpoint reads.

```python Before theme={null}
from py_clob_client_v2 import BookParams

midpoint = client.get_midpoint("TOKEN_ID")
midpoints = client.get_midpoints(
    [BookParams(token_id="TOKEN_ID_1"), BookParams(token_id="TOKEN_ID_2")]
)
```

```python After theme={null}
midpoint = await client.get_midpoint(asset_id="ASSET_ID")
midpoints = await client.get_midpoints(asset_ids=["ASSET_ID_1", "ASSET_ID_2"])
```

### Fetch Spreads

Both `AsyncPublicClient` and `AsyncSecureClient` provide single and batch spread
reads.

```python Before theme={null}
from py_clob_client_v2 import BookParams

spread = client.get_spread("TOKEN_ID")
spreads = client.get_spreads(
    [BookParams(token_id="TOKEN_ID_1"), BookParams(token_id="TOKEN_ID_2")]
)
```

```python After theme={null}
spread = await client.get_spread(asset_id="ASSET_ID")
spreads = await client.get_spreads(asset_ids=["ASSET_ID_1", "ASSET_ID_2"])
```

### Fetch Last Trade Prices

Both `AsyncPublicClient` and `AsyncSecureClient` provide singular and batch
methods for last-trade prices.

```python Before theme={null}
from py_clob_client_v2 import BookParams

last_trade = client.get_last_trade_price("TOKEN_ID")
last_trades = client.get_last_trades_prices(
    [BookParams(token_id="TOKEN_ID_1"), BookParams(token_id="TOKEN_ID_2")]
)
```

```python After theme={null}
last_trade = await client.get_last_trade_price(asset_id="ASSET_ID")
last_trades = await client.get_last_trade_prices(
    asset_ids=["ASSET_ID_1", "ASSET_ID_2"]
)
```

### Fetch Price History

Both `AsyncPublicClient` and `AsyncSecureClient` provide price history. Pass the
parameters as keyword arguments; the response contains typed points.

```python Before theme={null}
from py_clob_client_v2 import PricesHistoryParams

history = client.get_prices_history(
    PricesHistoryParams(market="TOKEN_ID", interval="1d", fidelity=60)
)
```

```python After theme={null}
history = await client.get_price_history(
    asset_id="ASSET_ID",
    interval="1d",
    fidelity=60,
)
```

### Estimate a Market Order Price

Both `AsyncPublicClient` and `AsyncSecureClient` provide market-order price
estimates. Buys specify collateral spent, while sells specify shares sold.

```python Before theme={null}
from py_clob_client_v2 import OrderType, Side

buy_price = client.calculate_market_price(
    "TOKEN_ID", Side.BUY, 10, OrderType.FOK
)
sell_price = client.calculate_market_price(
    "TOKEN_ID", Side.SELL, 5, OrderType.FOK
)
```

```python After theme={null}
buy_price = await client.estimate_market_price(
    asset_id="ASSET_ID", side="BUY", amount=10, order_type="FOK"
)
sell_price = await client.estimate_market_price(
    asset_id="ASSET_ID", side="SELL", shares=5, order_type="FOK"
)
```

### List Recent Market Trades

Both `AsyncPublicClient` and `AsyncSecureClient` provide the public trade
paginator, which replaces the previous market-events response.

```python Before theme={null}
trades = client.get_market_trades_events("CONDITION_ID")
```

```python After theme={null}
pages = client.list_trades(market=["CONDITION_ID"])
page = await pages.first_page()
trades = page.items
```

## Orders

### Place a Limit Order

`AsyncSecureClient` resolves tick size, negative-risk status, fees, and signing
details before submitting a limit order.

```python Before theme={null}
from py_clob_client_v2 import OrderArgs, Side

response = client.create_and_post_order(
    OrderArgs(
        token_id="TOKEN_ID",
        price=0.52,
        size=10,
        side=Side.BUY,
    )
)
```

```python After theme={null}
response = await client.place_limit_order(
    asset_id="ASSET_ID",
    price=0.52,
    size=10,
    side="BUY",
)
```

### Place a Market Order

`AsyncSecureClient` places market orders. Buys specify collateral to spend,
while sells specify shares to sell.

```python Before theme={null}
from py_clob_client_v2 import MarketOrderArgs, OrderType, Side

response = client.create_and_post_market_order(
    MarketOrderArgs(
        token_id="TOKEN_ID",
        amount=10,
        user_usdc_balance=10,
        side=Side.BUY,
    ),
    order_type=OrderType.FOK,
)
```

```python After theme={null}
response = await client.place_market_order(
    asset_id="ASSET_ID",
    side="BUY",
    amount=10,
    max_spend=10,
    order_type="FOK",
)
```

`user_usdc_balance` becomes `max_spend`. The previous field supplied the
account balance used to adjust the order for fees; the unified SDK instead
accepts the maximum total USD to spend. Set `max_spend` equal to `amount` when
the amount should include fees, or omit it to pay applicable fees on top.

### Sign Without Posting

`AsyncSecureClient` provides order-type-specific creation methods when signing
and submission need to happen separately.

```python Before theme={null}
from py_clob_client_v2 import MarketOrderArgs, OrderArgs, Side

limit_order = client.create_order(
    OrderArgs(token_id="TOKEN_ID", price=0.52, size=10, side=Side.BUY)
)
market_order = client.create_market_order(
    MarketOrderArgs(token_id="TOKEN_ID", amount=10, side=Side.BUY)
)
```

```python After theme={null}
limit_order = await client.create_limit_order(
    asset_id="ASSET_ID",
    price=0.52,
    size=10,
    side="BUY",
)
market_order = await client.create_market_order(
    asset_id="ASSET_ID",
    side="BUY",
    amount=10,
)
```

### Post Several Orders

`AsyncSecureClient` provides `post_orders`. Order type and post-only behavior
are part of each signed order, so the method accepts signed orders directly.

```python Before theme={null}
from py_clob_client_v2 import OrderType, PostOrdersV2Args

responses = client.post_orders(
    [
        PostOrdersV2Args(order=first_order, orderType=OrderType.GTC),
        PostOrdersV2Args(order=second_order, orderType=OrderType.GTC),
    ]
)
```

```python After theme={null}
responses = await client.post_orders([first_order, second_order])
```

### Attribute an Order to a Builder

`AsyncSecureClient` attaches the builder code to each order.

```python Before theme={null}
from py_clob_client_v2 import OrderArgs, Side

response = client.create_and_post_order(
    OrderArgs(
        token_id="TOKEN_ID",
        price=0.52,
        size=10,
        side=Side.BUY,
        builder_code="BUILDER_CODE",
    )
)
```

```python After theme={null}
response = await client.place_limit_order(
    asset_id="ASSET_ID",
    price=0.52,
    size=10,
    side="BUY",
    builder_code="BUILDER_CODE",
)
```

### Cancel Orders

`AsyncSecureClient` provides explicit methods for cancelling one order,
several orders, all orders, or orders for a market.

```python Before theme={null}
from py_clob_client_v2 import OrderMarketCancelParams, OrderPayload

client.cancel_order(OrderPayload(orderID="ORDER_ID"))
client.cancel_orders(["ORDER_ID_1", "ORDER_ID_2"])
client.cancel_market_orders(OrderMarketCancelParams(market="CONDITION_ID"))
client.cancel_all()
```

```python After theme={null}
await client.cancel_order(order_id="ORDER_ID")
await client.cancel_orders(order_ids=["ORDER_ID_1", "ORDER_ID_2"])
await client.cancel_market_orders(market="CONDITION_ID")
await client.cancel_all()
```

### Fetch an Order

`AsyncSecureClient` fetches an order by ID using a keyword argument.

```python Before theme={null}
order = client.get_order("ORDER_ID")
```

```python After theme={null}
order = await client.get_order(order_id="ORDER_ID")
```

### List Open Orders

`AsyncSecureClient` provides `list_open_orders`, which returns an async
paginator.

```python Before theme={null}
from py_clob_client_v2 import OpenOrderParams

orders = client.get_open_orders(
    OpenOrderParams(market="CONDITION_ID", asset_id="TOKEN_ID")
)
```

```python After theme={null}
pages = client.list_open_orders(market="CONDITION_ID", asset_id="ASSET_ID")
orders = [order async for order in pages.iter_items()]
```

### Check Order Scoring

`AsyncSecureClient` provides `get_order_scoring` for one order and
`get_orders_scoring` for several.

```python Before theme={null}
from py_clob_client_v2 import OrderScoringParams, OrdersScoringParams

scoring = client.is_order_scoring(OrderScoringParams(orderId="ORDER_ID"))
batch = client.are_orders_scoring(
    OrdersScoringParams(orderIds=["ORDER_ID_1", "ORDER_ID_2"])
)
```

```python After theme={null}
scoring = await client.get_order_scoring(order_id="ORDER_ID")
batch = await client.get_orders_scoring(
    order_ids=["ORDER_ID_1", "ORDER_ID_2"]
)
```

## Account Activity and Balances

### List Account Trades

`AsyncSecureClient` replaces both previous account trade-history methods with one
async paginator.

```python Before theme={null}
from py_clob_client_v2 import TradeParams

trades = client.get_trades(TradeParams(market="CONDITION_ID"))
page = client.get_trades_paginated(TradeParams(market="CONDITION_ID"))
```

```python After theme={null}
pages = client.list_account_trades(market="CONDITION_ID")
first_page = await pages.first_page()

trades = [trade async for trade in pages.iter_items()]
```

### List Builder Trades

Both `AsyncPublicClient` and `AsyncSecureClient` provide public builder trade
history, filtered by builder code.

```python Before theme={null}
from py_clob_client_v2 import BuilderTradeParams

page = client.get_builder_trades(
    BuilderTradeParams(builder_code="BUILDER_CODE")
)
trades = page["trades"]
```

```python After theme={null}
pages = client.list_builder_trades(builder_code="BUILDER_CODE")
page = await pages.first_page()
trades = page.items
```

### Read and Drop Notifications

`AsyncSecureClient` provides notification methods with keyword arguments and
typed responses.

```python Before theme={null}
from py_clob_client_v2 import DropNotificationParams

notifications = client.get_notifications()
client.drop_notifications(DropNotificationParams(ids=[1, 2]))
```

```python After theme={null}
notifications = await client.get_notifications()
await client.drop_notifications(ids=["1", "2"])
```

### Refresh Balances and Allowances

`AsyncSecureClient` reads balances and manages missing allowances while placing
orders. It completes the required approval, refreshes the allowance, and
retries the order.

```python Before theme={null}
from py_clob_client_v2 import AssetType, BalanceAllowanceParams

params = BalanceAllowanceParams(asset_type=AssetType.COLLATERAL)
client.update_balance_allowance(params)
balance = client.get_balance_allowance(params)
```

```python After theme={null}
balance = await client.get_balance_allowance(asset_type="COLLATERAL")
response = await client.place_limit_order(
    asset_id="ASSET_ID",
    price=0.52,
    size=10,
    side="BUY",
)
```

## Positions

The unified methods build and submit wallet transactions. You no longer need to
encode contract calls or pass transaction arrays to `execute`.

### Split a Position

`AsyncSecureClient` splits collateral into a complete set of YES and NO outcome
tokens.

```python Before theme={null}
from py_builder_relayer_client.models import Transaction

split_tx = Transaction(
    to=CTF_COLLATERAL_ADAPTER_ADDRESS,
    data=collateral_adapter.encode_abi(
        "splitPosition",
        args=[PUSD_ADDRESS, bytes(32), CONDITION_ID, [1, 2], 1_000_000],
    ),
    value="0",
)

split = relayer.execute([split_tx], "Split position")
split.wait()
```

```python After theme={null}
split = await client.split_position(
    condition_id="CONDITION_ID",
    amount=1_000_000,
)
await split.wait()
```

### Merge Positions

`AsyncSecureClient` merges balanced YES and NO tokens back into collateral.

```python Before theme={null}
from py_builder_relayer_client.models import Transaction

merge_tx = Transaction(
    to=CTF_COLLATERAL_ADAPTER_ADDRESS,
    data=collateral_adapter.encode_abi(
        "mergePositions",
        args=[PUSD_ADDRESS, bytes(32), CONDITION_ID, [1, 2], 1_000_000],
    ),
    value="0",
)

merge = relayer.execute([merge_tx], "Merge positions")
merge.wait()
```

```python After theme={null}
merge = await client.merge_positions(
    condition_id="CONDITION_ID",
    amount="max",
)
await merge.wait()
```

### Redeem Resolved Positions

`AsyncSecureClient` redeems winning outcome tokens for collateral after
resolution.

```python Before theme={null}
from py_builder_relayer_client.models import Transaction

redeem_tx = Transaction(
    to=CTF_COLLATERAL_ADAPTER_ADDRESS,
    data=collateral_adapter.encode_abi(
        "redeemPositions",
        args=[PUSD_ADDRESS, bytes(32), CONDITION_ID, [1, 2]],
    ),
    value="0",
)

redeem = relayer.execute([redeem_tx], "Redeem positions")
redeem.wait()
```

```python After theme={null}
redeem = await client.redeem_positions(condition_id="CONDITION_ID")
await redeem.wait()
```

## Service Status

Neither `AsyncPublicClient` nor `AsyncSecureClient` requires these calls. The
unified clients manage request timing internally.

```python Before theme={null}
client.get_ok()
timestamp = client.get_server_time()
```

```python After theme={null}
# No client call is required for request timestamp synchronization.
```

**Rust**

A unified Rust SDK is in progress. Until it is available, use
`polymarket_client_sdk_v2` `0.7.0`, the current Rust SDK.

See the [GitHub repository](https://github.com/Polymarket/rs-clob-client-v2) and
the [`polymarket_client_sdk_v2` package on crates.io](https://crates.io/crates/polymarket_client_sdk_v2)
for the complete API and examples.

## Install the Rust SDK

Enable the `clob` feature for authentication and trading:

```bash theme={null}
cargo add polymarket_client_sdk_v2@0.7.0 --features clob
```

## Trade From a Deposit Wallet

The Rust SDK supports the CLOB order path for an existing Deposit Wallet. It
does not include a client for deploying Deposit Wallets or submitting wallet
batches; use the Direct API workflows for those actions.

Pass the deployed Deposit Wallet as the funder and use
`SignatureType::Poly1271` when authenticating. This example refreshes the
collateral allowance cache, then places a GTC limit buy:

```rust theme={null}
use std::str::FromStr as _;

use alloy::signers::Signer as _;
use alloy::signers::local::LocalSigner;
use polymarket_client_sdk_v2::clob::types::request::UpdateBalanceAllowanceRequest;
use polymarket_client_sdk_v2::clob::types::{
    AssetType, OrderType, Side, SignatureType,
};
use polymarket_client_sdk_v2::clob::{Client, Config};
use polymarket_client_sdk_v2::types::{Address, Decimal, U256};
use polymarket_client_sdk_v2::{POLYGON, PRIVATE_KEY_VAR};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let host = "https://clob-v2.polymarket.com";
    let signer = LocalSigner::from_str(&std::env::var(PRIVATE_KEY_VAR)?)?
        .with_chain_id(Some(POLYGON));
    let deposit_wallet = Address::from_str(&std::env::var("DEPOSIT_WALLET")?)?;

    let client = Client::new(host, Config::default())?
        .authentication_builder(&signer)
        .funder(deposit_wallet)
        .signature_type(SignatureType::Poly1271)
        .authenticate()
        .await?;

    client
        .update_balance_allowance(
            UpdateBalanceAllowanceRequest::builder()
                .asset_type(AssetType::Collateral)
                .build(),
        )
        .await?;

    let response = client
        .limit_order()
        .token_id(U256::from_str(&std::env::var("TOKEN_ID")?)?)
        .side(Side::Buy)
        .price(Decimal::from_str("0.40")?)
        .size(Decimal::from_str("100")?)
        .order_type(OrderType::GTC)
        .build_sign_and_post(&signer)
        .await?;

    println!("order_id={} status={}", response.order_id, response.status);
    Ok(())
}
```

## Handle Matching Engine Restarts

Rebuild and re-sign an order before each retry because `SignedOrder` is
consumed when it is submitted. Treat HTTP `425` as temporary and retry with
exponential backoff:

```rust theme={null}
use polymarket_client_sdk_v2::error::{Kind, StatusCode};

let mut delay = std::time::Duration::from_secs(1);

for _ in 0..10 {
    let order = client.limit_order()
        .token_id(token_id).price(price).size(size).side(side)
        .build().await?;
    let signed = client.sign(&signer, order).await?;

    match client.post_order(signed).await {
        Ok(response) => return Ok(response),
        Err(err) if err.kind() == Kind::Status => {
            if let Some(status) = err.downcast_ref::<polymarket_client_sdk_v2::error::Status>() {
                if status.status_code == StatusCode::from_u16(425).unwrap() {
                    eprintln!("Engine restarting, retrying in {delay:?}...");
                    tokio::time::sleep(delay).await;
                    delay = (delay * 2).min(std::time::Duration::from_secs(30));
                    continue;
                }
            }
            return Err(err);
        }
        Err(err) => return Err(err),
    }
}
```

See [Matching Engine Restarts](/trading/matching-engine) for the restart window,
post-only period, and restricted-mode responses.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.