Esta página foi traduzida automaticamente. O original em inglês é a versão canônica. Ler em inglês →
Pular para o conteúdo principal

API WebSocket

Streaming de dados em tempo real para negociação de opções na Hypercall.

Referência interativa

Confira a Referência interativa da API WebSocket para uma navegação melhor, com exemplos ao vivo e detalhes dos schemas.

Especificação legível por máquina

Baixe a especificação AsyncAPI para uso programático.

Evolução aditiva do schema

Os objetos de mensagem do WebSocket podem ganhar novos campos sem aviso prévio. Os clientes devem ignorar campos que não reconhecem. A Hypercall não remove campos de um schema de mensagem existente.

Conexão​

Conecte-se a wss://HOST/ws:

Endpoints:

  • Produção: wss://api.hypercall.xyz/ws
  • Local: ws://localhost:3000/ws
Status da testnet

A testnet está temporariamente desativada até que a Hypercall adquira mais HYPE de testnet.

Compressão​

/ws suporta permessage-deflate conforme a RFC 7692. Ative-o no seu cliente para reduzir a banda de dados de mercado: em tráfego de produção capturado, frames comprimidos de forma independente ficam cerca de 45% menores, e lotes de preços de índice cerca de 70% menores.

  • Seu cliente oferece a extensão na requisição de upgrade, por exemplo Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits.
  • Quando o servidor aceita, a resposta 101 traz Sec-WebSocket-Extensions: permessage-deflate; server_no_context_takeover. Cada mensagem do servidor é então comprimida isoladamente, sem uma janela deslizante compartilhada, e mensagens com menos de algumas centenas de bytes continuam sendo enviadas sem compressão. Sua biblioteca descomprime de forma transparente.
  • Se a resposta não tiver o header Sec-WebSocket-Extensions, todos os frames vêm sem compressão. A compressão é ativada por ambiente, então os clientes precisam lidar com os dois casos; as mensagens JSON são idênticas em ambos. A produção ainda não aceita a extensão, então os frames de produção atualmente vêm sem compressão.
  • Seu cliente pode comprimir o que envia. O servidor descomprime cada mensagem do cliente até 256 KiB e fecha a conexão se uma mensagem ultrapassar esse limite.

Navegadores negociam a extensão automaticamente. A maioria das bibliotecas não precisa de nenhuma alteração:

Python (websockets ativa a compressão por padrão):

import websockets

async with websockets.connect("wss://api.hypercall.xyz/ws", compression="deflate") as ws:
...

Node.js (ws):

import WebSocket from "ws";

const ws = new WebSocket("wss://api.hypercall.xyz/ws", { perMessageDeflate: true });

Rust: o WsClient do hypercall-client negocia permessage-deflate por padrão (veja Exemplo: cliente Rust). tungstenite e tokio-tungstenite puros ainda não o implementam, então se conectam sem compressão. Para usar compressão com o seu próprio socket, use um cliente que a implemente, como o yawc:

let url = "wss://api.hypercall.xyz/ws".parse()?;
let mut ws = yawc::WebSocket::connect(url)
.with_options(yawc::Options::default().with_low_latency_compression())
.await?;

Identificação da carteira​

Para receber dados em canais autenticados (ordens, execuções, portfólio), identifique sua carteira após conectar enviando uma mensagem Authenticate:

{"type": "Authenticate", "wallet": "0x1234..."}

O servidor responde com uma confirmação:

{"type": "Authenticated", "wallet": "0x1234..."}

Após receber Authenticated, você pode se inscrever em canais autenticados. Se o endereço da carteira for inválido, o servidor responde com uma mensagem Error e a conexão permanece aberta.

Obsoleto: autenticação por query parameter

O query parameter ?wallet= ainda é suportado por compatibilidade, mas está obsoleto e será removido em uma versão futura. Prefira a abordagem baseada em mensagem descrita acima.

Liveness da conexão​

