Versão resumida
A Polymarket oferece três APIs públicas (uma API é uma forma de programas lerem dados ou enviarem operações automaticamente): CLOB (negociação), Gamma (descoberta de mercados) e Data (análises). O SDK oficial em Python é o py-clob-client 0.34.6. A autenticação usa uma chave de API + assinatura ECDSA, e as ordens são assinadas via EIP-712 por meio de uma carteira proxy na Polygon. Os limites de taxa restringem você a cerca de 60 ordens por minuto por chave. O principal ponto de atenção para novos desenvolvedores é o problema de mapeamento condition_id → token_id entre Gamma e CLOB. Resolva isso primeiro, e o restante fica muito mais simples. Cerca de US$ 40 milhões por mês em recompensas de liquidez e spread capturado por bots é ganho na Polymarket, quase tudo por usuários de API.
Parte 1: As três APIs
A Polymarket divide o trabalho de forma clara entre três serviços separados. Usar a API certa para cada tarefa mantém seu bot rápido, simples e dentro dos limites de taxa.
| API | Base URL | Purpose | Auth Required |
|---|---|---|---|
| CLOB API | clob.polymarket.com | Enviar, cancelar e acompanhar ordens. Ler livros de ofertas. Consultar posições. | Sim (para negociar) |
| Gamma API | gamma-api.polymarket.com | Navegar por mercados, buscar metadados, imagens, preços de resultados, volume, vencimento e tags. | Não (pública) |
| Data API | data-api.polymarket.com | Operações históricas, snapshots de posições, análises de usuários e dados de ranking. | Não (pública) |
Um loop típico de bot usa Gamma para encontrar mercados, CLOB para buscar livros de ofertas e enviar operações, e Data para fazer backtest do desempenho da estratégia offline. Pense no Gamma como o "catálogo", no CLOB como a "bolsa" e no Data como o "armazém".
Parte 2: Autenticação & o modelo de carteira proxy
A Polymarket não assina operações com a chave privada da sua carteira principal. Em vez disso, ela usa uma carteira proxy no estilo Gnosis Safe. Sua carteira principal autoriza um proxy, e o proxy executa todas as operações na Polygon. Seu bot de API se comunica com esse proxy.
Do que você precisa
- Chave de API - gere em Polymarket Settings → Developer
- Chave privada - a chave da sua carteira de negociação (NÃO a seed phrase da sua MetaMask principal)
- Endereço funder - o endereço da sua carteira proxy (exibido em Settings → Wallet)
- Chain ID -
137(Polygon mainnet) - Signature type -
1(POLY_PROXY, padrão para usuários de varejo)
Parte 3: Instalação do py-clob-client
O SDK oficial em Python é a forma mais rápida de sair do zero e enviar sua primeira ordem. Vamos usar a versão 0.34.6 — a versão atual no PyPI (fev. de 2026) e a que praticamente todo bot em produção usa.
# 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-dotenvConfiguração básica do cliente
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())A chamada create_or_derive_api_creds() assina uma mensagem com sua chave privada. Ela troca essa assinatura por uma chave de API, um segredo e uma passphrase. Armazene esses dados no seu .env após a primeira execução, para não chamar o endpoint de derivação a cada inicialização.
Parte 4: Descobrindo mercados via Gamma
Antes de operar, você precisa encontrar mercados que valham a pena. Gamma retorna JSON com tudo o que a interface da Polymarket mostra: a pergunta, os resultados, os preços, o volume em 24 h, a expiração, as tags e as imagens.
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}")Parâmetros úteis de consulta do Gamma
| Parameter | What it does |
|---|---|
tag_slug | Filtra por categoria (política, esportes, cripto, cultura etc.) |
active=true | Somente mercados que estão aceitando negociações no momento |
closed=false | Oculta mercados já resolvidos |
order=volume24hr | Ordena por volume recente (sinal de liquidez) |
end_date_min | Data ISO — ignora mercados que serão resolvidos cedo demais |
limit | Até 500 por página (use offset para paginação) |
Parte 5: O mapeamento condition_id → token_id
Este é o principal ponto de atrito ao criar bots para a Polymarket. Gamma retorna um condition_id (um por mercado). As negociações no CLOB usam um token_id (um por resultado). Você sempre precisa dos dois.
# 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']Atenção à ordem dos resultados
O array outcomes e o array clobTokenIds do Gamma são correspondidos por índice. Sempre leia o rótulo do resultado. Não presuma que o índice 0 é "Yes". Em mercados com múltiplos resultados (NegRisk, Oscar, eleições), o índice 0 pode ser "Kamala Harris" ou "Taylor Swift". A ordem é fixa, mas específica de cada mercado.
Parte 6: Lendo livros de ofertas
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}")Os livros de ofertas retornam como arrays ordenados (bids em ordem decrescente, asks em ordem crescente). Cada nível tem um price e um size. Para estimar o slippage em uma ordem maior, percorra o livro e some o notional até preencher o tamanho desejado.
Parte 6b: Os endpoints REST CLOB v2 (brutos, sem SDK)
O SDK encapsula esses endpoints, mas conhecer os endpoints brutos ajuda a depurar, usar outra linguagem ou criar um cliente leve. URL base: https://clob.polymarket.com. Todas as leituras abaixo são públicas — não exigem autenticação. Elas foram verificadas em produção em junho de 2026.
| Endpoint | Method | What it returns |
|---|---|---|
/markets | GET | Todos os mercados (paginados via next_cursor). Inclui condition_id, tokens[], minimum_tick_size, neg_risk. |
/sampling-markets | GET | Apenas mercados com livro de ofertas ativo — a forma mais rápida de encontrar token_ids negociáveis. |
/book?token_id= | GET | Livro de ofertas completo: bids[] e asks[] com preço + tamanho. |
/price?token_id=&side=buy | GET | Melhor preço para um lado. side não diferencia maiúsculas de minúsculas (buy/BUY). Retorna {"price":"0.14"}. |
/midpoint?token_id= | GET | {"mid":"0.21"} — ponto médio entre a melhor oferta de compra e a melhor oferta de venda. |
/spread?token_id= | GET | {"spread":"0.14"} — melhor oferta de venda menos a melhor oferta de compra. |
/tick-size?token_id= | GET | {"minimum_tick_size":0.01} — o menor incremento de preço permitido para esse token. |
/prices-history?market=&interval= | GET | Pontos de preço históricos. interval = 1m,1h,6h,1d,1w,max. |
/trades | GET | Negociações recentes (com autenticação para as suas; público para o mercado). |
/order | POST | Envia uma ordem assinada (autenticação obrigatória). |
/order | DELETE | Cancela uma ordem por id (autenticação). |
/orders | GET | Suas ordens abertas pendentes (autenticação). |
/balance-allowance?asset_type= | GET | Seu saldo em USDC e a autorização on-chain (autenticação). Verifique antes de cada ordem. |
Respostas verificadas, direto da API ativa:
$ 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}Cabeçalhos de autenticação L2 (para REST puro sem o SDK)
Endpoints de leitura são públicos. Para enviar ou cancelar ordens via REST puro, você assina cada requisição com suas credenciais de API. O SDK faz isso para você; veja o que ele monta internamente:
| Header | What it carries |
|---|---|
POLY_ADDRESS | O endereço da sua carteira de assinatura |
POLY_API_KEY | A chave de API de create_or_derive_api_creds() |
POLY_PASSPHRASE | A passphrase da mesma chamada de derivação |
POLY_TIMESTAMP | Segundos UNIX atuais (deve corresponder ao relógio do servidor — veja a dica de sincronização de relógio) |
POLY_NONCE | Nonce por requisição |
POLY_SIGNATURE | HMAC-SHA256 de timestamp + method + path + body, usando seu secret de API como chave, codificado em base64-url |
Parte 7: Envio de ordens — compra e venda
Ordem limitada (GTC — o padrão)
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)A chamada create_order assina uma mensagem estruturada EIP-712 com sua chave privada. Em seguida, post_order a envia para o CLOB. Você nunca envia chaves privadas brutas pela rede — apenas ordens assinadas.
Ajuste o preço ao incremento mínimo primeiro
Todo preço de ordem deve ser um múltiplo exato do minimum_tick_size do mercado (0,01 na maioria dos mercados, 0,001 nos mais precisos). Um preço fora do incremento permitido é rejeitado. Busque o incremento uma vez e arredonde para ele:
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 marketCompra
side="BUY", size é em cotas (não em dólares). 100 cotas a US$ 0,45 custam no máximo US$ 45 e pagam US$ 100 se o resultado vencer. O valor mínimo da ordem é de cerca de US$ 1.
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', ...}Venda
Vender usa a mesma chamada com side="SELL". Você só pode vender cotas que já possui; tentar vender mais do que sua posição é rejeitado com um erro de "insufficient balance". Para encerrar uma posição, venda o mesmo token_id que você comprou.
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)Resumo dos parâmetros de ordem
| Field | Meaning | Notes |
|---|---|---|
token_id | O resultado que você está negociando | Não é condition_id; veja a Parte 5 |
side | BUY ou SELL | BUY exige USDC; SELL exige cotas |
price | 0,001-0,999 | Deve ser múltiplo do tamanho do tick |
size | Número de cotas | Valor mínimo da ordem de ~US$ 1; custo = preço x quantidade |
| tipo de ordem | GTC / GTD / FOK / FAK | Passado para post_order(...) |
Juntando tudo: sua primeira negociação via API (um script executável)
Este é o fluxo completo, do início ao fim: conectar, encontrar um mercado líquido, ler o livro de ofertas, alinhar ao tick, enviar uma pequena ordem real e depois cancelá-la. Preencha seus dois segredos e execute. Na primeira execução, comece com um tamanho bem pequeno (alguns dólares).
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"])Tipos de ordem
| Type | Code | Behaviour | When to use |
|---|---|---|---|
| Válida até cancelamento | GTC | Fica no livro de ofertas até ser executada ou até você cancelar | Padrão. A maioria das estratégias de market making e de limite. |
| Válida até uma data | GTD | É cancelada automaticamente em um timestamp especificado | Orientado a eventos: "cancelar 5 min antes do comunicado do Fed" |
| Executar ou cancelar | FOK | Deve executar o tamanho inteiro imediatamente ou ser totalmente cancelada | Pernas de arbitragem em que execuções parciais inviabilizam a operação |
| Executar e cancelar | FAK | Executa o que conseguir no preço limite e cancela o restante | Tomada agressiva de liquidez: funciona como uma ordem a mercado com limite de preço |
Cancelamento
# 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()Parte 8: Streaming via WebSocket
Consultar Gamma a cada segundo é desperdício, e você atingirá os limites de taxa rapidamente. O feed WebSocket transmite atualizações em tempo real do livro de ofertas e das negociações, com latência inferior a um segundo.
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)Existem dois feeds. O feed /market carrega o livro de ofertas público e as negociações. O feed /user carrega seus próprios eventos de ordens e execuções (autenticado). Bots em produção se conectam aos dois, reconectam automaticamente em caso de desconexão e tratam o WebSocket como a fonte da verdade para o livro de ofertas atual.
Parte 9: Limites de taxa e backoff
| Endpoint class | Limit | Burst |
|---|---|---|
| Envio de ordens (CLOB) | ~60/minuto por API key | ~10/segundo |
| Cancelamento de ordens | ~120/minuto | ~20/segundo |
| Leituras de dados de mercado (livro do CLOB) | ~300/minuto | maior, varia |
| Gamma API | Generoso; respeite 429s | - |
| Mensagens WebSocket | Sem limite prático de entrada | - |
Quando você recebe um HTTP 429, o servidor retorna um cabeçalho Retry-After. Use backoff exponencial com 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")Parte 10: Uma arquitetura de bot de referência
Todo bot confiável da Polymarket tem os mesmos seis componentes. Crie cada um como seu próprio módulo e mantenha-os com baixo acoplamento.
| Component | Responsibility | APIs used |
|---|---|---|
| Varredor | Job agendado: buscar mercados que atendam aos seus critérios (tags, volume, dias até o vencimento) | Gamma |
| Motor de preços | Manter livros de ordens locais em tempo real via WebSocket | CLOB WS |
| Gerador de sinais | Função pura: estado do livro + metadados → posição-alvo | - (em memória) |
| Gerenciador de ordens | Comparar ordens atuais com o alvo e criar/cancelar o mínimo necessário | CLOB REST |
| Gerenciador de risco | Aplicar limites por mercado, limites de perda diária e circuit breakers | - (em memória + DB) |
| Logger e livro-razão | Persistir todas as decisões, fills e cancelamentos. Alimenta relatórios fiscais e depuração. | SQLite / Postgres |
Parte 11: Modos comuns de falha
- Rejeição por preço fora do tick - o preço deve ser um múltiplo exato do
minimum_tick_sizedo mercado. Busque esse valor via/tick-size?token_id=e arredonde antes de assinar, ou a ordem será rejeitada. - 404 "No orderbook exists" - você consultou
/book,/priceou/midpointem um token fechado/resolvido. Use/sampling-marketspara encontrar tokens com livro ativo. - Dados obsoletos no WebSocket - acompanhe o horário da última mensagem por ativo; se não houver atualizações por >30s em um mercado ativo, force uma atualização via REST.
- Colisões de nonce - py-clob-client gerencia os nonces das ordens para você, mas, se você estiver implementando seu próprio assinador, incremente o nonce a cada ordem.
- Saldo insuficiente - sempre verifique o saldo de USDC antes de enviar; o livro pode exibir sua ordem, mas o matching vai rejeitá-la.
- Mercado pausado ou em resolução - verifique
market.active && !market.closedantes de negociar. As atualizações do Gamma ficam alguns segundos atrás do CLOB perto da resolução. - Incompatibilidade do adaptador NegRisk - mercados com múltiplos resultados passam por um adaptador NegRisk separado. O SDK lida com isso, mas confirme se sua ordem foi para o venue correto.
Parte 12: Recompensas de Liquidez via API
A Polymarket distribui ~US$ 5 milhões/mês em recompensas gerais de liquidez, além de mais de US$ 5 milhões/mês em recompensas específicas de esportes (consulte Recompensas de Liquidez). A maior parte vai para market makers orientados por API. Eles mantêm cotações ajustadas em ambos os lados em milhares de mercados.
A fórmula de recompensa favorece ordens próximas ao ponto médio, com tamanho e tempo no livro. Veja um loop mínimo de market making:
- Ler o livro de ordens do mercado-alvo
- Calcular um ponto médio justo (por exemplo, VWAP dos 3 primeiros níveis de cada lado)
- Publicar uma bid em
mid − spread_target/2e uma ask emmid + spread_target/2 - A cada atualização do WebSocket, reajustar o preço se sua cotação se afastar mais de um tick do alvo
- Cancelar e sair se o livro perder profundidade ou se surgir uma notícia relevante
Parte 13: Indo para produção
- Hospedagem: uma VPS de US$ 6/mês (Hetzner, DigitalOcean) na Europa ou em US-East é suficiente para a maioria dos bots. Hospede próximo ao RPC da Polygon se você precisar de latência abaixo de 10 ms.
- RPC: use Alchemy, Infura ou QuickNode para ter um RPC da Polygon confiável. Os planos gratuitos são suficientes até você começar a enviar centenas de ordens por minuto.
- Monitoramento: Prometheus + Grafana para métricas; um bot do Telegram para alertas. Registre em log cada ID de ordem que você enviar e cada fill que receber.
- Backups: persista o estado a cada minuto. Se a VPS cair no meio de um fill, você vai querer retomar em segundos, não reconciliar tudo manualmente.
- Impostos: seu logger também é sua trilha de auditoria - consulte o Guia de Impostos.
Parte 14 - Dicas avançadas validadas para a API da Polymarket
Guia rápido Situação → Ação
| Situation | Action | Why |
|---|---|---|
| 401 "invalid api key" na primeira chamada | Verifique se signature_type corresponde à origem da carteira e se funder é o endereço do proxy | A incompatibilidade entre os tipos 1 e 2 causa 80% dos erros 401; o restante é EOA como funder |
| Ordens rejeitadas com "insufficient balance" | Consulte /balance-allowance antes de cada ordem e reserve localmente | O CLOB reserva a garantia no instante em que você envia a ordem; duas ordens simultâneas podem comprometer o mesmo saldo |
| 429 por throttling no endpoint /order | Use backoff com jitter: 2^attempt + random() limitado a 30s | O Cloudflare aplica throttling em vez de rejeitar; retentativas ingênuas aumentam o backlog |
| WebSocket desconectado no meio da negociação | Obtenha um snapshot do book via REST, reconcilie o estado local e depois assine novamente | Os deltas durante a interrupção são perdidos; o snapshot ressincroniza os níveis de preço |
| Ordem enviada, mas sem confirmação de fill | Consulte /data/order/{id} em até 5s; se estiver pendente, aguarde; se não for encontrada, substitua | É raro, mas recuperável; por padrão, “verifique o estado e só então aja” |
| Mercado resolvido enquanto há cotação ativa | Cancele todas as ordens abertas desse conditionId no evento de resolução | Ordens pós-resolução podem permanecer como fills zumbis se peculiaridades do adapter forem acionadas |
| Executando um bot de market-making | Cote a até 2 centavos do midpoint com tamanho de 100+ shares | A fórmula de recompensa pondera proximidade + tamanho + tempo no book; cotação próxima + tamanho + persistência vencem |
| Executando um bot de arbitragem em multi-outcome | Use FOK para cada perna, não GTC | Fills parciais na perna A com uma perna B completa = exposição sem hedge e perda imediata |
| Primeira vez criando um bot | Construa primeiro o scanner, depois o mecanismo de preço e então o sinal — nunca comece pelo sinal | Sinais sem um estado de book limpo são armadilhas de correlação; faça os fluxos funcionarem primeiro |
| Bot de produção caiu às 3h | Tenha reinício automático com systemd + alerta no Telegram + estado persistente | Qualquer bot sem supervisão vai cair; a única questão é se ele reinicia corretamente |
Próximos passos
- Ferramentas e recursos - dashboards, análises e feeds de dados de terceiros que complementam a API
- Estratégias avançadas - arbitragem multi-leg e construções semelhantes a opções adequadas para bots
- Recompensas de liquidez - fórmulas exatas para ganhar rebates de market-making
- Guia do Order Book - intuição mais aprofundada para ler o book antes de programar contra ele
- Glossário - definições em linguagem simples de todos os termos deste guia











