In het kort

Polymarket biedt drie publieke API's (een API is een manier waarop programma's automatisch gegevens kunnen lezen of trades kunnen plaatsen): CLOB (handelen), Gamma (markten ontdekken) en Data (analytics). De officiële Python-SDK is py-clob-client 0.34.6. Authenticatie gebruikt een API-sleutel + ECDSA-handtekening, en orders worden via EIP-712 ondertekend met een Polygon proxy wallet. Door rate limits kun je per sleutel ongeveer maximaal 60 orders per minuut plaatsen. De grootste valkuil voor nieuwe ontwikkelaars is het condition_id → token_id-koppelingsprobleem tussen Gamma en CLOB. Los dat eerst op, dan wordt de rest een stuk eenvoudiger. Op Polymarket wordt ongeveer 40 miljoen dollar per maand verdiend aan liquiditeitsbeloningen en spread die bots binnenhalen, vrijwel volledig door API-gebruikers.

Deel 1: de drie API's

Polymarket verdeelt het werk netjes over drie afzonderlijke services. Door voor elke taak de juiste API te gebruiken, blijft je bot snel en eenvoudig en overschrijd je de rate limits niet.

APIBase URLPurposeAuth Required
CLOB APIclob.polymarket.comOrders plaatsen, annuleren en volgen. Orderboeken lezen. Posities opvragen.Yes (voor handelen)
Gamma APIgamma-api.polymarket.comMarkten bekijken, metadata, afbeeldingen, outcome-prijzen, volume, vervaldatum en tags ophalen.No (publiek)
Data APIdata-api.polymarket.comHistorische trades, momentopnamen van posities, gebruikersanalytics en leaderboardgegevens.No (publiek)

Een typische botloop gebruikt Gamma om markten te vinden, CLOB om orderboeken op te halen en trades te plaatsen, en Data om de prestaties van strategieën offline te backtesten. Zie Gamma als de "catalogus", CLOB als de "beurs" en Data als het "datawarehouse".

Deel 2: authenticatie en het proxywalletmodel

Polymarket ondertekent trades niet met de privésleutel van je hoofdwallet. In plaats daarvan gebruikt het een Gnosis Safe-achtige proxy wallet. Je hoofdwallet autoriseert een proxy, en die proxy voert alle trades uit op Polygon. Je API-bot communiceert met die proxy.

Wat je nodig hebt

  • API-sleutel - genereer die in Polymarket Settings → Developer
  • Privésleutel - de sleutel van je trading wallet (NIET de seed phrase van je hoofd-MetaMask)
  • funder-adres - het adres van je proxy wallet (te zien in Settings → Wallet)
  • Chain ID - 137 (Polygon mainnet)
  • Signature type - 1 (POLY_PROXY, standaard voor particuliere gebruikers)

Deel 3: py-clob-client installeren

De officiële Python SDK is de snelste manier om vanaf nul je eerste order te plaatsen. We gebruiken versie 0.34.6: de huidige release op PyPI (februari 2026) en de versie waarop vrijwel elke live bot draait.

# Create a virtual environment first
python3 -m venv venv
source venv/bin/activate   # macOS/Linux
venv\Scripts\activate      # Windows

# Install the SDK
pip install py-clob-client==0.34.6 requests websocket-client python-dotenv

Basisconfiguratie van de client

import os
from dotenv import load_dotenv
from py_clob_client.client import ClobClient
from py_clob_client.constants import POLYGON

load_dotenv()

client = ClobClient(
    host="https://clob.polymarket.com",
    key=os.environ["POLY_PRIVATE_KEY"],
    chain_id=POLYGON,          # 137
    signature_type=1,          # POLY_PROXY
    funder=os.environ["POLY_FUNDER"],
)

# One-time: derive and cache API credentials
client.set_api_creds(client.create_or_derive_api_creds())

De aanroep create_or_derive_api_creds() ondertekent een bericht met je private key. Daarmee krijg je een API key, secret en passphrase terug. Sla deze na de eerste run op in je .env, zodat je het derive-endpoint niet bij elke start opnieuw aanroept.

Deel 4: Markten ontdekken via Gamma

Voordat je kunt handelen, moet je markten vinden die interessant genoeg zijn. Gamma retourneert JSON met alles wat de Polymarket UI toont: de vraag, uitkomsten, prijzen, 24-uursvolume, einddatum, tags en afbeeldingen.