O servidor aplica um heartbeat no WebSocket:

  • Envia um frame de controle Ping a cada 20 segundos
  • Espera um Pong correspondente em até 60 segundos
  • Fecha a conexão com o código 1008 e o motivo pong timeout se o cliente parar de responder

As implementações de WebSocket dos navegadores tratam ping/pong automaticamente. Muitas bibliotecas websocket em Rust, incluindo tungstenite e tokio-tungstenite, também tratam o ping/pong dos frames de controle para você. Consulte a documentação da biblioteca do seu cliente antes de adicionar tratamento manual de Pong. Implementações customizadas ou com socket bruto devem responder aos frames Ping com Pong.

Recuperação de consumidor lento​

O servidor fecha uma conexão /ws que não consegue escoar os dados de saída dentro do teto de segurança configurado de mensagens, bytes codificados, idade da fila ou escrita no socket. Quando a conexão ainda consegue aceitar um frame de fechamento, o servidor usa o código 1008 e um motivo em JSON compacto:

{"error":"slow_consumer","class":"ordered_public","cause":"message_age","recovery":"snapshot_resubscribe"}

Os campos do motivo são:

CampoSignificado
classClasse de entrega cujo frame ultrapassou o limite de segurança.
causemessage_limit, byte_limit, message_age ou write_timeout.
recoveryPróxima ação obrigatória, como resubscribe, snapshot_resubscribe, portfolio_refetch ou rest_reconcile.

Após qualquer desconexão, reconecte, identifique a carteira novamente quando necessário, refaça as inscrições e reconcilie o estado atual antes de processar novos eventos. Canais públicos ordenados exigem um snapshot novo. Canais de eventos privados exigem reconciliação pela superfície REST autoritativa, porque o replay por cursor ainda não está disponível. Uma conexão totalmente travada pode ser encerrada antes de conseguir ler o motivo do fechamento, então os clientes devem usar esse fluxo de recuperação também em fechamentos não limpos.

Use conexões separadas para dados de mercado públicos de alta frequência e para comandos autenticados ou streams privados. As classes de entrega selecionam métricas e o comportamento de recuperação, mas os frames de uma mesma conexão ainda compartilham um único caminho ordenado de escrita no socket. Uma escrita pública travada pode, portanto, atrasar frames privados posteriores nessa mesma conexão até que o prazo de escrita a feche.

Inscrição em canais​

Envie uma mensagem JSON para se inscrever:

{"type": "Subscribe", "channel": "orderbook"}

Para cancelar a inscrição:

{"type": "Unsubscribe", "channel": "orderbook"}

Você receberá uma confirmação:

{"type": "Subscribed", "channel": "orderbook"}

Filtro por símbolo​

Os canais order_updates e fills suportam um filtro opcional symbols. Quando informado, o servidor só envia mensagens cujo ativo subjacente corresponda a um dos símbolos especificados.

{"type": "Subscribe", "channel": "order_updates", "symbols": ["BTC"]}

São aceitos tanto ativos subjacentes isolados ("BTC") quanto nomes completos de instrumentos ("BTC-20260131-100000-C"). Para adicionar mais símbolos, envie outro Subscribe. Para remover símbolos específicos:

{"type": "Unsubscribe", "channel": "order_updates", "symbols": ["BTC"]}

Quando nenhum symbols é especificado, todas as atualizações da sua carteira são encaminhadas.

Os canais públicos orderbook, trades, indicative_market_data e indicative_market_data_v2 também aceitam symbols, comparados com os símbolos exatos dos instrumentos (sem diferenciar maiúsculas e minúsculas), e não com os ativos subjacentes:

{"type": "Subscribe", "channel": "orderbook", "symbols": ["BTC-20260131-100000-C"]}

Sem symbols, esses canais entregam todos os instrumentos.

Filtro da grade de opções​

O canal options_chain suporta filtro por símbolos de instrumentos, data de vencimento e tipo de opção:

