API · Troubleshooting

Most Polymarket API errors have a one-line cause and a one-line fix — but the answers are scattered across GitHub issues. This page collects the errors developers actually hit on CLOB V2 / pUSD, with the cause, a minimal reproduction, and the fix in Python and Rust. Paste your error below to jump straight to it.

First, the #1 root cause in 2026: you're still on the V1 SDK. The old py-clob-client (latest 0.34.6) and @polymarket/clob-client are archived / superseded and produce orders the V2 exchange rejects. Move to py-clob-client-v2 (Python), @polymarket/clob-client-v2 (Node) or the official Rust client polymarket_client_sdk_v2. New projects can use the unified beta SDKs (polymarket-client / @polymarket/client).

order_version_mismatch

Cause. You signed a V1-shaped order (old EIP-712 Exchange domain version "1", legacy fields) and posted it to the V2 exchange (domain version "2"). On 28 April 2026 the order struct changed: nonce, feeRateBps, taker and expiration were removed from the signed struct and timestamp, metadata and builder were added. Almost always this means you are still importing the V1 client.

Fix. Switch to the V2 SDK — it builds and signs the V2 struct for you.

pip install py-clob-client-v2          # V1 py-clob-client (0.34.x) is archived
from py_clob_client_v2 import ClobClient
client.create_and_post_order(order_args)   # signs the V2 struct, domain "2"
// Cargo.toml: polymarket_client_sdk_v2 = "0.5"   (official, repo rs-clob-client-v2)
use polymarket_client_sdk_v2::ClobClient;

Related: invalid signature, migrate v1 → v2.

not enough balance / allowance

Cause. Under V2 your funding wallet must approve the V2 exchange contracts to move your collateral and outcome tokens — and your collateral must be pUSD, not USDC.e. A buy needs a pUSD allowance; a sell needs a CTF (ERC-1155) approval. Missing either returns this error.

Fix. (1) Wrap USDC.e → pUSD, then (2) approve pUSD and the conditional tokens to the three V2 contracts:

Approve to all three V2 contracts
  • CTF Exchange (V2) — 0xE111180000d2663C0091e4f400237545B87B996B
  • Neg Risk CTF Exchange — 0xe2222d279d744050d28e00520010520000310F59
  • Neg Risk Adapter — 0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296
pUSD token: 0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB · Conditional Tokens (CTF): 0x4D97DCd97eC945f40cF65F87097ACe5EA0476045

Website users are auto-wrapped after a one-time approval; API-only traders call CollateralOnramp.wrap() (0x93070a847efEf7F70739046A929D47a521F5B8ee) themselves.

maker address not allowed, please use the deposit wallet flow

Cause. You're signing with a POLY_1271 deposit wallet (signature type 3). As of June 2026 the Python (py-clob-client-v2) and TypeScript (@polymarket/clob-client-v2) clients have an open bug: L1 auth binds the API key to your EOA instead of the deposit wallet, so the exchange rejects the order.

Fix. For deposit-wallet (type 3) trading today, use the official Rust client, which wraps the EIP-1271 signature correctly:

// Rust — authentication_builder().funder(deposit_wallet).signature_type(SignatureType::Poly1271)

Workaround without Rust: sign up via email/Magic, export the Magic wallet key and use signature_type = POLY_PROXY (type 2) — it works but doesn't scale to many bots. This is a moving bug — re-check Polymarket issues #70 (Python) and #65 (TS) for a fix.

the order signer address has to be the address of the API KEY

Cause. The wallet that signed the order doesn't match the wallet your API key was derived for, or you didn't pass the right funder/signature type. Common with proxy and Gnosis-Safe wallets when the signing key differs from the fund-holding address.

Fix. Derive the API key for the same wallet you sign with, and pass both the private key and the funder address with the correct signature_type (1 = email/Magic proxy, 2 = Gnosis Safe, 3 = deposit wallet).

invalid signature

Cause. Usually one of: (a) signing the wrong EIP-712 domain — the V2 Exchange domain version is "2" (the L1 ClobAuth domain stays "1"); (b) clock drift > ~60s between your machine and the server; (c) a V1 client (see order_version_mismatch).

Fix. Use the V2 SDK so the domain/struct are correct, and sync your clock (NTP).

401 / invalid api key / PolyApiException

Cause. Missing or wrong L2 credentials (API key/secret/passphrase), or you never created them. Reading market data is keyless — this only affects authenticated calls (orders, your positions).

Fix. Create or derive your API credentials, then pass all three on authenticated requests:

# client.create_or_derive_api_key()  -> api_key, api_secret, api_passphrase

INVALID_ORDER_MIN_TICK_SIZE

Cause. Your price isn't a multiple of the market's tick size (often 0.01, sometimes 0.001).

Fix. Fetch the market's tick size (GET /tick-size) and round your price to it before signing.

FOK_ORDER_NOT_FILLED

Cause. A Fill-Or-Kill order couldn't be filled completely at your price against current resting liquidity, so it was killed (this is FOK working as intended, not a failure).

Fix. Read the book first and size to available depth, widen your price, or use GTC/FAK instead of FOK.

invalid amounts (decimals)

Cause. Amounts must respect decimal precision — maker amount to 2 decimals, taker amount to 4 decimals. Extra precision is rejected.

Fix. Round/quantize before signing; let the V2 SDK compute amounts from price × size.

Size lower than the minimum: 5

Cause. Orders below the minimum share size (5) are rejected.

Fix. Increase order size to ≥ 5 shares.

429 / throttled

Cause. You exceeded a sliding-window rate limit. V2 limits are high (CLOB ~9,000 / 10s; /book,/price 1,500 / 10s; Gamma 4,000 / 10s; Data 1,000 / 10s) and over-limit requests are throttled/queued, not hard-rejected — but a client-side limiter is still wise.

Fix. Add a token-bucket limiter and exponential backoff on 429.

Still stuck? Confirm you're on the V2 SDK, your collateral is pUSD, and all three V2 contracts are approved. Then check Authentication & wallets and the v1 → v2 migration.

Next: Authentication & wallets · CLOB API reference · API quickstart.