import requests

resp = requests.get(
    "https://gamma-api.polymarket.com/markets",
    params={
        "active": "true",
        "closed": "false",
        "tag_slug": "politics",
        "limit": 20,
        "order": "volume24hr",
        "ascending": "false",
    },
    timeout=10,
)
resp.raise_for_status()
markets = resp.json()

for m in markets:
    print(f"{m['slug']:50} Yes ${float(m['outcomePrices'][0]):.3f}  Vol24h ${m.get('volume24hr', 0):,.0f}")

Nuttige queryparameters voor Gamma

ParameterWhat it does
tag_slugFilter op categorie (politics, sports, crypto, culture, enzovoort)
active=trueAlleen markten die momenteel orders accepteren
closed=falseVerberg afgehandelde markten
order=volume24hrSorteer op recent volume (liquiditeitssignaal)
end_date_minISO-datum - sla markten over die te snel worden beslist
limitMaximaal 500 per pagina (gebruik offset voor paginering)

Deel 5: De mapping van condition_id naar token_id

Dit is het grootste struikelblok bij het bouwen van Polymarket-bots. Gamma retourneert een condition_id (één per markt). CLOB-trades gebruiken een token_id (één per uitkomst). Je hebt altijd beide nodig.

# Each Gamma market object contains 'clobTokenIds' - a JSON string array
import json

market = markets[0]
token_ids = json.loads(market['clobTokenIds'])   # ['7410...', '1120...']
yes_token = token_ids[0]   # First outcome
no_token  = token_ids[1]   # Second outcome

# Alternative: ask CLOB directly using condition_id
info = client.get_market(condition_id=market['conditionId'])
yes_token = info['tokens'][0]['token_id']

Valkuil bij de volgorde van uitkomsten

De array outcomes van Gamma en de array clobTokenIds zijn op index aan elkaar gekoppeld. Lees altijd het uitkomstlabel. Ga er niet van uit dat index 0 "Yes" is. In markten met meerdere uitkomsten (NegRisk, Oscars, verkiezingen) kan index 0 bijvoorbeeld "Kamala Harris" of "Taylor Swift" zijn. De volgorde ligt vast, maar is per markt specifiek.

Deel 6: Orderboeken lezen

book = client.get_order_book(token_id=yes_token)

best_bid = float(book.bids[0].price) if book.bids else None
best_ask = float(book.asks[0].price) if book.asks else None
mid      = (best_bid + best_ask) / 2 if best_bid and best_ask else None
spread   = best_ask - best_bid if best_bid and best_ask else None

print(f"Bid {best_bid}  Ask {best_ask}  Mid {mid:.4f}  Spread {spread:.4f}")

Orderboeken worden geretourneerd als gesorteerde arrays (bids aflopend, asks oplopend). Elk niveau heeft een price en een size. Wil je de slippage voor een grotere order inschatten, loop dan door het orderboek en tel de nominale waarde op totdat je je doelgrootte hebt gevuld.

Deel 6b: De CLOB v2 REST-endpoints (raw, zonder SDK)

De SDK is een wrapper rond deze endpoints, maar als je de raw endpoints kent, kun je makkelijker debuggen, een andere taal gebruiken of een lichte client bouwen. Base URL: https://clob.polymarket.com. Alle onderstaande leesaanvragen zijn publiek - geen auth nodig. Deze zijn in juni 2026 live gecontroleerd.

EndpointMethodWhat it returns
/marketsGETAlle markten (gepagineerd via next_cursor). Bevat condition_id, tokens[], minimum_tick_size, neg_risk.
/sampling-marketsGETAlleen markten met een live orderboek - de snelste manier om verhandelbare token_ids te vinden.
/book?token_id=GETVolledig orderboek: bids[] en asks[] met prijs + omvang.
/price?token_id=&side=buyGETBeste prijs voor een orderzijde. side is niet hoofdlettergevoelig (buy/BUY). Retourneert {"price":"0.14"}.
/midpoint?token_id=GET{"mid":"0.21"} - halverwege de beste bied- en laatprijs.
/spread?token_id=GET{"spread":"0.14"} - beste laatprijs min beste biedprijs.
/tick-size?token_id=GET{"minimum_tick_size":0.01} - de kleinste toegestane prijsstap voor die token.
/prices-history?market=&interval=GETHistorische prijspunten. interval = 1m,1h,6h,1d,1w,max.
/tradesGETRecente trades (authenticatie voor je eigen trades; openbaar per markt).
/orderPOSTPlaats een ondertekende order (authenticatie vereist).
/orderDELETEAnnuleer één order op id (authenticatie).
/ordersGETJe openstaande orders (authenticatie).
/balance-allowance?asset_type=GETJe pUSD-saldo en on-chain allowance (authenticatie). Controleer dit vóór elke order.

