WebSocket API

PolySocket Documentation

Connect to the PolySocket feed, authenticate with an API key, send wallet addresses in a subscribe command, and receive flat Polymarket wallet activity events for your own bot, dashboard, alerting, or API stack.

WebSocketwss://feed.polysocket.dev/v1
AccessAccount API keys
Default payloadFlat wallet activity JSON
Quickstart

Connect, auth, listen.

Open a WebSocket connection and send an auth message as the first client message. Subscribe with wallet addresses for that live connection, then route activity messages with `observed_at_unix_ns` and `tx_hash` into your own stack.

Auth messagejson
{ "type": "auth", "api_key": "YOUR_API_KEY", "scope": "account" }
Subscribe messagejson
{ "type": "subscribe", "wallets": ["0x885278f0e304bc2d53f805af2ab779cb6011c569"] }
Auth successjson
{
  "type": "auth_ok",
  "connection_id": "conn_1777766498121579485_100",
  "account_id": "acct_sample",
  "plan": "basic_weekly_2",
  "wallet_count": 0,
  "wallet_limit": 2,
  "include_tx": false
}
Default subscription acknowledgementjson
{
  "type": "subscribed",
  "scope": "custom",
  "wallet_count": 1
}
01Connect
02Authenticate
03Subscribe
04Receive events
05Route or execute
Authentication

First-message auth.

Clients authenticate immediately after opening the socket. API keys are stored server-side as SHA-256 hashes. Plaintext keys are only shown once and should never be committed or published.

WebSocket URLtext
wss://feed.polysocket.dev/v1
Temporary legacy query-string auth with ?api_key=... remains enabled for compatibility, but new clients should send API keys only in the first WebSocket auth message.
Plan codeLive wallet capacityWebSocket limit
basic_weekly_22100
basic_monthly_2020100
scale_monthly_100100Unlimited
Invalid, missing, inactive, suspended, or over-limit credentials cause authentication to fail and the WebSocket connection to close. Connection limits are enforced from the account plan loaded by the feed server.
Security

Connection-edge abuse controls.

The production feed keeps auth, billing, database, and rate-limit checks off the wallet-event fanout path. Abuse controls run at handshake, private sync, command parsing, and connection liveness boundaries.

ControlLimitEffect
WebSocket upgrade attempts240/minute/IPExcess attempts are rejected with HTTP 429 and temporarily blocked.
Bad WebSocket auth attempts30/minute/IPExcess invalid credentials are rejected with HTTP 429 and temporarily blocked.
Bad account-sync bearer attempts10/minute/IPExcess invalid sync tokens are rejected with HTTP 429 and temporarily blocked.
Temporary abuse block15 minutesApplies only to the specific abuse key or IP.
Client command frame size8 KiBOversized client text or binary commands are rejected and the connection is closed.
Subscribe wallet array length100 walletsLarger arrays receive too_many_wallets. Lower account plan wallet limits still apply after deduplication.
Server heartbeatProtocol Ping every 15 secondsClients should let their WebSocket library answer with protocol Pong.
Heartbeat timeout45 seconds without protocol PongThe server closes stale connections.
Access

Account access stays managed.

Approved accounts manage feed access and API keys through the PolySocket account surface. Internal provisioning, billing, and operational sync details are not part of the public WebSocket API.

Treat API keys like credentials. Do not publish keys in client-side code, public repositories, screenshots, or Discord messages.
Events

Flat wallet activity messages.

When a watched wallet appears in the upstream Polygon wallet feed, PolySocket publishes a flat activity message to matching subscribers.