{
"type": "Subscribe",
"channel": "options_chain",
"symbols": ["BTC-20260131-100000-C"],
"expiry": "2026-01-31",
"option_type": "call"
}
FiltroValoresPadrão
symbolsArray de símbolos completos de instrumentos (ex.: ["BTC-20260131-100000-C"])Todos os instrumentos
expiryString de data "YYYY-MM-DD", comparada com a data de calendário UTC do vencimento de cada instrumentoTodos os vencimentos
option_type"call", "put", "both", ou omita para ambosAmbos

Entrega em lotes​

indicative_market_data_v2 traz as mesmas linhas que indicative_market_data, com várias linhas por frame:

{"type": "Subscribe", "channel": "indicative_market_data_v2", "symbols": ["BTC-20260131-100000-C"]}

O servidor confirma com um marcador de lote:

{"type": "Subscribed", "channel": "indicative_market_data_v2", "batch": true}

Em seguida, ele retém cada linha por no máximo uma janela de lote, 25 ms por padrão, e envia as linhas publicadas nessa janela como um único frame IndicativeMarketDataBatch. Um lote também é enviado antes do prazo quando atinge 256 linhas.

  • Detecção de suporte: somente uma confirmação com "batch": true indica que o servidor faz lotes. Servidores lançados antes deste canal confirmam qualquer nome de canal sem o marcador e depois não enviam nada, e os servidores atuais respondem a um canal desconhecido com um erro unknown_channel. Em qualquer desses casos, cancele a inscrição em indicative_market_data_v2 e inscreva-se em indicative_market_data na mesma conexão.
  • Latência: uma linha chega até uma janela mais tarde do que em indicative_market_data. Em tráfego de produção com a janela padrão, as linhas esperaram 12 ms em média e nunca mais de 25 ms. Use o canal v1 se você reage a atualizações individuais de cotação em milissegundos.
  • Banda: os lotes sozinhos economizam cerca de 7% dos bytes. A grande economia vem com o permessage-deflate: lotes comprimidos são cerca de 9,8 vezes menores que frames de uma linha sem compressão em uma inscrição sem filtro, e cerca de 8,3 vezes menores para uma única grade de opções, contra cerca de 1,8 vez para linhas comprimidas uma a uma.
  • Ordem: as linhas em updates estão em ordem de publicação, e os lotes chegam em ordem. As linhas não são consolidadas, então um mesmo instrumento pode aparecer mais de uma vez em um lote. Aplique as linhas em ordem e você chega ao mesmo estado que no canal v1.
  • Snapshot: o snapshot do momento da inscrição também chega como frames de lote.
  • Filtros: symbols funciona como em indicative_market_data. Restringir o filtro ou cancelar a inscrição primeiro envia as linhas já pendentes sob o filtro antigo e depois a confirmação Unsubscribed, então nenhuma linha é perdida ou duplicada.
  • Canais independentes: uma conexão pode se inscrever nos dois canais com filtros diferentes. indicative_market_data não muda.

Canais disponíveis​

CanalRequer autenticaçãoDescrição
orderbookNãoAtualizações L2 do livro de ofertas para todos os símbolos
tradesNãoFeed público de negócios
market_updatesNãoMudanças na listagem de mercados (criados/removidos/vencidos)
options_chainNãoAtualizações incrementais da grade de opções (filtrável por symbols, expiry, option_type)
index_pricesNãoPreços spot/de índice em tempo real para todos os ativos subjacentes
indicative_market_dataNãoStream de provedores de cotação em allowlist. Ainda não disponível de forma geral
indicative_market_data_v2NãoO mesmo stream em frames de lote. Veja Entrega em lotes
order_updatesSimMudanças de status das suas ordens (filtrável por símbolo)
fillsSimExecuções dos seus negócios (filtrável por símbolo)
portfolioSimAtualizações das suas posições e saldos
liquidationSimMudanças no seu estado de liquidação
rfqSimCotações de RFQ, atualizações de status e notificações de execução
experimental_order_updates, experimental_combo_fillsSimCanais experimentais de combos. Veja API experimental de combos
experimental_combo_tradesNãoNegócios públicos experimentais de combos