Geverifieerde API-responses, rechtstreeks uit de live API:

$ curl "https://clob.polymarket.com/price?token_id=7347...&side=buy"
{"price":"0.14"}

$ curl "https://clob.polymarket.com/midpoint?token_id=7347..."
{"mid":"0.21"}

$ curl "https://clob.polymarket.com/spread?token_id=7347..."
{"spread":"0.14"}

$ curl "https://clob.polymarket.com/tick-size?token_id=7347..."
{"minimum_tick_size":0.01}

L2-authenticatieheaders (voor raw REST zonder de SDK)

Read-endpoints zijn openbaar. Om orders via raw REST te plaatsen of te annuleren, onderteken je elke request met je API-referenties. De SDK doet dit voor je; dit is wat die op de achtergrond opbouwt:

HeaderWhat it carries
POLY_ADDRESSHet walletadres waarmee je ondertekent
POLY_API_KEYDe API key uit create_or_derive_api_creds()
POLY_PASSPHRASEDe passphrase uit dezelfde derive-aanroep
POLY_TIMESTAMPHuidige UNIX-seconden (moet overeenkomen met de serverklok - zie de tip over kloksynchronisatie)
POLY_NONCENonce per request
POLY_SIGNATUREHMAC-SHA256 van timestamp + method + path + body, met je API-secret als sleutel, base64-url-gecodeerd

Deel 7: Orders plaatsen - kopen en verkopen

Limietorder (GTC - de standaard)

from py_clob_client.clob_types import OrderArgs, OrderType

args = OrderArgs(
    token_id=yes_token,
    price=0.45,
    size=100,           # Shares, not dollars. 100 shares @ $0.45 = $45 max cost.
    side="BUY",
)
signed_order = client.create_order(args)
response = client.post_order(signed_order, OrderType.GTC)
print(response)

De create_order-aanroep ondertekent een gestructureerd EIP-712-bericht met je privésleutel. Vervolgens dient post_order die in bij CLOB. Je verstuurt nooit ruwe privésleutels via het netwerk - alleen ondertekende orders.

Rond je prijs eerst af op de tick

Elke orderprijs moet een exact veelvoud zijn van de minimum_tick_size van de markt (0,01 op de meeste markten, 0,001 op markten met een kleine spread). Een prijs die niet op een tick valt, wordt geweigerd. Haal de tick één keer op en rond daarop af:

from py_clob_client.clob_types import OrderArgs, OrderType

tick = float(client.get_tick_size(token_id=yes_token))   # e.g. 0.01
def to_tick(p, tick): return round(round(p / tick) * tick, 4)

price = to_tick(0.453, tick)   # -> 0.45 on a 0.01 market

Kopen

side="BUY", size is in aandelen (niet in dollars). 100 aandelen tegen 0,45 dollar kosten maximaal 45 dollar en keren 100 dollar uit als de uitkomst wint. De minimale orderwaarde is ongeveer 1 dollar.

buy = OrderArgs(token_id=yes_token, price=to_tick(0.45, tick), size=100, side="BUY")
resp = client.post_order(client.create_order(buy), OrderType.GTC)
print(resp)   # {'success': True, 'orderID': '0x...', 'status': 'live', ...}

Verkopen

Verkopen is dezelfde aanroep met side="SELL". Je kunt alleen aandelen verkopen die je al bezit; meer verkopen dan je positie wordt geweigerd met een foutmelding "onvoldoende saldo". Om een positie te sluiten, verkoop je dezelfde token_id die je hebt gekocht.

sell = OrderArgs(token_id=yes_token, price=to_tick(0.62, tick), size=100, side="SELL")
resp = client.post_order(client.create_order(sell), OrderType.GTC)

