tier=logical
and tier=endgame opportunity at the exact moment the arb engine
detects it — typically within 100ms of the underlying price/book
event that triggered it.
Plus tier and above only. Free and Pro stay on REST polling
(
GET /v1/arb/live). This is the headline Plus differentiator —
no quota burn, no missed signals.Endpoint
Query parameters
WebSockets can’t carry custom
Authorization headers reliably across
proxies, so auth is via query param. Use HTTPS-equivalent transport
security (this URL is TLS — never ws://).
Message types
Every message is a single JSON object with atype discriminator.
ready (sent once, on connect)
opportunity (zero or many — pushed as they fire)
Same shape as items in the opportunities array from
GET /v1/arb/live, with a type: "opportunity" field added. The
tier field is the actionable filter — only "logical" or
"endgame" are pushed; "stable" / "stale" rows are kept off the
push channel by design (they’re not tradable signals).
ping (every 25s if no opportunities)
Sent so a long-idle connection doesn’t get killed by intermediaries.
Clients can ignore the body — receiving any message is enough proof
of liveness. No client pong required.
Minimal Python client
Reconnect handling
Networks die. Add a backoff loop so a transient drop doesn’t lose you signals for the rest of the day:What you don’t get
- No historical replay. Connect = subscribe from now. If you
disconnect for 5 minutes and reconnect, any signals fired during
the gap are lost. Use
GET /v1/arb/audit?window=24hto backfill if needed for analysis (note: settled-only, not real-time). - No order submission. PolyQuantLab is a research / signal API; execution stays on Polymarket. Pipe the message into your py-clob-client loop — see Auto-trade logical arbs.
- No
stable/stalerows. Those have ~0 expected edge after fees; surfacing them on the push channel would just waste your socket bandwidth and tempt bad trades. They remain available via RESTGET /v1/arb/live.