Dados de competições e leaderboards não são servidos por api.hypercall.xyz, nem via WebSocket nem via REST. Inscrever-se nos canais descontinuados competition ou competition_engagement retorna um Error. O app de trading lê as competições via HTTP a partir do serviço de analytics em https://api-ui.hypercall.xyz, por exemplo GET /v2/competitions, GET /v2/competitions/{id}, GET /v2/competitions/leaderboard e GET /v2/competitions/all-time/leaderboard.

Tipos de mensagem​

Enviar ordem (autenticado)​

Envie uma ordem pelo caminho de comandos do WebSocket.

{
"type": "PlaceOrder",
"wallet": "0x1234...",
"symbol": "BTC-20260131-100000-C",
"side": "Buy",
"size": "1",
"price": "100",
"tif": "gtc",
"route": "book_only",
"client_id": "my-order-1",
"nonce": 1780000000000,
"signature": "0x..."
}

O nonce acima é ilustrativo. Gere um novo para cada ordem a partir do horário Unix atual em milissegundos, por exemplo Date.now() em JavaScript. Um valor fixo copiado fica fora da janela aceita e é rejeitado.

CampoTipoDescrição
walletstringEndereço da carteira dona da ordem
symbolstringSímbolo da opção
sidestring"Buy" ou "Sell"
sizestringTamanho do contrato, exatamente igual ao valor assinado
pricestringPreço limite, exatamente igual ao valor assinado
tifstringTime-in-force opcional, padrão "gtc"
routestringUse "book_only". Uma rota omitida ainda é aceita, mas está obsoleta, e a data de descontinuação já passou.
client_idstringID de ordem do cliente, opcional
reduce_onlybooleanOpcional, padrão false. Uma ordem reduce-only assina PlaceOrderReduceOnly e exige uma route explícita
mmp_enabledbooleanOpcional, padrão false
builder_code_addressstringCarteira de builder code, opcional
nonceintegerNonce de assinatura obrigatório: o horário Unix atual em milissegundos. Deve estar entre dois dias antes e um dia depois do horário atual. Cada nonce é aceito uma única vez por signatário, e ordens REST e WebSocket compartilham o mesmo espaço de nonces. Um frame reenviado é rejeitado.
signaturestringAssinatura EIP-712 PlaceOrder

A conexão precisa ter enviado Authenticate antes; caso contrário, o servidor responde {"type": "Error", "message": "Not authenticated"}. O signatário deve ser a wallet ou um agente aprovado para ela.

O PlaceOrder via WebSocket atualmente envia a ordem diretamente ao livro de ofertas. route="best_execution" e route="rfq_only" são rejeitados no WebSocket porque esse caminho ainda não executa o roteamento RPI/RFQ. Use POST /order para best_execution.

Uma ordem admitida é respondida na mesma conexão com um OrderResult:

{
"type": "OrderResult",
"order_id": 12345,
"status": "ACKED",
"symbol": "BTC-20260131-100000-C",
"side": "Buy",
"price": "100",
"size": "1"
}

reason é incluído quando a ordem não é aceita. Falhas de validação, assinatura e rate limit são enviadas como um Error cujo message começa com Order placement failed:. Mudanças de status posteriores chegam em order_updates.

Atualização do livro de ofertas​

Snapshot/atualização L2 do livro de ofertas para um símbolo.

{
"type": "OrderbookUpdate",
"symbol": "BTC-20260131-100000-C",
"option_token_address": "0x...",
"bids": [["95000.5", "10.5"], ["94999.0", "25.0"]],
"asks": [["95001.0", "8.0"], ["95002.5", "15.0"]],
"timestamp": 1737331200000
}
CampoTipoDescrição
symbolstringSímbolo da opção
option_token_addressstring?Endereço on-chain do token da opção, quando conhecido
bidsarrayNíveis de bid como tuplas [price, size], com o tamanho em contratos legíveis
asksarrayNíveis de ask como tuplas [price, size], com o tamanho em contratos legíveis
timestampintegerTimestamp Unix (milissegundos)

