DEV Community

Cover image for Padrões de Design de API da Polymarket: O Maior Mercado de Previsões do Mundo
Lucas
Lucas

Posted on • Originally published at apidog.com

Padrões de Design de API da Polymarket: O Maior Mercado de Previsões do Mundo

Mercados de previsão estão entre os domínios mais exigentes para construir APIs: há instrumentos financeiros com expiração, probabilidades precificadas em tempo real, eventos com múltiplos resultados, relações de capital e usuários humanos competindo com robôs de arbitragem. Sob essas condições, decisões de modelagem, autenticação e streaming são testadas rapidamente em produção.

Experimente o Apidog hoje

A Polymarket, atualmente a maior plataforma de mercado de previsão do mundo em volume, oferece um caso útil para estudo. Seu ecossistema não é uma API CRUD convencional: ele separa descoberta, negociação e análise; combina dados públicos com operações autenticadas; e expõe regras financeiras diretamente no contrato da API.

A seguir, veja oito padrões que você pode aplicar ao projetar APIs para sistemas financeiros, marketplaces ou aplicações em tempo real.


Padrão 1: Separe APIs por domínio, não apenas por entidade

A Polymarket expõe três APIs com responsabilidades claras:

  • API Gamma (gamma-api.polymarket.com) — descoberta de mercados, eventos, tags e busca.
  • API CLOB (clob.polymarket.com) — livro de ordens, preços e colocação de ordens.
  • API de Dados (data-api.polymarket.com) — posições, negociações, análises e classificações de usuários.

Essa divisão vai além de nomes diferentes. Cada API possui consumidores, requisitos de autenticação e padrões de atualização próprios:

API Consumidor principal Autenticação Característica principal
Gamma Interfaces e exploradores Pública Navegação e descoberta
CLOB Traders e bots Leitura pública; escrita autenticada Baixa latência
Dados Dashboards e análises Pública, consultada por carteira Histórico e posições

Em vez de centralizar tudo em endpoints como:

/markets
/orders
/users
Enter fullscreen mode Exit fullscreen mode

separe a API de acordo com o objetivo do consumidor:

discovery.example.com
trading.example.com
analytics.example.com
Enter fullscreen mode Exit fullscreen mode

Essa abordagem permite escalar, versionar e proteger cada domínio de forma independente. Descoberta não tem os mesmos requisitos de latência que negociação, e negociação não deve compartilhar as mesmas garantias de disponibilidade de um endpoint analítico.

Aplicação prática: antes de criar recursos REST, defina os fluxos principais:

  1. Quem consulta dados?
  2. Quem escreve dados?
  3. Quais chamadas exigem baixa latência?
  4. Quais operações manipulam dinheiro, inventário ou permissões?
  5. Quais dados podem ser cacheados?

Use essas respostas para definir fronteiras de API.


Padrão 2: Torne dados de leitura públicos quando isso aumenta o valor da plataforma

Os dados de mercado da Polymarket — preços, livros de ordens, metadados e negociações históricas — podem ser consultados publicamente:

curl "https://gamma-api.polymarket.com/events?limit=5"
Enter fullscreen mode Exit fullscreen mode

Não há chave de API, OAuth ou autenticação obrigatória para esse tipo de leitura.

Essa decisão reduz atrito para desenvolvedores que querem criar:

  • dashboards;
  • alertas;
  • visualizações de mercado;
  • ferramentas de análise;
  • estratégias automatizadas;
  • integrações de terceiros.

O ponto importante é separar claramente leitura de escrita.

GET /markets/{id}       → público
GET /order-book/{token} → público
POST /orders            → autenticado
DELETE /orders/{id}     → autenticado
Enter fullscreen mode Exit fullscreen mode

Em plataformas onde o consumo de dados é muito maior que a criação de dados, exigir autenticação em toda leitura pode limitar o ecossistema sem oferecer ganho proporcional de segurança.

Checklist de implementação:

  • Deixe públicos os dados que não expõem informações sensíveis.
  • Aplique limites de taxa compatíveis com uso aberto.
  • Exija autenticação apenas em operações que alteram estado.
  • Separe quotas para leitura pública e escrita autenticada.
  • Documente explicitamente quais endpoints são públicos.