Activity eventjson
{
  "event_id": "polygon:0x71a325...bf2ce:0x885278...1c569",
  "observed_at_unix_ns": 1777766595870568021,
  "wallet": "0x885278f0e304bc2d53f805af2ab779cb6011c569",
  "tx_hash": "0x71a325019e713fb2234578d55e66e17b25a6f3868f6075a126356e7cc96bf2ce",
  "role": "maker",
  "side": "buy",
  "side_raw": 0,
  "price": 0.17,
  "shares": 9.19,
  "notional_usd": 1.5623,
  "token_id": "70244509752957369974591345556629529797103276141600347856253643886913568219784",
  "outcome_token_id": "70244509752957369974591345556629529797103276141600347856253643886913568219784",
  "exchange_contract": "0xe111180000d2663c0091e4f400237545b87b996b",
  "maker": "0x885278f0e304bc2d53f805af2ab779cb6011c569",
  "signer": "0xa928b536ee1fedc96655820da2593ac50b1abb46",
  "maker_amount_raw": "1562300",
  "taker_amount_raw": "9190000"
}
FieldTypeDescription
event_idstringStable event ID formatted as polygon:{tx_hash}:{wallet}.
observed_at_unix_nsintegerPolySocket gateway observation timestamp in Unix nanoseconds.
walletstringNormalized lowercase watched wallet address.
tx_hashstringNormalized lowercase Polygon transaction hash.
rolestringMatched order role, currently maker or taker.
sidestringTrade side from the matched order. Values are buy or sell when decoded.
side_rawintegerRaw decoded order side when present. BUY is 0 and SELL is 1.
pricenumbernotional_usd / shares.
sharesnumberOutcome shares from the matched order.
notional_usdnumberUSDC notional, normalized from 6 decimals.
token_id / outcome_token_idstringPolymarket CLOB outcome token ID.
exchange_contractstringPolymarket exchange contract address that matched the order.
maker, signerstringOrder maker and signer addresses.
maker_amount_raw, taker_amount_rawstringRaw integer order amounts. For buys, maker amount is USDC and taker amount is shares; for sells, maker amount is shares and taker amount is USDC.
txobjectOnly present when include_tx, full_tx, or include_payload is true.
Activity events intentionally omit constant wrapper fields such as type, chain, source, payload, and match_type. Deduplicate by event_id or by the tx_hash and wallet tuple.
Commands

Client command frames.

All client commands are JSON text frames. The first meaningful client command must be auth, and each client command frame must be 8 KiB or smaller.

Subscribe to walletsjson
{
  "type": "subscribe",
  "wallets": ["0x885278f0e304bc2d53f805af2ab779cb6011c569"]
}
Unsubscribe walletsjson
{
  "type": "unsubscribe",
  "wallets": ["0x885278f0e304bc2d53f805af2ab779cb6011c569"]
}
Pingjson
{ "type": "ping", "ts": 1777766595 }
Pong responsejson
{ "type": "pong", "ts": 1777766595 }
Connection liveness uses WebSocket protocol Ping/Pong frames, not JSON heartbeat messages. The server sends protocol Ping roughly every 15 seconds and closes stale connections after 45 seconds without protocol Pong.
Error codeMeaning
unknown_commandClient sent an unsupported JSON command type.
invalid_walletClient sent a malformed wallet address.
too_many_walletsClient sent more than 100 wallet entries or exceeded the account wallet_limit after deduplication.
message_too_largeClient command exceeded 8 KiB; the connection closes.
auth_requiredFirst meaningful client message was not auth; the connection closes.
unauthorizedAuth message had a missing, invalid, inactive, or disallowed credential; the connection closes.
connection_limitAccount exceeded its concurrent WebSocket limit; the connection closes.
Payload options

Decoded summaries by default.

The default feed sends a readable, low-latency summary. To receive the full upstream transaction object in addition to the decoded summary, opt in per connection.

Full transaction auth messagejson
{
  "type": "auth",
  "api_key": "YOUR_API_KEY",
  "include_tx": true,
  "scope": "account"
}
include_tx=true

Include the full upstream transaction object.

full_tx=true

Alias for include_tx=true.

include_payload=true

Alias for include_tx=true.

Full transaction payloads are larger and can add client-side parsing cost. Keep the default summary feed unless you explicitly need raw transaction details.
Wallet matching

Polymarket-aware detection.