Negócio​

Evento público de negócio.

{
"type": "Trade",
"symbol": "BTC-20260131-100000-C",
"price": "0.0523",
"size": "5.0",
"side": "Buy",
"timestamp": 1737331200000
}
CampoTipoDescrição
symbolstringSímbolo da opção
pricestringPreço do negócio em USD
sizestringTamanho do negócio em contratos
sidestringLado agressor (Buy ou Sell)
timestampintegerTimestamp Unix (milissegundos)

Execução (autenticado)​

Notificação de execução do seu negócio.

{
"type": "Fill",
"order_id": 12345,
"fill_id": 67890,
"symbol": "BTC-20260131-100000-C",
"side": "Buy",
"price": "0.0523",
"size": "5.0",
"timestamp": 1737331200000,
"wallet_address": "0x1234...abcd",
"fee": "0",
"trade_id": 99999,
"is_taker": true,
"builder_code_address": null,
"builder_code_fee": null,
"instrument_type": "option"
}
CampoTipoDescrição
order_idintegerID da sua ordem
fill_idintegerID da execução
symbolstringSímbolo da opção
sidestringSeu lado no negócio (Buy ou Sell)
pricestringPreço de execução em USD
sizestringTamanho executado em contratos
timestampintegerTimestamp Unix (milissegundos)
wallet_addressstringEndereço da sua carteira
feestringTaxa de negociação cobrada. Retorna 0 enquanto as taxas da venue no lançamento estiverem desativadas
trade_idintegerID único do negócio
is_takerbooleanSe você foi o taker
builder_code_addressstring?Carteira de builder code (se houver)
builder_code_feestring?Taxa de builder code. Retorna null enquanto as taxas da venue no lançamento estiverem desativadas
instrument_typestring"option"

Atualização de portfólio (autenticado)​

Enviada no canal portfolio para posições, saldos, margem e gregas. Na inscrição, o servidor envia um snapshot Initial e depois atualizações incrementais.

O type de cada frame é o tipo de atualização:

Tipo de atualizaçãoCampos além de timestamp
Initialpositions
PositionUpdateposition
BalanceUpdatetotal_margin_used
MarginUpdatespan_margin, margin_summary, margin_mode, total_margin_used, available_balance
GreeksUpdateper_leg, aggregate

O timestamp nos frames de portfolio é em segundos Unix, diferente dos timestamps em milissegundos dos outros canais.

Exemplo de atualização de gregas:

{
"type": "GreeksUpdate",
"timestamp": 1737331200,
"per_leg": [
{
"symbol": "BTC-20260131-100000-C",
"quantity": "2.0",
"delta": 0.91,
"gamma": 0.003,
"theta": -0.12,
"vega": 0.44,
"iv": 0.63
}
],
"aggregate": {
"delta": 0.91,
"gamma": 0.003,
"theta": -0.12,
"vega": 0.44,
"iv": 0.63
}
}

Para portfólios vazios, as atualizações de gregas usam:

  • per_leg: []
  • aggregate: null

Atualização de ordem (autenticado)​

Notificação de mudança de status da ordem. Atualizações PARTIALLY_FILLED são incluídas. filled_size é a quantidade acumulada executada em todas as execuções da ordem, não a quantidade da execução mais recente.

{
"type": "OrderUpdate",
"order_id": 12345,
"client_id": "my-order-1",
"request": {
"price": "0.0523",
"size": "10.0",
"symbol": "BTC-20260131-100000-C",
"side": "Buy",
"tif": "gtc"
},
"status": "PARTIALLY_FILLED",
"filled_size": "0.75",
"timestamp": 1767225600000,
"reason": null,
"wallet_address": "0x0000000000000000000000000000000000000001",
"instrument_type": "option"
}

status é um de ACKED, OPEN, PARTIALLY_FILLED, FILLED, CANCELED ou REJECTED. client_id é omitido quando a ordem não tem um. instrument_type é "option" ou "perp".

