Skip to main content
If you’ve built bots or agents on Polymarket, this guide maps every concept, endpoint, and code pattern to the Limitless equivalents so you can port your code in minutes.

What changed

PolymarketLimitless
ChainPolygon (137)Base (8453)
CollateralUSDC.eUSDC (6 decimals)
REST hostsgamma-api.polymarket.com (data) + clob.polymarket.com (trading)api.limitless.exchange (unified)
WebSocketwss://ws-subscriptions-clob.polymarket.comwss://ws.limitless.exchange
Auth modelL1/L2 — derive API creds with EIP-712, sign every request with HMACSingle API key in X-API-Key header
SDKspy-clob-client, @polymarket/clob-client, polymarket-client-sdk (Rust)Python SDK, TypeScript SDK, or direct REST
Wallet typesEOA, Proxy, Gnosis SafeEOA
Market lookupcondition_id or clobTokenIdsslug or address
Token IDsclobTokenIds[0] = Yes, [1] = NopositionIds[0] = Yes, [1] = No
Order signingEIP-712 verifyingContract = CTF ExchangeEIP-712 verifyingContract = venue.exchange
Neg-riskPass negRisk flag when creating ordersHandled via venue system — extra approval to venue.adapter for SELL

Authentication

Polymarket requires deriving API credentials (apiKey, secret, passphrase) through an L1 EIP-712 handshake, then signing every request with HMAC-SHA256 across 5 POLY_* headers. Limitless uses a single API key generated in the UI.
from py_clob_client.client import ClobClient

client = ClobClient(
    "https://clob.polymarket.com",
    key=private_key,
    chain_id=137,
)
creds = client.create_or_derive_api_creds()

client = ClobClient(
    "https://clob.polymarket.com",
    key=private_key,
    chain_id=137,
    creds=creds,
    signature_type=0,
    funder=wallet_address,
)
No HMAC signing, no credential derivation, no POLY_* headers.

Endpoint mapping

Market data

ActionPolymarketLimitless
List active marketsGET gamma-api.polymarket.com/markets?active=trueGET /markets/active
Get market by slugGET gamma-api.polymarket.com/markets?slug=...GET /markets/:slug
Search marketsGET gamma-api.polymarket.com/markets?tag=...GET /markets/search?query=...
OrderbookGET clob.polymarket.com/book?token_id=...GET /markets/:slug/orderbook
Price historyGET gamma-api.polymarket.com/markets/:id/prices-historyGET /markets/:slug/historical-price
Midpoint priceGET clob.polymarket.com/midpoint?token_id=...Compute from orderbook response

Trading

ActionPolymarketLimitless
Place orderPOST clob.polymarket.com/orderPOST /orders
Cancel orderDELETE clob.polymarket.com/order/:idDELETE /orders/:orderId
Cancel multipleDELETE clob.polymarket.com/cancel-orders (up to 3000)POST /orders/cancel-batch
Cancel allDELETE clob.polymarket.com/cancel-allDELETE /orders/all/:slug
Get open ordersGET clob.polymarket.com/ordersGET /markets/:slug/user-orders
Get order by IDGET clob.polymarket.com/order/:idPOST /orders/status/batch

Portfolio

ActionPolymarketLimitless
Get positionsGET clob.polymarket.com/positionsGET /portfolio/positions
Get tradesGET clob.polymarket.com/tradesGET /portfolio/trades
PnL chartN/AGET /portfolio/pnl-chart
Trade historyGET gamma-api.polymarket.com/activityGET /portfolio/history

Fetch a market

# Two separate APIs: Gamma for metadata, CLOB for trading
market = requests.get(
    "https://gamma-api.polymarket.com/markets",
    params={"slug": "will-trump-win"}
).json()[0]

token_id = market["clobTokenIds"][0]   # Yes token
condition_id = market["conditionId"]
neg_risk = market["negRisk"]
tick_size = market["minimum_tick_size"]

Build and sign an order

The order structure is almost identical — both use EIP-712 typed data with the same field names. Key differences:
FieldPolymarketLimitless
chainId137 (Polygon)8453 (Base)
verifyingContractCTF Exchange addressvenue.exchange from market data
name (EIP-712 domain)"Polymarket CTF Exchange""Limitless CTF Exchange"
tokenId sourceclobTokenIds[0|1]positionIds[0|1]
from py_clob_client.order_builder.constants import BUY

order = client.create_and_post_order(
    OrderArgs(
        token_id=token_id,
        price=0.50,
        size=10,
        side=BUY,
        order_type=OrderType.GTC,
    ),
    options={"tick_size": "0.01", "neg_risk": False},
)
ownerId is your Limitless profile ID — a required field on every POST /orders request. You can find it in the Limitless UI or from your first authenticated API response. Polymarket’s SDK handles this internally; on Limitless you pass it explicitly.
If you use the Python SDK or TypeScript SDK, order building and signing are handled for you — similar to how py-clob-client works on Polymarket.

Porting a Polymarket agent

If you’re adapting an agent built with the Polymarket/agents framework, here’s a checklist:
1

Swap credentials