PolySocket customer subscriptions are wallet subscriptions, but matching is not a naive from/to transaction filter. The gateway decodes Polymarket exchange calls, checks taker and maker orders, and can match watched wallets by maker or signer.

  • Supports direct exchange and fee-module contract calls.
  • Unwraps one Gnosis Safe execTransaction layer when present.
  • Supports older matchOrders and newer matchOrdersV2 flows.
  • Matches against order maker and signer addresses.
  • Drops ambiguous multi-token matches instead of emitting misleading signals.
Fee Module V1

0xe3f18acc55091e2c48d883fc8c8413319d4ab7b0

Standard CTF Exchange V2

0xe111180000d2663c0091e4f400237545b87b996b

NegRisk CTF Exchange V2

0xe2222d279d744050d28e00520010520000310f59

Examples

Consume events in common runtimes.

Node.jsjavascript
const apiKey = process.env.POLYSOCKET_API_KEY;
const wallets = ["0x885278f0e304bc2d53f805af2ab779cb6011c569"];
const ws = new WebSocket("wss://feed.polysocket.dev/v1");

ws.addEventListener("open", () => {
  ws.send(JSON.stringify({
    type: "auth",
    api_key: apiKey,
    scope: "account"
  }));
});

ws.addEventListener("message", (event) => {
  const msg = JSON.parse(event.data);

  if (msg.type === "auth_ok") {
    console.log("connected", msg.connection_id);
    ws.send(JSON.stringify({
      type: "subscribe",
      wallets
    }));
  }

  if (msg.observed_at_unix_ns && msg.tx_hash) {
    routeToYourSystem(msg);
  }
});
Pythonpython
import asyncio
import json
import os
import websockets

async def main():
    api_key = os.environ["POLYSOCKET_API_KEY"]
    wallets = ["0x885278f0e304bc2d53f805af2ab779cb6011c569"]

    async with websockets.connect("wss://feed.polysocket.dev/v1", ping_interval=None, max_queue=None) as ws:
        await ws.send(json.dumps({
            "type": "auth",
            "api_key": api_key,
            "scope": "account"
        }))

        async for raw in ws:
            msg = json.loads(raw)
            if msg.get("type") == "auth_ok":
                await ws.send(json.dumps({
                    "type": "subscribe",
                    "wallets": wallets
                }))

            if "observed_at_unix_ns" in msg and "tx_hash" in msg:
                print(msg["wallet"], msg["tx_hash"], msg["observed_at_unix_ns"])

asyncio.run(main())
Rustrust
use futures_util::{SinkExt, StreamExt};
use serde_json::{json, Value};
use tokio_tungstenite::connect_async;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let api_key = std::env::var("POLYSOCKET_API_KEY")?;
    let wallets = ["0x885278f0e304bc2d53f805af2ab779cb6011c569"];
    let (mut ws, _) = connect_async("wss://feed.polysocket.dev/v1").await?;

    ws.send(json!({
        "type": "auth",
        "api_key": api_key,
        "scope": "account"
    }).to_string().into()).await?;

    while let Some(msg) = ws.next().await {
        let parsed: Value = serde_json::from_str(&msg?.into_text()?)?;
        if parsed["type"] == "auth_ok" {
            ws.send(json!({
                "type": "subscribe",
                "wallets": wallets
            }).to_string().into()).await?;
        }

        if parsed["observed_at_unix_ns"].is_number() && parsed["tx_hash"].is_string() {
            println!("wallet={} tx={}", parsed["wallet"], parsed["tx_hash"]);
        }
    }

    Ok(())
}
Availability

Runtime checks stay minimal.

Health

GET https://feed.polysocket.dev/healthz returns ok when the feed edge is reachable.

Specs

AsyncAPI is published at /asyncapi.yaml and HTTP endpoint OpenAPI is published at /openapi.yaml.

Metrics

Public /metrics returns 404 by design. Runtime metrics are local to DEDI for operators.

Product boundary

A feed, not a trading bot.

PolySocket is

A WebSocket feed, structured event source, latency-focused input layer, and API surface for wallet activity monitoring.

PolySocket is not

A copy trading bot, execution venue, wallet manager, custody product, strategy engine, or position-sizing engine.

Execution context

Your bot, network path, routing, queue position, order type, and execution latency determine actual fills.