Atualização de mercado​

Mudanças na listagem de mercados.

Mercado criado:

{
"type": "MarketUpdate",
"action": "Created",
"symbol": "BTC-20260131-100000-C",
"strike": "100000",
"is_call": true,
"underlying": "BTC",
"expiry": 1738281600,
"timestamp": 1737331200000
}

Mercado vencido:

{
"type": "MarketUpdate",
"action": "Expired",
"symbol": "BTC-20260131-100000-C",
"strike": "100000",
"is_call": true,
"underlying": "BTC",
"expiry": 1738281600,
"timestamp": 1738281600000
}

action é Created, Expired, Deleted (traz apenas symbol e timestamp) ou ComboCreated (veja API experimental de combos).

Atualização da grade de opções​

Enviada em options_chain quando uma listagem ou o seu topo de livro muda. action é Upsert ou Remove.

{
"type": "OptionsChainUpdate",
"action": "Upsert",
"currency": "BTC",
"expiry": 1769846400,
"row": {
"strike": 100000.0,
"call": {
"symbol": "BTC-20260131-100000-C",
"bid_price_usd": 1520.0,
"ask_price_usd": 1580.0
}
},
"timestamp": 1737331200000
}

Uma linha Upsert traz uma perna (call ou put) com os campos de perna do snapshot da grade de opções: symbol, option_token_address, preço de bid e ask, IV, tamanho em contratos e nocional em USD, greeks_abs e greeks_cash (o exemplo acima está abreviado). Valores indisponíveis são null; a perna que não faz parte da atualização é omitida. Um Remove traz currency, expiry, strike, option_type, symbol e timestamp quando um instrumento é removido, vence ou entra em liquidação pendente. expiry é em segundos Unix.

Posição vencida (autenticado)​

Enviada no canal portfolio quando a sua posição é liquidada no vencimento.

{
"type": "PositionExpired",
"wallet_address": "0x1234...abcd",
"symbol": "BTC-20260131-100000-C",
"position_size": "10.0",
"settlement_price": "105000",
"settlement_value": "500.0",
"settlement_entry_price": "100.0",
"cost_basis": "1000.0",
"net_pnl": "-500.0",
"timestamp": 1738281600000
}

settlement_entry_price, cost_basis e net_pnl são null quando não estão disponíveis.

Mudança de estado de liquidação (autenticado)​

Enviada no canal liquidation quando o estado de liquidação da sua conta muda.

{
"type": "LiquidationStateChange",
"wallet_address": "0x1234...abcd",
"previous_state": "healthy",
"new_state": "pre_liquidation",
"liquidation_mode": "partial",
"margin_mode": "standard",
"equity": "10000.0",
"mm_required": "10500.0",
"maintenance_margin": "-500.0",
"shortfall": "500.0",
"partial_liquidation": { "...": "..." },
"full_liquidation": null,
"timestamp": 1737331200000
}
CampoDescrição
previous_state, new_statehealthy, pre_liquidation, in_liquidation ou liquidated
liquidation_modepartial, full ou null quando nenhum fluxo de liquidação está ativo
margin_modestandard ou portfolio
equityPatrimônio da conta
mm_requiredRequisito de margem de manutenção
maintenance_marginPatrimônio menos o requisito de margem de manutenção
shortfallQuanto a conta está abaixo da margem de manutenção
partial_liquidationAndamento da liquidação parcial (horário de entrada, patrimônio alvo, prazo de escalonamento, ordens de liquidação ativas, bônus) ou null
full_liquidationDetalhes do leilão de liquidação total (ID do leilão, horário de início, margem necessária e, ao final, o vencedor, o bônus e a transação de resolução) ou null

Veja Liquidação para o significado de cada estado.

Atualização de preço de índice​

Preços spot/de índice em lote para todos os ativos subjacentes.