Replace POLYGON_WALLET_PRIVATE_KEY with your existing private key on Base. Add API_KEY with your lmts_ key. Remove any HMAC credential derivation code.
2

Update base URLs

Replace both gamma-api.polymarket.com and clob.polymarket.com with api.limitless.exchange.
3

Change chain ID

Update chainId from 137 to 8453 in all EIP-712 domain definitions.
4

Update EIP-712 domain name

Change "Polymarket CTF Exchange" to "Limitless CTF Exchange".
5

Swap token ID fields

Replace clobTokenIds lookups with positionIds. The index convention is the same: [0] = Yes, [1] = No.
6

Use venue addresses

Fetch venue.exchange from GET /markets/:slug and use it as verifyingContract. On Polymarket you may have hardcoded the CTF Exchange address — on Limitless each market can have its own venue.
7

Remove Polymarket-specific params

Drop tick_size, neg_risk, funder, and signature_type from order construction. These are either not needed or handled by the venue system.
8

Add ownerId to order submissions

POST /orders requires an ownerId field (your Limitless profile ID). Polymarket’s SDK handles this internally; on Limitless you pass it explicitly in every order payload alongside order, orderType, and marketSlug.
9

Update approvals

Approve USDC on Base (not Polygon) to venue.exchange. For NegRisk SELL orders, also approve Conditional Tokens to venue.adapter. See venue system.

WebSocket

PolymarketLimitless
URLwss://ws-subscriptions-clob.polymarket.com/ws/...wss://ws.limitless.exchange
NamespaceChannel-based (market, user)Socket.IO namespace /markets
AuthAPI key in connection paramsX-API-Key header during handshake
See WebSocket events for the full event reference.

Rate limits

PolymarketLimitless
Concurrent requestsVaries by builder tier2
Minimum delayVaries300 ms between requests

Quick reference for agents

If you’re building an LLM-powered agent or bot, here’s the minimal flow:
import os, time, requests
from eth_account import Account
from eth_account.messages import encode_typed_data
from web3 import Web3

API = "https://api.limitless.exchange"
KEY = os.environ["API_KEY"]           # lmts_...
PK  = os.environ["PRIVATE_KEY"]      # 0x...
OWNER_ID = int(os.environ["OWNER_ID"])  # Profile ID from the Limitless UI
H   = {"X-API-Key": KEY, "Content-Type": "application/json"}

CHAIN_ID = 8453
ZERO_ADDR = "0x0000000000000000000000000000000000000000"
ORDER_TYPES = {
    "EIP712Domain": [
        {"name": "name", "type": "string"},
        {"name": "version", "type": "string"},
        {"name": "chainId", "type": "uint256"},
        {"name": "verifyingContract", "type": "address"},
    ],
    "Order": [
        {"name": "salt", "type": "uint256"},
        {"name": "maker", "type": "address"},
        {"name": "signer", "type": "address"},
        {"name": "taker", "type": "address"},
        {"name": "tokenId", "type": "uint256"},
        {"name": "makerAmount", "type": "uint256"},
        {"name": "takerAmount", "type": "uint256"},
        {"name": "expiration", "type": "uint256"},
        {"name": "nonce", "type": "uint256"},
        {"name": "feeRateBps", "type": "uint256"},
        {"name": "side", "type": "uint8"},
        {"name": "signatureType", "type": "uint8"},
    ],
}

# 1. Find a market
markets = requests.get(f"{API}/markets/active", headers=H).json()
slug = markets[0]["slug"]

# 2. Get venue + token IDs (cache per market — these are static)
market = requests.get(f"{API}/markets/{slug}", headers=H).json()
venue_exchange = market["venue"]["exchange"]
yes_token = market["positionIds"][0]

# 3. Build order (BUY 10 YES shares at $0.50)
acct = Account.from_key(PK)
order = {
    "salt": int(time.time() * 1000),
    "maker": Web3.to_checksum_address(acct.address),
    "signer": Web3.to_checksum_address(acct.address),
    "taker": ZERO_ADDR,
    "tokenId": yes_token,
    "makerAmount": 5_000_000,   # 0.50 * 10 * 1e6
    "takerAmount": 10_000_000,  # 10 * 1e6
    "expiration": 0,
    "nonce": 0,
    "feeRateBps": 0,
    "side": 0,
    "signatureType": 0,
}

# 4. Sign (EIP-712) — same encode_typed_data pattern as Polymarket CTF
encoded = encode_typed_data({
    "types": ORDER_TYPES,
    "primaryType": "Order",
    "domain": {
        "name": "Limitless CTF Exchange",
        "version": "1",
        "chainId": CHAIN_ID,
        "verifyingContract": Web3.to_checksum_address(venue_exchange),
    },
    "message": order,
})
sig = Account.sign_message(encoded, private_key=PK).signature.hex()

# 5. Submit
resp = requests.post(f"{API}/orders", headers=H, json={
    "order": {**order, "signature": sig},
    "ownerId": OWNER_ID,
    "orderType": "GTC",
    "marketSlug": slug,
})
print(resp.json())

Next steps