Orderparameters in één oogopslag

FieldMeaningNotes
token_idDe uitkomst waarin je handeltNiet condition_id - zie deel 5
sideBUY of SELLBUY vereist pUSD; SELL vereist aandelen
price0,001-0,999Moet een veelvoud van de tickgrootte zijn
sizeAantal aandelenMin. orderwaarde van circa 1 pUSD; kosten = price x size
order typeGTC / GTD / FOK / FAKWordt doorgegeven aan post_order(...)

Alles samen: je eerste API-trade (één uitvoerbaar script)

Dit is de volledige flow van begin tot eind: verbinden, een liquide markt vinden, het orderboek lezen, afronden op de tick, een kleine echte order plaatsen en die daarna annuleren. Vul je twee geheimen in en voer het uit. Begin bij je allereerste run met een heel kleine size (een paar dollar).

import os, json, requests
from dotenv import load_dotenv
from py_clob_client.client import ClobClient
from py_clob_client.constants import POLYGON
from py_clob_client.clob_types import OrderArgs, OrderType

load_dotenv()

# 1) Connect (signing key in your EOA, funds in your proxy/funder)
client = ClobClient(
    "https://clob.polymarket.com",
    key=os.environ["POLY_PRIVATE_KEY"],
    chain_id=POLYGON,            # 137
    signature_type=1,            # 1 = email/Magic proxy, 2 = browser-wallet proxy
    funder=os.environ["POLY_FUNDER"],
)
client.set_api_creds(client.create_or_derive_api_creds())   # cache these after first run

# 2) Find the most-traded open market (Gamma, no auth)
m = requests.get(
    "https://gamma-api.polymarket.com/markets",
    params={"active": "true", "closed": "false", "order": "volume24hr",
            "ascending": "false", "limit": 1}, timeout=10,
).json()[0]
token_id = json.loads(m["clobTokenIds"])[0]   # index 0 = first outcome (read the label!)
print("Trading:", m["question"])

# 3) Read the book + the tick size
tick = float(client.get_tick_size(token_id))
book = client.get_order_book(token_id)
best_ask = float(book.asks[0].price)
print("best ask", best_ask, "| tick", tick)

# 4) Place a small BUY at the ask (tiny size to start)
price = round(round(best_ask / tick) * tick, 4)      # snap to tick
order = OrderArgs(token_id=token_id, price=price, size=5, side="BUY")  # 5 shares
resp = client.post_order(client.create_order(order), OrderType.GTC)
print(resp)                                          # {'success': True, 'orderID': '0x...', ...}

# 5) Cancel it (clean up)
# client.cancel(order_id=resp["orderID"])

Ordertypes

TypeCodeBehaviourWhen to use
Good Till CancelledGTCBlijft in het orderboek staan totdat de order is uitgevoerd of totdat je hem annuleertStandaard. De meeste market-making- en limietstrategieën.
Good Till DateGTDWordt automatisch geannuleerd op een opgegeven timestampEvent-driven: "annuleer 5 min. vóór de Fed-publicatie"
Fill or KillFOKMoet de volledige size direct uitvoeren of volledig worden geannuleerdArbitrage-legs waarbij gedeeltelijke uitvoeringen de trade verpesten
Fill and KillFAKVoert uit wat mogelijk is tegen de limietprijs en annuleert de restAgressief nemen van liquiditeit: gedraagt zich als een marktorder met een prijslimiet

Annuleren

# Single order
client.cancel(order_id="0xabc...")

# Cancel all orders on a specific market
client.cancel_market_orders(market=market['conditionId'])

# Nuclear option: cancel everything
client.cancel_all()

Deel 8: WebSocket-streaming

Elke seconde Gamma pollen is verspilling, en je loopt snel tegen rate limits aan. De WebSocket-feed streamt orderboek- en trade-updates in realtime met een latentie van minder dan een seconde.

import json, websocket

WS_URL = "wss://ws-subscriptions-clob.polymarket.com/ws/market"

def on_open(ws):
    ws.send(json.dumps({
        "type": "market",
        "assets_ids": [yes_token, no_token],
    }))

def on_message(ws, message):
    event = json.loads(message)
    if event.get("event_type") == "price_change":
        print(f"{event['market']} {event['side']} {event['price']} size={event['size']}")