{
"type": "IndexPriceUpdate",
"prices": [
{"underlying": "BTC", "price": "97250.50", "timestamp": 1737331200000},
{"underlying": "ETH", "price": "3200.00", "timestamp": 1737331199980},
{"underlying": "NVDA", "price": "182.40", "timestamp": 1737331199950}
],
"timestamp": 1737331199950
}
CampoTipoDescrição
pricesarrayArray de entradas {underlying, price, timestamp} para cada ativo subjacente acompanhado
prices[].underlyingstringSímbolo do ativo subjacente (ex.: "BTC", "ETH")
prices[].pricestringPreço spot/de índice atual em USD
prices[].timestampintegerHorário de observação na fonte para este ativo subjacente, em milissegundos Unix
timestampintegerHorário de observação na fonte mais antigo incluído em prices, em milissegundos Unix

Dados de mercado indicativos​

Stream de provedores de cotação em allowlist, com o melhor bid/ask agregado dos provedores de cotação registrados. Este canal ainda não está disponível de forma geral. Use os dados de mercado via REST e os canais autenticados de ordens/execuções/portfólio, a menos que a Hypercall tenha habilitado o streaming de provedores de cotação para a sua integração.

{
"type": "IndicativeMarketData",
"instrument": "BTC-20260131-100000-C",
"best_bid": "0.0520",
"best_ask": "0.0530",
"indicative_bid_size": "50.0",
"indicative_ask_size": "25.0",
"num_providers": 3,
"published_at": 1737331200004,
"timestamp": 1737331200000
}
CampoTipoDescrição
instrumentstringSímbolo da opção
best_bidstringMelhor preço de bid agregado, opcional
best_askstringMelhor preço de ask agregado, opcional
bid_ivnumberVolatilidade implícita do melhor bid, opcional
ask_ivnumberVolatilidade implícita do melhor ask, opcional
indicative_bid_sizestringTamanho total de bid entre os provedores, opcional
indicative_ask_sizestringTamanho total de ask entre os provedores, opcional
num_providersintegerNúmero de provedores de cotação ativos
rfq_provider_quotesarrayCotações por provedor, opcional: wallet, bid_price, ask_price, max_bid_size, max_ask_size, updated_at
published_atintegerHorário do relógio da API em que esta linha foi publicada, em milissegundos Unix. Meça a idade de rfq_provider_quotes em relação a ele, não ao seu relógio local
timestampintegerHorário da cotação mais recente de um provedor, em milissegundos Unix

Lote de dados de mercado indicativos​

Enviado no canal indicative_market_data_v2 (veja Entrega em lotes). Cada elemento de updates tem os mesmos campos de uma mensagem IndicativeMarketData, sem type.

{
"type": "IndicativeMarketDataBatch",
"flushed_at": 1737331200025,
"updates": [
{
"instrument": "BTC-20260131-100000-C",
"best_bid": "0.0520",
"best_ask": "0.0530",
"num_providers": 3,
"published_at": 1737331200004,
"timestamp": 1737331200000
},
{
"instrument": "BTC-20260131-105000-C",
"best_bid": "0.0310",
"best_ask": "0.0322",
"num_providers": 2,
"published_at": 1737331200004,
"timestamp": 1737331200001
}
]
}
CampoTipoDescrição
flushed_atintegerHorário do relógio da API em que o lote foi enviado, em milissegundos Unix. flushed_at - published_at é o atraso de lote de uma linha
updatesarrayLinhas publicadas durante a janela, da mais antiga para a mais recente

Cotações de RFQ (autenticado)​

Cotações recebidas em resposta ao seu envio de RFQ.

{
"type": "RfqQuotes",
"rfq_id": "550e8400-e29b-41d4-a716-446655440000",
"quotes": [
{
"quote_id": "660e8400-e29b-41d4-a716-446655440001",
"net_premium": "52.30",
"expires_at": 1737331225000
}
],
"status": "quoted",
"taker_wallet": "0x1234...abcd"
}

Atualização de status de RFQ (autenticado)​

Mudança de status de um RFQ que você enviou.

