Read Polymarket odds programmatically (no CLOB)

Every fact below was tested end-to-end on 2026-07-11. If you want live prediction-market odds without running the order-book client, the public gamma-api is all you need — but it has three traps.

1. The endpoint

GET https://gamma-api.polymarket.com/markets?closed=false&active=true&order=volume24hr&ascending=false&limit=120

No API key, no wallet, no signing. Returns an array of market objects with question, outcomes, outcomePrices, volume24hr, liquidity, endDate, slug.

2. Trap: the ordering leaks resolved markets

order=volume24hr with closed=false&active=true still returns already-resolved / expired markets near the top. You must filter client-side: drop any row where Date.parse(m.endDate) < Date.now(). Skip this and your "top markets" list is full of dead events.

3. Trap: outcomes and prices are JSON strings

m.outcomes and m.outcomePrices are stringified JSON arrays, not native arrays:

outcomes:      "[\"Yes\",\"No\"]"
outcomePrices: "[\"0.2115\",\"0.7885\"]"

JSON.parse() both, then zip by index. The price is already a probability: price * 100 = implied %. On a binary market the two prices sum to ~1.0 by construction, so there is no intra-market arbitrage — don't waste time looking for it.

4. Finding a user's deposit wallet (the "DW" proxy)

Polymarket holds a user's USDC.e and ERC-1155 positions in a proxy, not their signing EOA. The data-api (/value, /positions) is keyed by the proxy address, so querying the owner EOA returns zeros. Two proxy types on Polygon:

Collateral is USDC.e 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174 on Polygon (chainId 137). If the Safe address has no deployed code, the account was never funded — Polymarket deploys the Safe on first deposit.

5. clob-client v5 wants a viem signer, not ethers v6

If you do place orders: @polymarket/clob-client v5.x throws "wallet client is missing account address" when handed an ethers v6 Wallet. Cause: ethers v6 renamed _signTypedData → signTypedData, so the client mis-detects it as a viem walletClient and looks for .account.address. Fix — pass a real viem client:

import { createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { polygon } from 'viem/chains';
const account = privateKeyToAccount(PK);
const wc = createWalletClient({ account, chain: polygon, transport: http(RPC) });
new ClobClient(host, 137, wc, creds);   // works
Don't want to run any of this? This site exposes it as a live x402 endpoint: GET /svc/polymarket?mode=contested&limit=5 returns ranked markets with implied %, favorite outcome, a contested flag (leader <65% = still tradeable) and days-to-resolve. Free trial, pay-per-call in USDC on Base. See the service catalog.

Services · Knowledge base · x402 discovery guide