ws = websocket.WebSocketApp(
    WS_URL,
    on_open=on_open,
    on_message=on_message,
)
ws.run_forever(ping_interval=20)

Er zijn twee feeds. De /market-feed bevat het openbare orderboek en trades. De /user-feed bevat je eigen order- en fill-events (geauthenticeerd). Productiebots verbinden met beide, maken automatisch opnieuw verbinding na een disconnect en behandelen de WebSocket als de bron van waarheid voor het actuele orderboek.

Deel 9: Rate Limits & Backoff

Endpoint classLimitBurst
Orderplaatsing (CLOB)circa 60 / minuut per API keycirca 10 / seconde
Orderannuleringcirca 120 / minuutcirca 20 / seconde
Marktdata lezen (CLOB-boek)circa 300 / minuuthoger, varieert
Gamma APIRuim; respecteer 429s-
WebSocket-berichtenGeen praktische limiet inkomend-

Wanneer je een HTTP 429 krijgt, stuurt de server een Retry-After-header terug. Gebruik exponential backoff with jitter:

import random, time

def post_with_backoff(fn, *args, max_retries=6):
    for attempt in range(max_retries):
        try:
            return fn(*args)
        except Exception as e:
            if "429" in str(e):
                sleep = (2 ** attempt) + random.random()
                time.sleep(min(sleep, 30))
                continue
            raise
    raise RuntimeError("Too many retries")

Deel 10: Een referentiearchitectuur voor bots

Elke betrouwbare Polymarket-bot heeft dezelfde zes componenten. Bouw elk component als een eigen module en houd ze losjes gekoppeld.

ComponentResponsibilityAPIs used
ScannerGeplande taak: haal markets op die aan je criteria voldoen (tags, volume, dagen tot expiratie)Gamma
PrijsmotorBeheer lokale orderboeken in realtime via WebSocketCLOB WS
SignaalgeneratorPure functie: orderboekstatus + metadata → doelpositie- (in-memory)
OrdermanagerVergelijk huidige orders met het doel en plaats/annuleer zo beperkt mogelijkCLOB REST
RisicomanagerDwing limieten per market, dagelijkse verlieslimieten en circuit breakers af- (in-memory + DB)
Logger & grootboekSla elke beslissing, fill en annulering permanent op. Voedt belastingrapportages en helpt bij debugging.SQLite / Postgres

Deel 11: Veelvoorkomende foutscenario's

  • Order geweigerd door prijs buiten de tick - de prijs moet een exacte veelvoud zijn van de minimum_tick_size van de market. Haal die op via /tick-size?token_id= en rond af voordat je tekent, anders wordt de order geweigerd.
  • 404 "No orderbook exists" - je hebt /book, /price of /midpoint opgevraagd voor een gesloten/afgewikkelde token. Gebruik /sampling-markets om tokens met een live orderboek te vinden.
  • Verouderde WebSocket-data - houd per asset het tijdstip van het laatste bericht bij; als er op een actieve market langer dan 30 seconden geen updates zijn, forceer dan een refresh via REST.
  • Nonce-conflicten - py-clob-client handelt order-nonces voor je af, maar als je je eigen signer bouwt, verhoog dan de nonce bij elke order.
  • Onvoldoende saldo - controleer altijd je pUSD-saldo voordat je een order plaatst; het orderboek kan je order tonen, maar het matchingproces kan deze alsnog weigeren.
  • Market gepauzeerd of in afwikkeling - controleer market.active && !market.closed voordat je handelt. Rond de afwikkeling loopt Gamma een paar seconden achter op CLOB.
  • NegRisk-adapter komt niet overeen - markets met meerdere uitkomsten lopen via een aparte NegRisk-adapter. De SDK handelt dit af, maar controleer of je order naar de juiste venue is gegaan.

Deel 12: Liquidity Rewards via API

Polymarket keert circa 5 miljoen dollar per maand uit aan algemene liquidity rewards, plus meer dan 5 miljoen dollar per maand aan sports-specifieke rewards (zie Liquidity Rewards). Het grootste deel daarvan gaat naar market makers die via de API werken. Zij houden krappe tweezijdige quotes aan over duizenden markets.