{
"type": "RfqStatusUpdate",
"rfq_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "executed",
"taker_wallet": "0x1234...abcd"
}

Sincronização de relógio​

Envie ClockSync com qualquer string de nonce para obter uma amostra do relógio da API na mesma conexão, por exemplo para limitar o atraso de transporte:

{"type": "ClockSync", "nonce": "abc"}
{"type": "ClockSynced", "nonce": "abc", "server_at": 1737331200000}

server_at é em milissegundos Unix. Não é necessária autenticação.

Erro​

Mensagem de erro do servidor. Faça a correspondência por code quando presente, não por message.

{
"type": "Error",
"message": "Unknown channel 'foobar'",
"code": "unknown_channel",
"channel": "foobar"
}
CampoTipoDescrição
messagestringDescrição legível
codestringMotivo estável, opcional. unknown_channel: um Subscribe indicou um canal que não existe
channelstringOpcional. O canal indicado por um Subscribe rejeitado

Um Subscribe para um canal que não está listado em Canais disponíveis é respondido com o erro unknown_channel, e nenhuma inscrição é criada. Servidores anteriores confirmavam qualquer nome e depois não enviavam nada.

Outros erros trazem apenas message. Exemplos: Authentication required for this channel quando você se inscreve em um canal autenticado antes de Authenticate, Not authenticated para PlaceOrder antes de Authenticate, e Invalid wallet address: ....

Autenticação​

Canais autenticados exigem uma mensagem de identificação da carteira após a conexão:

{"type": "Authenticate", "wallet": "0x1234567890abcdef..."}

As mensagens em canais autenticados são filtradas para mostrar apenas os dados da sua carteira. Nenhuma assinatura é exigida para conexões WebSocket.

Exemplo: cliente Python​

import asyncio
import websockets
import json

async def main():
uri = "wss://api.hypercall.xyz/ws"

async with websockets.connect(uri) as ws:
# Identify the wallet before subscribing to authenticated channels.
await ws.send(json.dumps({
"type": "Authenticate",
"wallet": "0xYourWallet"
}))

# Subscribe to orderbook
await ws.send(json.dumps({
"type": "Subscribe",
"channel": "orderbook"
}))

# Subscribe to fills for BTC only
await ws.send(json.dumps({
"type": "Subscribe",
"channel": "fills",
"symbols": ["BTC"]
}))

# Listen for messages
async for message in ws:
data = json.loads(message)
print(f"Received: {data['type']}")

asyncio.run(main())

Exemplo: cliente TypeScript​

const ws = new WebSocket("wss://api.hypercall.xyz/ws");

ws.onopen = () => {
ws.send(JSON.stringify({ type: "Authenticate", wallet: "0xYourWallet" }));

// Subscribe to channels
ws.send(JSON.stringify({ type: "Subscribe", channel: "orderbook" }));

// Subscribe to order updates filtered to BTC
ws.send(JSON.stringify({
type: "Subscribe",
channel: "order_updates",
symbols: ["BTC"],
}));
};

ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
console.log(`Received: ${msg.type}`);

if (msg.type === "OrderbookUpdate") {
console.log(`${msg.symbol}: ${msg.bids.length} bids, ${msg.asks.length} asks`);
}
};

Exemplo: cliente Rust​

O WsClient do crate hypercall-client identifica a carteira, restaura as inscrições após uma reconexão e responde aos pings do servidor para você. Ele oferece compressão permessage-deflate por padrão e volta para frames sem compressão quando o servidor não a aceita, com as mesmas mensagens JSON em ambos os casos. Chame with_permessage_deflate(false) para deixar de oferecê-la.

use hypercall_client::WsClient;

#[tokio::main]
async fn main() -> hypercall_client::Result<()> {
let ws = WsClient::new();
ws.connect("https://api.hypercall.xyz", None).await?;
ws.subscribe(vec!["orderbook", "index_prices"]).await?;

if let Some(msg) = ws.wait_for_message(|_| true, 5_000).await {
println!("Received: {msg:?}");
}
Ok(())
}