Padrão 3: Use autenticação em níveis diferentes conforme o risco da operação

Os endpoints de negociação exigem autenticação, mas a Polymarket usa dois níveis com objetivos distintos.

A autenticação L1 usa uma assinatura EIP-712 com a chave privada da carteira. Ela prova que o usuário controla aquela identidade e é usada para derivar credenciais de API:

// L1: use sua chave privada para derivar credenciais de API
const credentials = await client.createOrDeriveApiKey();

// { key: "...", secret: "...", passphrase: "..." }
Enter fullscreen mode Exit fullscreen mode

A autenticação L2 usa HMAC-SHA256 com as credenciais derivadas. Ela é enviada em cada solicitação de negociação:

{
  "POLY_ADDRESS": "0x...",
  "POLY_SIGNATURE": "<hmac-sha256>",
  "POLY_TIMESTAMP": "1716000000",
  "POLY_API_KEY": "550e8400-...",
  "POLY_PASSPHRASE": "..."
}
Enter fullscreen mode Exit fullscreen mode

A ideia é separar duas perguntas:

  1. “Você controla esta identidade?”

    Use uma credencial forte e pouco frequente, como uma assinatura de carteira.

  2. “Esta solicitação foi autorizada?”

    Use uma credencial de sessão ou API para chamadas frequentes.

Esse padrão evita exigir operações pesadas ou sensíveis a cada requisição de alta frequência.

Uma implementação equivalente para APIs tradicionais pode seguir este fluxo:

1. Usuário autentica com MFA, assinatura ou credencial forte.
2. Servidor emite chave de API ou token de sessão com escopo limitado.
3. Cliente assina requisições rotineiras com HMAC.
4. Servidor valida assinatura, timestamp, escopo e expiração.
Enter fullscreen mode Exit fullscreen mode

Boas práticas:

  • Inclua timestamp para reduzir risco de replay.
  • Defina expiração para credenciais derivadas.
  • Use escopos como orders:write e positions:read.
  • Permita revogação independente da identidade principal.
  • Registre operações L1 e L2 para auditoria.

Padrão 4: Modele ordens como mensagens assinadas, não apenas como payloads HTTP

Ao criar uma ordem na Polymarket, o cliente não envia apenas um JSON para o servidor. Ele cria uma mensagem EIP-712 assinada, que representa um compromisso financeiro executável:

const response = await client.createAndPostOrder(
  {
    tokenID: "71321045679...",
    price: 0.65,
    size: 100,
    side: Side.BUY,
  },
  {
    tickSize: "0.01",
    negRisk: false,
  },
  OrderType.GTC
);
Enter fullscreen mode Exit fullscreen mode

O SDK constrói uma estrutura tipada, assina a ordem com a chave privada e transmite a assinatura. O motor de correspondência opera fora da cadeia, mas as negociações correspondidas são liquidadas na Polygon usando essas autorizações assinadas.

A mudança conceitual é importante:

API convencional:
"Servidor, execute esta ação em meu nome."

Mensagem assinada:
"Esta é uma autorização verificável para executar esta ação."
Enter fullscreen mode Exit fullscreen mode

Quando o payload carrega a própria autorização, o sistema ganha propriedades úteis:

  • não repúdio: a assinatura prova quem autorizou a ordem;
  • verificabilidade: terceiros podem validar a assinatura;
  • menor confiança no intermediário: o operador não precisa receber poder irrestrito para agir;
  • auditoria mais precisa: a autorização é um artefato criptográfico.

Esse padrão é aplicável além de cripto, especialmente em:

  • instruções financeiras;
  • aprovações corporativas;
  • assinaturas de contratos;
  • transferências de ativos;
  • operações administrativas de alto risco.

Padrão 5: Expresse a ontologia do domínio no modelo de dados

A Polymarket organiza seus dados em dois conceitos: Eventos e Mercados.

  • Um Evento representa uma pergunta ou contexto maior.
  • Um Mercado representa um resultado negociável específico dentro desse evento.

Exemplo:

{
  "id": "501",
  "title": "2026 Pennsylvania Senate Race",
  "negRisk": true,
  "markets": [
    {
      "id": "2301",
      "question": "Will Bob Casey win?",
      "outcomePrices": "[\"0.42\", \"0.58\"]"
    },
    {
      "id": "2302",
      "question": "Will Dave McCormick win?",
      "outcomePrices": "[\"0.35\", \"0.65\"]"
    },
    {
      "id": "2303",
      "question": "Will a third candidate win?",
      "outcomePrices": "[\"0.23\", \"0.77\"]"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

A hierarquia deixa explícito que vários mercados pertencem ao mesmo evento e podem compartilhar regras ou relações de capital.

O modelo também usa convenções estruturais, como arrays paralelos:

outcomes[0] === outcomePrices[0]
Enter fullscreen mode Exit fullscreen mode

Isso exige cuidado no cliente. Ao consumir a API, valide que os arrays possuem o mesmo tamanho e mantenha o vínculo por índice:

function mapOutcomes(outcomes: string[], prices: string[]) {
  if (outcomes.length !== prices.length) {
    throw new Error("Outcomes e prices possuem tamanhos diferentes");
  }

  return outcomes.map((outcome, index) => ({
    outcome,
    price: Number(prices[index]),
  }));
}
Enter fullscreen mode Exit fullscreen mode

O campo negRisk também é parte essencial do modelo. Ele informa que os mercados daquele evento não devem ser tratados como instrumentos independentes.

Regra de design: se uma relação de domínio altera o comportamento do cliente, ela deve estar representada no payload como dado estruturado, e não escondida em uma nota da documentação.


Padrão 6: Transforme invariantes financeiros em campos tipados

O campo negRisk indica um tipo específico de relação de capital entre resultados de um evento.

Em um evento com múltiplos resultados mutuamente exclusivos, existe uma equivalência:

1 token Não no resultado A ≡ 1 token Sim em todos os outros resultados

Por exemplo:

Antes Depois
1× Não (Outro) 1× Sim (Casey) + 1× Sim (McCormick)

A Polymarket torna essa regra explícita no objeto de mercado e exige que o cliente informe o contexto ao criar uma ordem:

{
  tickSize: "0.01",
  negRisk: true
}
Enter fullscreen mode Exit fullscreen mode

Isso evita que o cliente envie uma ordem usando regras incorretas para aquele mercado.

Em sistemas próprios, siga o mesmo princípio. Não represente regras críticas apenas com texto como:

{
  "description": "Apenas um resultado pode vencer"
}
Enter fullscreen mode Exit fullscreen mode

Prefira campos que o cliente possa validar e usar diretamente:

{
  "settlementMode": "mutually_exclusive",
  "positionConversionEnabled": true,
  "requiresSharedCollateral": true
}
Enter fullscreen mode Exit fullscreen mode

Depois, faça o servidor validar essas regras:

if (market.negRisk !== orderOptions.negRisk) {
  throw new Error("Configuração negRisk incompatível com o mercado");
}
Enter fullscreen mode Exit fullscreen mode

Regra prática: se ignorar uma propriedade pode causar cálculo financeiro incorreto, rejeição de ordem ou perda de fundos, essa propriedade deve fazer parte do contrato tipado da API.


Padrão 7: Trate parâmetros dinâmicos como estado transmitido em tempo real

Na Polymarket, o tamanho mínimo do tick não é sempre fixo. Quando o preço se aproxima dos extremos, acima de 0.96 ou abaixo de 0.04, o tick pode mudar de 0.01 para 0.001:

{
  "event_type": "tick_size_change",
  "asset_id": "65818619657...",
  "old_tick_size": "0.01",
  "new_tick_size": "0.001",
  "timestamp": "100000000"
}
Enter fullscreen mode Exit fullscreen mode

Essa mudança é relevante porque, em probabilidades extremas, uma variação de 0.01 representa uma alteração proporcional muito maior. Por exemplo, passar de 0.04 para 0.03 equivale a uma queda de 25%.

O ponto de design é que tickSize não deve ser tratado como configuração carregada uma única vez. Ele é um estado do mercado.

Ao implementar um cliente WebSocket, mantenha o tick em memória e atualize-o ao receber eventos:

const marketState = new Map<string, { tickSize: string }>();

function handleMessage(message: {
  event_type: string;
  asset_id: string;
  new_tick_size?: string;
}) {
  if (message.event_type !== "tick_size_change" || !message.new_tick_size) {
    return;
  }

  const current = marketState.get(message.asset_id) ?? { tickSize: "0.01" };

  marketState.set(message.asset_id, {
    ...current,
    tickSize: message.new_tick_size,
  });
}
Enter fullscreen mode Exit fullscreen mode

Antes de enviar uma ordem, leia o estado atual:

const state = marketState.get(tokenID);

if (!state) {
  throw new Error("Estado do mercado ainda não foi carregado");
}

const order = {
  tokenID,
  price: 0.973,
  size: 100,
  tickSize: state.tickSize,
};
Enter fullscreen mode Exit fullscreen mode

Evite: codificar o tamanho do tick no cliente e assumir que ele nunca muda. Isso pode resultar em ordens inválidas ou rejeitadas.


Padrão 8: Use canais WebSocket diferentes para consumidores diferentes

A Polymarket mantém dois sistemas WebSocket separados.

O Canal de Mercado:

wss://ws-subscriptions-clob.polymarket.com/ws/market
Enter fullscreen mode Exit fullscreen mode

é voltado para negociação. Ele entrega snapshots de livro de ordens, mudanças de preço, execuções e mudanças de tick por ID de ativo:

{
  "assets_ids": [
    "65818619657568813474341868652308942079804919287380422192892211131408793125422"
  ],
  "type": "market"
}
Enter fullscreen mode Exit fullscreen mode

Já o Socket de Dados em Tempo Real:

wss://ws-live-data.polymarket.com
Enter fullscreen mode Exit fullscreen mode

atende consumidores de dados e interfaces. Ele transmite comentários, preços de cripto de Binance e Chainlink, preços de ações e eventos de interação social:

{
  "action": "subscribe",
  "subscriptions": [
    {
      "topic": "crypto_prices",
      "type": "update",
      "filters": "btcusdt,ethusd"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Esses públicos possuem requisitos diferentes:

Consumidor Dados necessários Latência esperada Tolerância a falhas
Bot de trading Livro de ordens e execuções Muito baixa Baixa
Interface pública Comentários, preços e atividade Moderada Maior
Dashboard analítico Agregações e histórico Baixa prioridade Alta

Evite criar um único WebSocket que transmite tudo para todos. Em vez disso, separe canais por perfil de uso:

/ws/trading
/ws/market-data
/ws/social
/ws/notifications
Enter fullscreen mode Exit fullscreen mode

Isso permite definir políticas específicas de:

  • retenção de mensagens;
  • reconexão;
  • ordenação;
  • compactação;
  • limites de assinatura;
  • garantias de entrega;
  • escalabilidade.

Quando consumidores têm volumes, tolerâncias à latência e modos de falha muito diferentes, a infraestrutura também deve ser diferente.


O que esses padrões têm em comum

O design da API da Polymarket prioriza fidelidade ao domínio.

A arquitetura de três camadas reflete fronteiras reais entre descoberta, negociação e análise. O acesso público aos dados facilita a criação de ferramentas e melhora a utilidade do mercado. A autenticação em dois níveis diferencia prova de identidade de autorização frequente. Ordens assinadas carregam autorização no próprio payload. Eventos, mercados, negRisk e ticks dinâmicos expõem regras que os clientes precisam entender para operar corretamente. WebSockets separados atendem públicos com necessidades distintas.

Ao aplicar esses padrões, use esta lista como referência:

  1. Separe APIs por responsabilidade de domínio.
  2. Remova autenticação de leituras que podem ser públicas.
  3. Use credenciais fortes para ações sensíveis e credenciais leves para sessões.
  4. Assine payloads quando a operação exigir autorização verificável.
  5. Modele relações de domínio explicitamente nos recursos.
  6. Transforme invariantes críticos em campos tipados e validações.
  7. Publique mudanças de estado em tempo real.
  8. Não force consumidores diferentes a compartilhar o mesmo canal em tempo real.

Uma API fácil de chamar é importante. Porém, em sistemas complexos, uma API que torna regras, restrições e estados visíveis é ainda mais valiosa. Ela reduz suposições implícitas e ajuda os consumidores a construir integrações corretas desde o início.

Top comments (0)