De reward-formule beloont orders dicht bij het midpoint, met meeweging van omvang en tijd in het orderboek. Dit is een minimale market-making-loop:

  1. Lees het orderboek voor de doelmarket
  2. Bereken een fair midpoint (bijvoorbeeld VWAP van de bovenste 3 niveaus aan beide kanten)
  3. Plaats een bid op mid − spread_target/2 en een ask op mid + spread_target/2
  4. Herprijs bij elke WebSocket-update als je quote meer dan één tick van het doel afwijkt
  5. Annuleer en stap uit als het orderboek dunner wordt of er nieuws naar buiten komt

Deel 13: Naar productie

  • Hosting: een VPS van 6 dollar per maand (Hetzner, DigitalOcean) in Europa of US-East is genoeg voor de meeste bots. Plaats je bot dicht bij Polygon RPC als je latency onder 10 ms nodig hebt.
  • RPC: gebruik Alchemy, Infura of QuickNode voor betrouwbare Polygon RPC. Gratis tiers zijn prima totdat je honderden orders per minuut plaatst.
  • Monitoring: Prometheus + Grafana voor metrics; een Telegram-bot voor alerts. Log elke order-ID die je verstuurt en elke fill die je ontvangt.
  • Back-ups: sla state elke minuut persistent op. Als de VPS midden in een fill uitvalt, wil je binnen enkele seconden verder kunnen, niet handmatig hoeven reconciliëren.
  • Belasting: je logger is ook je audittrail - zie Tax Guide.

Deel 14 - Bewezen pro-tips voor de Polymarket API

Spiekbrief: situatie → actie

SituationActionWhy
401 "invalid api key" bij de eerste aanroepControleer of signature_type overeenkomt met de herkomst van de wallet en of funder het proxy-adres isEen mismatch tussen type 1 en 2 veroorzaakt 80% van de 401-fouten; de rest komt door een EOA als funder
Orders geweigerd met "insufficient balance"Vraag vóór elke order /balance-allowance op en reserveer lokaalCLOB reserveert onderpand zodra je post; twee gelijktijdige orders kunnen dezelfde balans dubbel reserveren
429-throttling op de /order-endpointGebruik back-off met jitter: 2^attempt + random(), afgetopt op 30 sCloudflare throttlet in plaats van te weigeren; naïef opnieuw proberen maakt de wachtrij alleen groter
WebSocket verbroken midden in een tradeMaak via REST een snapshot van het orderboek, reconcilieer de lokale state en abonneer je daarna opnieuwDeltas tijdens de onderbreking gaan verloren; een snapshot synchroniseert de prijsladders opnieuw
Order geplaatst, maar geen bevestiging van fillVraag binnen 5 s /data/order/{id} op; als de order pending is, wacht je; als hij niet wordt gevonden, vervang je hemZeldzaam maar herstelbaar; hanteer standaard: eerst state controleren, daarna handelen
Market resolved terwijl er een actieve quote staatAnnuleer bij de resolution event alle openstaande orders voor die conditionIdOrders na resolution kunnen als zombie fills blijven hangen als adapter-eigenaardigheden optreden
Je draait een market-making botQuote binnen 2 cent van de middenprijs met een size van 100+ sharesDe beloningsformule weegt scherpte + size + time-on-book; scherp + groot + consistent wint
Je draait een arbitragebot op multi-outcomeGebruik FOK voor elke leg, niet GTCGedeeltelijke fills op leg A met een volledige leg B = niet-afgedekte exposure en direct verlies
Je bouwt voor het eerst een botBouw eerst de scanner, daarna de prijsengine en daarna het signaal - nooit eerst het signaalSignalen zonder schone orderboekstate zijn correlatievalkuilen; zorg eerst dat de datastromen werken
Productiebot crashte om 03:00Zorg voor auto-restart via systemd + Telegram-melding + persistente stateElke onbeheerde bot crasht vroeg of laat; de enige vraag is of hij netjes opnieuw opstart

Wat nu?

  • Tools en resources - dashboards, analytics en datafeeds van derden die de API aanvullen
  • Geavanceerde strategieën - multi-leg arbitrage en option-achtige constructies die geschikt zijn voor bots
  • Liquidity Rewards - exacte formules om market-making rebates te verdienen
  • Orderboekgids - meer inzicht in het lezen van het orderboek voordat je ertegen codeert
  • Glossary - heldere definities in eenvoudig Engels van elke term in deze gids

Snelle check